Skip to content
This repository has been archived by the owner on May 5, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1 from tistocks/tistocks_HDInsight_2
Browse files Browse the repository at this point in the history
List and Create HDInsight clusters
Tests and moved things around to comply with OneSDK standards
  • Loading branch information
tistocks committed May 22, 2013
2 parents 541de58 + 911c3bd commit b775dcd
Show file tree
Hide file tree
Showing 15 changed files with 2,567 additions and 49 deletions.
27 changes: 26 additions & 1 deletion lib/azure.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,31 @@ exports.createSqlManagementService = function (subscriptionId, authentication, h
return new SqlManagementService(subscriptionId, authentication, hostOptions);
};

var HDInsightService = require('./services/serviceManagement/hdinsightservice');
exports.HDInsightService = HDInsightService;

/**
* Creates a new HDInsightService object.
*
* @param {string} subscriptionId The subscription ID for the account.
* @param {string} authentication The authentication object for the client.
* {
* keyfile: 'path to .pem',
* certfile: 'path to .pem',
* keyvalue: privatekey value,
* certvalue: public cert value
* }
* @param {string} hostOptions The host options to override defaults.
* {
* host: 'management.core.windows.net',
* apiversion: '2012-03-01',
* serializetype: 'XML'
* }
*/
exports.createHDInsightService = function (subscriptionId, authentication, hostOptions) {
return new HDInsightService(subscriptionId, authentication, hostOptions);
};

/**
* ServiceBusManagementService client exports.
*/
Expand Down Expand Up @@ -269,4 +294,4 @@ exports.date = require('./util/date');
*/
exports.isEmulated = function (host) {
return exports.ServiceClient.isEmulated(host);
};
};
59 changes: 59 additions & 0 deletions lib/services/serviceManagement/hdinsightnamespaceutils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Copyright (c) Microsoft. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// External dependencies
var crypto = require('crypto');

function HDInsightNamespace() {

}

function _LongUnsignedRor(value, count) {
for(var i = 0; i<count; i++) {
value = value / 2;
}
return Math.floor(value);
}

var base32StandardAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
function _Base32NoPaddingEncode (data) {
var result = '';
for (var i = 0; i < data.length; i+=5) {

// Process input 5 bytes at a time
var multiplier = 256;
var loopValue = 0;
for (var j = Math.min(data.length-1, i+4); j >= i ; j--) {
loopValue += data[j] * multiplier;
multiplier = multiplier * 256;
}

// Converts them into base32
var bytes = Math.min(data.length - i, 5);
for (var bitOffset = (bytes+1)*8 - 5; bitOffset > 3; bitOffset -= 5) {
var index = _LongUnsignedRor(loopValue,bitOffset) % 32;
result += base32StandardAlphabet[index];
}
}
return result;
}

HDInsightNamespace.prototype.GetNameSpace = function (subscriptionId, prefix, location) {
location = location.replace(' ', '-');
var hash = crypto.createHash('sha256').update(new Buffer(subscriptionId, 'utf-8')).digest('hex');
return prefix + _Base32NoPaddingEncode(new Buffer(hash, 'hex')) + '-' + location;
};

module.exports = HDInsightNamespace;
304 changes: 304 additions & 0 deletions lib/services/serviceManagement/hdinsightservice.js

Large diffs are not rendered by default.

112 changes: 112 additions & 0 deletions lib/util/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

var fs = require('fs');
var path = require('path');
var assert = require('assert');
var crypto = require('crypto');
var _ = require('underscore');

Expand Down Expand Up @@ -265,6 +266,65 @@ exports.tryGetValueInsensitive = function (key, haystack, defaultValue) {
return defaultValue;
};

function _LongUnsignedRor(value, count) {
for(var i = 0; i<count; i++) {
value = value / 2;
}
return Math.floor(value);
}

var base32StandardAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
function _Base32NoPaddingEncode (data) {
var result = '';
for (var i = 0; i < data.length; i+=5) {

// Process input 5 bytes at a time
var multiplier = 256;
var loopValue = 0;
for (var j = Math.min(data.length-1, i+4); j >= i ; j--) {
loopValue += data[j] * multiplier;
multiplier = multiplier * 256;
}

// Converts them into base32
var bytes = Math.min(data.length - i, 5);
for (var bitOffset = (bytes+1)*8 - 5; bitOffset > 3; bitOffset -= 5) {
var index = _LongUnsignedRor(loopValue,bitOffset) % 32;
result += base32StandardAlphabet[index];
}
}
return result;
}

/**
* Returns the namespace for a subscriptoinId, prefix and location
*
* @subscriptionId {string} The Azure subscription id.
* @prefix {string} The prifix for the service.
* @location {string} The location of the service.
* @return {Bool} True if the value is an integer number; false otherwise.
*/
exports.getNameSpace = function (subscriptionId, prefix, location) {
location = location.replace(' ', '-');
var hash = crypto.createHash('sha256').update(new Buffer(subscriptionId, 'utf-8')).digest('hex');
return prefix + _Base32NoPaddingEncode(new Buffer(hash, 'hex')) + '-' + location;
};

/**
* Determines if a value (string or number) is an integer number.
*
* @param {object} The value to assess.
* @return {Bool} True if the value is an integer number; false otherwise.
*/
exports.isInt = function (value){
if((parseFloat(value) == parseInt(value, 10)) && !isNaN(value)) {
return true;
}
else {
return false;
}
};

/**
* Returns the value in a chained object.
*
Expand Down Expand Up @@ -345,4 +405,56 @@ exports.analyzeStream = function (stream, calculateMD5, callback) {
});
};

function pollRequest(channel, reqid, callback) {
  channel.getOperationStatus(reqid, function(error, response) {
    if (error) {
      callback(error, { isSuccessful: false });
    } else {
      assert.ok(response.isSuccessful);
      var body = response.body;
      if (body.Status === 'InProgress') {
        setTimeout(function() {
          pollRequest(channel, reqid, callback);
        }, exports.POLL_REQUEST_INTERVAL);
      } else if (body.Status === 'Failed') {
        callback(body.Error, { isSuccessful: false,  statusCode: body.HttpStatusCode});
      } else {
        callback(null, { isSuccessful: true,  statusCode: body.HttpStatusCode});
      }
    }
  });
}

exports.doServiceManagementOperation = function(channel, operation) {
  var callback = arguments[arguments.length - 1];

  /*jshint camelcase:false*/
  function callback_(error, response) {
    if (error) {
      callback(error, response);
    } else {
      if (response.statusCode === 200) {
        callback(null, response);
      } else {
        // poll
        pollRequest(channel, response.headers['x-ms-request-id'], function(error, response) {
          if (error) {
            callback(error, response);
          } else {
            callback(null, response);
          }
        });
      }
    }
  }

  var args = Array.prototype.slice.call(arguments).slice(2, arguments.length - 1);
  args.push(callback_);
  if (!channel[operation]) {
    throw new Error('Incorrect service management operarion requested : ' + operation);
  }

  channel[operation].apply(channel, args);
};

exports.pathExistsSync = fs.existsSync ? fs.existsSync : path.existsSync;
114 changes: 114 additions & 0 deletions lib/util/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,120 @@ exports.isValidUri = function (uri) {
}
};

/**
*
* Validates that a clusterCreationObject is properly formed.
*
* @param {object} clusterCreationObject The object used to supply all parameters needed to create a cluster.
* {
* // the following are required fields
* name: 'the name of the cluster (dns name) all lower case',
* location: 'the Azure data center where the cluster is to be created',
* defaultStorageAccountName: 'The name of the default Azure storage account',
* defaultStorageAccountKey: 'The secret key for the default Azure storage account',
* defaultStorageContainer: 'The container for the default Azure storage account',
* user: 'The username to use for the cluster',
* password: 'The password to use for the cluster',
* nodes: number // The number of nodes to use
* // the following are optional fields
* additionalStorageAccounts : [ {
* name: 'the name of the storage acount'
* key: 'the secret key for the storage acount'
* }, { // additional accounts following the same pattern }
* ]
* // the following are optional but if one is specified the other is required
* oozieMetastore : {
* server : 'the name of the sql server to use',
* database : 'the sql databse to use'
* user : 'the user name to use when logging into the database'
* password : 'the password to use when logging into the database'
* }
* hiveMetastore : {
* server : 'the name of the sql server to use',
* database : 'the sql databse to use'
* user : 'the user name to use when logging into the database'
* password : 'the password to use when logging into the database'
* }
* }
*/
exports.isValidHDInsightCreationObject = function (clusterCreationObject) {
if (typeof(clusterCreationObject.name) != 'string') {
throw new Error('The [name] field is required when creating a cluster and must be a string');
}
if (typeof(clusterCreationObject.location) != 'string') {
throw new Error('The [location] field is required when creating a cluster and must be a string');
}
if (typeof(clusterCreationObject.defaultStorageAccountName) != 'string') {
throw new Error('The [defaultStorageAccountName] field is required when creating a cluster and must be a string');
}
if (typeof(clusterCreationObject.defaultStorageAccountKey) != 'string') {
throw new Error('The [defaultStorageAccountKey] field is required when creating a cluster and must be a string');
}
if (typeof(clusterCreationObject.defaultStorageContainer) != 'string') {
throw new Error('The [defaultStorageContainer] field is required when creating a cluster and must be a string');
}
if (!this.containerNameIsValid(clusterCreationObject.defaultStorageContainer, function() {})) {
throw new Error('The [defaultStorageContainer] field is required when creating a cluster and must be a valid storage container name');
}
if (typeof(clusterCreationObject.user) != 'string') {
throw new Error('The [user] field is required when creating a cluster and must be a string');
}
if (typeof(clusterCreationObject.password) != 'string') {
throw new Error('The [password] field is required when creating a cluster and must be a string');
}
if (typeof(clusterCreationObject.nodes) != 'number' || !azureutil.isInt(clusterCreationObject.nodes)) {
throw new Error('The [nodes] field is required when creating a cluster and must be an integer');
}
if (clusterCreationObject.additionalStorageAccounts) {
if (!_.isArray(clusterCreationObject.additionalStorageAccounts)) {
throw new Error('The [additionalStorageAccounts] field is optional when creating a cluster but must be an array when specified');
}
for (var i = 0; i < clusterCreationObject.additionalStorageAccounts.length; i++) {
var account = clusterCreationObject.additionalStorageAccounts[i];
if (typeof(account.name) != 'string') {
throw new Error('The [additionalStorageAccounts] field is optional but if supplied each element must have a [name] field and it must be a string. Element ' + i + ' does not have a [name] field or it is not a string');
}
if (typeof(account.key) != 'string') {
throw new Error('The [additionalStorageAccounts] field is optional but if supplied each element must have a [key] field and it must be a string. Element ' + i + ' does not have a [key] field or it is not a string');
}
}
}
if (clusterCreationObject.oozieMetastore) {
if (!clusterCreationObject.hiveMetastore) {
throw new Error('If the [oozieMetastore] field is supplied, than the [hiveMetastore] field must also be supplied');
}
if (typeof(clusterCreationObject.oozieMetastore.server) != 'string') {
throw new Error('If the [oozieMetastore] field is supplied it must contain a [server] field which must be a string');
}
if (typeof(clusterCreationObject.oozieMetastore.database) != 'string') {
throw new Error('If the [oozieMetastore] field is supplied it must contain a [database] field which must be a string');
}
if (typeof(clusterCreationObject.oozieMetastore.user) != 'string') {
throw new Error('If the [oozieMetastore] field is supplied it must contain a [user] field which must be a string');
}
if (typeof(clusterCreationObject.oozieMetastore.password) != 'string') {
throw new Error('If the [oozieMetastore] field is supplied it must contain a [password] field which must be a string');
}
}
if (clusterCreationObject.hiveMetastore) {
if (!clusterCreationObject.oozieMetastore) {
throw new Error('If the [hiveMetastore] field is supplied, than the [oozieMetastore] field must also be supplied');
}
if (typeof(clusterCreationObject.hiveMetastore.server) != 'string') {
throw new Error('If the [hiveMetastore] field is supplied it must contain a [server] field which must be a string');
}
if (typeof(clusterCreationObject.hiveMetastore.database) != 'string') {
throw new Error('If the [hiveMetastore] field is supplied it must contain a [database] field which must be a string');
}
if (typeof(clusterCreationObject.hiveMetastore.user) != 'string') {
throw new Error('If the [hiveMetastore] field is supplied it must contain a [user] field which must be a string');
}
if (typeof(clusterCreationObject.hiveMetastore.password) != 'string') {
throw new Error('If the [hiveMetastore] field is supplied it must contain a [password] field which must be a string');
}
}
};

/**
* Creates a anonymous function that check if a given key is base 64 encoded.
*
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"tunnel": ">= 0.0.1",
"request": ">= 2.9.203",
"validator": ">= 0.4.12",
"wns": ">= 0.5.3"
"wns": ">= 0.5.3",
"encdec": ">= 0.1.3"
},
"devDependencies": {
"mocha": "*",
Expand Down
Loading

0 comments on commit b775dcd

Please sign in to comment.