azure-cli
Version:
Microsoft Azure Cross Platform Command Line tool
1,551 lines (1,337 loc) • 50.1 kB
JavaScript
//
// Copyright (c) Microsoft and contributors. 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.
//
var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var url = require('url');
var util = require('util');
var uuid = require('uuid');
var azureCommon = require('azure-common');
var _ = require('underscore');
var blobUtils = require('./blobUtils');
var constants = require('./constants');
var log = require('./logging');
var utilsCore = require('./utilsCore');
var userAgentCore = require('./userAgentCore');
var commandMetadataFilter = require('./commandMetadataFilter');
var cliUserAgentFilter = require('./cliUserAgentFilter');
var locale = require('../locales/en-us.json');
var BEGIN_CERT = '-----BEGIN CERTIFICATE-----';
var END_CERT = '-----END CERTIFICATE-----';
exports.POLL_REQUEST_INTERVAL = 1000;
var moduleVersion = require('../../package.json').version;
exports.moduleVersion = moduleVersion;
exports.azureDir = utilsCore.azureDir;
exports.camelcase = utilsCore.camelcase;
exports.ignoreCaseEquals = utilsCore.ignoreCaseEquals;
exports.stringStartsWith = utilsCore.stringStartsWith;
exports.pathExistsSync = utilsCore.pathExistsSync;
var getUserAgent = exports.getUserAgent = function () {
var userAgent = util.format('AzureXplatCLI/%s', moduleVersion);
// if this env var is set, then use that in User Agent header
if (process.env.AZURE_HTTP_USER_AGENT) {
userAgent += ';' + process.env.AZURE_HTTP_USER_AGENT;
}
else {
// else, construct our custom User Agent header.
// add OS and command info into the user agent.
// Note: Do this only if the above env variable is *not set*.
var _userAgentInfo = userAgentCore.getUserAgentData();
if (_userAgentInfo) {
userAgent += ';' + Object.keys(_userAgentInfo).map(function (key) {
return key + ':' + _userAgentInfo[key];
}).join(';');
}
}
return userAgent;
};
exports.createClient = function (factoryMethod, credentials, endpoint, options) {
if(!options) {
options = {};
}
var client = factoryMethod(credentials,
exports.stringTrimEnd(endpoint, '/'))
.withFilter(exports.certAuthFilter(credentials))
.withFilter(cliUserAgentFilter.create(exports.getUserAgent()))
.withFilter(exports.createPostBodyFilter())
.withFilter(polishErrorCausedByArmProviderNotRegistered())
.withFilter(commandMetadataFilter.create(userAgentCore.getCommandData()));
if(!options.disableAutoRedirect) {
client = client.withFilter(exports.createFollowRedirectFilter());
}
if(!options.disableLogFilter) {
client = client.withFilter(log.createLogFilter());
}
return client;
};
/**
* Create Autorest client
* @param {function} Method to create an instance of the client
* @param {object} Subscription object
* @param {object} [options] - Optional parameters
* @param {boolean} [options.isTenantBased] - A Boolean value (true) indicating that the client is tenant based
* @param {string} [options.endPoint] - The url specifying the endpoint (baseUrl) for the client
*/
exports.createAutoRestClient = function (FactoryMethod, subscription, options) {
ensureAADBackedSubscription(subscription);
var credentials = null;
var baseUri = null;
var subscriptionOrTenantId = null;
if (options && options.isTenantBased && options.isTenantBased === true) {
if (!options.endPoint) {
options.endPoint = subscription.resourceManagerEndpointUrl;
}
subscriptionOrTenantId = subscription.tenantId;
credentials = subscription._createCredentials(options.endPoint);
baseUri = exports.stringTrimEnd(options.endPoint, '/');
} else {
subscriptionOrTenantId = subscription.id;
credentials = subscription._createCredentials();
baseUri = exports.stringTrimEnd(subscription.resourceManagerEndpointUrl, '/');
}
var factoryMethodOptions = {};
factoryMethodOptions.filters = [
exports.certAuthFilter(credentials),
log.createLogFilter(),
cliUserAgentFilter.create(exports.getUserAgent()),
exports.createPostBodyFilter(),
exports.createFollowRedirectFilter(),
polishErrorCausedByArmProviderNotRegistered(),
commandMetadataFilter.create(userAgentCore.getCommandData())
];
// there are a subset of clients that do not require a subscription
// TODO: need to figure out a way to pass options into factoryMethodOptions.
if (options && options.noSubscription) {
if (options.requiresBaseUri) {
return new FactoryMethod(credentials, baseUri, factoryMethodOptions);
} else {
return new FactoryMethod(credentials, factoryMethodOptions);
}
} else {
return new FactoryMethod(credentials, subscriptionOrTenantId, baseUri, factoryMethodOptions);
}
};
function _createAsmClient(factoryMethod, subscription) {
return exports.createClient(factoryMethod,
subscription._createCredentials(),
subscription.managementEndpointUrl);
}
function _createArmClient(factoryMethod, subscription, options) {
ensureAADBackedSubscription(subscription);
if(!options) {
options = {};
}
if(!options.endpoint) {
options.endpoint = subscription.resourceManagerEndpointUrl;
}
return exports.createClient(factoryMethod,
subscription._createCredentials(),
options.endpoint,
options);
}
function ensureAADBackedSubscription(subscription) {
if (subscription.wasCreatedFromPublishSettingsFile()) {
throw new Error('The current cmdlet requires you to log in using Azure Active Directory account, ' +
'not from a .publishsettings file. Please run \'azure login\' or use \'azure account set\' ' +
'to select a correct subscription.');
}
}
exports.getHDInsightClusterManagementClient = function (cloudServiceName, subscription) {
var factoryMethod = require('azure-asm-hdinsight').createHDInsightClusterManagementClient;
var client = _createAsmClient(factoryMethod, subscription);
client.cloudServiceName = cloudServiceName;
return client;
};
exports.getHDInsightCluster2ManagementClient = function (cloudServiceName, subscription) {
var factoryMethod = require('azure-asm-hdinsight').createHDInsightCluster2ManagementClient;
var client = _createAsmClient(factoryMethod, subscription);
client.cloudServiceName = cloudServiceName;
return client;
};
exports.getHDInsightJobManagementClient = function (clusterDnsName, userName, password) {
var hdinsight = require('azure-asm-hdinsight');
var client = hdinsight.createHDInsightJobManagementClient(clusterDnsName,
new hdinsight.createBasicAuthenticationCloudCredentials({ username: userName, password: password }));
return client;
};
exports.createCdnManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-cdn');
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createRedisCacheManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-rediscache');
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createHDInsightManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-hdinsight').createHDInsightManagementClient;
return _createArmClient(factoryMethod, subscription);
};
exports.createHDInsightJobManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-hdinsight-jobs').createHDInsightJobManagementClient;
return _createArmClient(factoryMethod, subscription);
};
exports.createInsightsClient = function (subscription) {
var factoryMethod = require('azure-arm-insights').createInsightsClient;
return _createArmClient(factoryMethod, subscription);
};
exports.createInsightsManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-insights').createInsightsManagementClient;
return _createArmClient(factoryMethod, subscription);
};
//website provider might not be registered yet, so make sure to register it
exports.createWebsiteClient = function (subscription, callback) {
var client;
subscription.registerAsmProvider('website', function (err) {
if (err) {
return callback(err);
}
var factoryMethod = require('azure-asm-website').createWebSiteManagementClient;
client = _createAsmClient(factoryMethod, subscription);
return callback(null, client);
});
};
exports.createWebSiteExtensionsClient = function (siteName, hostNameSuffix, username, password) {
var baseUri = util.format('https://%s.scm.%s:443', siteName, hostNameSuffix);
var azureWebSite = require('azure-asm-website');
var service = azureWebSite.createWebSiteExtensionsClient(siteName, new azureWebSite.createBasicAuthenticationCloudCredentials({
username: username,
password: password,
}), baseUri)
.withFilter(log.createLogFilter())
.withFilter(cliUserAgentFilter.create(getUserAgent()))
.withFilter(createPostBodyFilter())
.withFilter(createFollowRedirectFilter())
.withFilter(commandMetadataFilter.create(userAgentCore.getCommandData()));
return service;
};
exports.createWebappManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-website');
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createUsageManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-commerce');
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createSqlClient = function (subscription) {
var factoryMethod = require('azure-asm-sql').createSqlManagementClient;
return _createAsmClient(factoryMethod, subscription);
};
exports.createServiceBusClient = function (subscription) {
var factoryMethod = require('azure-asm-sb').createServiceBusManagementClient;
return _createAsmClient(factoryMethod, subscription);
};
exports.createManagementClient = function (subscription) {
var factoryMethod = require('azure-asm-mgmt').createManagementClient;
return _createAsmClient(factoryMethod, subscription);
};
exports.createStorageClient = function (subscription) {
var factoryMethod = require('azure-asm-storage').createStorageManagementClient;
return _createAsmClient(factoryMethod, subscription);
};
exports.createStorageResourceProviderClient = function (subscription) {
var clientConstructor = require('azure-arm-storage');
return this.createAutoRestClient(clientConstructor, subscription);
};
exports.createServerManagementClient = function(subscription) {
var clientConstructor = require('azure-arm-servermanagement');
return this.createAutoRestClient(clientConstructor, subscription);
};
exports.createBatchResourceProviderClient = function (subscription) {
var factoryMethod = require('azure-arm-batch');
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createBatchClient = function (accountName, accountKey, taskUri) {
var batch = require('azure-batch');
var credentials = new batch.SharedKeyCredentials(accountName, accountKey);
var options = {};
options.filters = [
log.createLogFilter(),
cliUserAgentFilter.create(exports.getUserAgent()),
exports.createPostBodyFilter(),
exports.createFollowRedirectFilter(),
commandMetadataFilter.create(userAgentCore.getCommandData())
];
options.generateClientRequestId = false;
var client = new batch.ServiceClient(credentials, taskUri, options);
return client;
};
/**
* Deprecated, use createComputeManagementClient instead.
*/
exports.createComputeResourceProviderClient = function (subscription) {
// TODO: delete 'armsdk' folder after migration to autorest SDK
var factoryMethod = require('./../commands/arm/armsdk/compute').createComputeResourceProviderClient;
return _createArmClient(factoryMethod, subscription);
};
exports.createComputeManagementClient = function (subscription) {
// TODO: Publish Compute npm package, uncomment the following 2 lines, and delete the other 2 lines after.
//var factoryMethod = require('azure-arm-compute');
// return this.createAutoRestClient(factoryMethod, subscription);
var factoryMethod = require('./../commands/arm/armsdk/compute').createComputeManagementClient;
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createNetworkManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-network');
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createPowerbiManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-powerbiembedded');
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createGraphManagementClient = function (subscription) {
var factoryMethod = require('azure-graph');
// Specify tenant based client and endpoint in options
var options = { isTenantBased: true, endPoint: subscription.activeDirectoryGraphResourceId };
return this.createAutoRestClient(factoryMethod, subscription, options);
};
exports.createTrafficManagerManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-trafficmanager');
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createDnsResourceProviderClient = function (subscription) {
var factoryMethod = require('azure-arm-dns');
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createComputeClient = function (subscription) {
var factoryMethod = require('azure-asm-compute').createComputeManagementClient;
return _createAsmClient(factoryMethod, subscription);
};
exports.createNetworkClient = function (subscription) {
var factoryMethod = require('azure-asm-network').createNetworkManagementClient;
return _createAsmClient(factoryMethod, subscription);
};
exports.createTrafficManagerClient = function (subscription) {
var factoryMethod = require('azure-asm-trafficmanager').createTrafficManagerManagementClient;
return _createAsmClient(factoryMethod, subscription);
};
exports.createResourceClient = function (subscription) {
var factoryMethod = require('azure-arm-resource').ResourceManagementClient;
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createSubscriptionClient = function (subscription) {
var options = {
noSubscription: true,
requiresBaseUri: true
};
var factoryMethod = require('azure-arm-resource').SubscriptionClient;
return this.createAutoRestClient(factoryMethod, subscription, options);
};
exports.createPolicyClient = function (subscription) {
var factoryMethod = require('azure-arm-resource').PolicyClient;
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createResourceManagerClient = function (subscription) {
// TODO: delete 'armsdk' folder after migration to autorest SDK
var factoryMethod = require('./../commands/arm/armsdk/resource').createResourceManagementClient;
return _createArmClient(factoryMethod, subscription);
};
exports.createResourceFeatureClient = function (subscription) {
var factoryMethod = require('azure-arm-resource').FeatureClient;
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createEventsClient = function (subscription) {
var factoryMethod = require('azure-monitoring').createEventsClient;
return _createArmClient(factoryMethod, subscription);
};
exports.createKeyVaultClient = function (subscription) {
var keyvault = require('azure-keyvault');
var authenticator = function (challenge, callback) {
// challenge.resource contains keyvault resourceId
var retrieveTokenCallback = function(err, scheme, token) {
return callback(err, util.format('%s %s', scheme, token));
};
var tokenCredentials = subscription._createCredentials(challenge.resource);
return tokenCredentials.retrieveTokenFromCache(retrieveTokenCallback);
};
var credentials;
if(subscription.user) {
credentials = new keyvault.KeyVaultCredentials(authenticator);
} else if(subscription.managementCertificate) {
credentials = subscription._createCredentials();
} else {
throw new Error('Unsupported subscription object.');
}
var options = {
filters: [
exports.certAuthFilter(credentials),
cliUserAgentFilter.create(exports.getUserAgent()),
exports.createPostBodyFilter(),
polishErrorCausedByArmProviderNotRegistered(),
commandMetadataFilter.create(userAgentCore.getCommandData())
]
};
return keyvault.createKeyVaultClient(credentials, options);
};
exports.createGalleryClient = function (subscription) {
var factoryMethod = require('azure-gallery').createGalleryClient;
return exports.createClient(factoryMethod,
new azureCommon.AnonymousCloudCredentials(),
subscription.galleryEndpointUrl);
};
exports.createMobileClient = function (subscription) {
return _createAsmClient(function (credentials) {
//propagates errors that ErrorHandlingFilter in azureCommon.Service would swallow
var errorPropagationFilter = function handle(resource, next, callback) {
return next(resource, function (err, response, body) {
if (body !== undefined && response !== undefined && (response.statusCode < 200 || response.statusCode >= 300)) {
callback(body, response, body);
} else {
callback(err, response, body);
}
});
};
var client = new azureCommon.Service(credentials, [errorPropagationFilter]);
client.longRunningOperationRetryTimeout = 5000;
return client;
}, subscription);
};
exports.createDataLakeStoreFileSystemManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-datalake-store').DataLakeStoreFileSystemClient;
var options = {
noSubscription: true,
dnsSuffix: subscription.azureDataLakeStoreFileSystemEndpointSuffix,
};
return this.createAutoRestClient(factoryMethod, subscription, options);
};
exports.createDataLakeStoreManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-datalake-store').DataLakeStoreAccountClient;
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createDataLakeAnalyticsManagementClient = function (subscription) {
var factoryMethod = require('azure-arm-datalake-analytics').DataLakeAnalyticsAccountClient;
return this.createAutoRestClient(factoryMethod, subscription);
};
exports.createDataLakeAnalyticsJobManagementClient = function (subscription) {
var options = {
noSubscription: true,
dnsSuffix: subscription.azureDataLakeAnalyticsCatalogAndJobEndpointSuffix
};
var factoryMethod = require('azure-arm-datalake-analytics').DataLakeAnalyticsJobClient;
return this.createAutoRestClient(factoryMethod, subscription, options);
};
exports.createDataLakeAnalyticsCatalogManagementClient = function (subscription) {
var options = {
noSubscription: true,
dnsSuffix: subscription.azureDataLakeAnalyticsCatalogAndJobEndpointSuffix
};
var factoryMethod = require('azure-arm-datalake-analytics').DataLakeAnalyticsCatalogClient;
return this.createAutoRestClient(factoryMethod, subscription, options);
};
exports.createDevTestLabsClient = function (subscription) {
var clientConstructor = require('azure-arm-devtestlabs');
return this.createAutoRestClient(clientConstructor, subscription);
};
exports.getiotHubClient = function (subscription) {
var clientConstructor = require('azure-arm-iothub');
return this.createAutoRestClient(clientConstructor, subscription);
};
/**
* Create old-style service object
* @param {string} serviceFactoryName name of factory function off azure module
*/
function createService(factoryMethod, subscription) {
var managementEndpoint = url.parse(subscription.managementEndpointUrl);
var service = factoryMethod(subscription.id, {
keyvalue: subscription.managementCertificate.key,
certvalue: subscription.managementCertificate.cert,
},
{
host: managementEndpoint.hostname,
port: managementEndpoint.port,
serializetype: 'XML'
}).withFilter(new RequestLogFilter(log));
return service;
}
exports.createWebsiteManagementService = function (subscription) {
var factoryMethod = require('azure-asm-website').createWebsiteManagementService;
return createService(factoryMethod, subscription);
};
// TODO: workaround for release 0.7.4. Remove in vnext and fix underlying issue in SDK.
function createPostBodyFilter() {
return function handle(resource, next, callback) {
if ((resource.method === 'POST' || resource.method === 'PUT' || resource.method === 'PATCH') && !resource.body) {
resource.body = '';
}
var stream = next(resource, callback);
stream.on('error', function () {
});
return stream;
};
}
exports.createPostBodyFilter = createPostBodyFilter;
function certAuthFilter(credentials) {
return function handle(resource, next, callback) {
if (credentials && credentials.credentials && credentials.credentials.key && credentials.credentials.cert) {
resource.key = credentials.credentials.key;
resource.cert = credentials.credentials.cert;
}
return next(resource, callback);
};
}
exports.certAuthFilter = certAuthFilter;
function createFollowRedirectFilter() {
return function handle(resource, next, callback) {
function handleRedirect(err, response, body) {
if (response &&
response.headers.location &&
response.statusCode >= 300 &&
response.statusCode < 400) {
resource.url = response.headers.location;
next(resource, handleRedirect);
} else if (callback) {
callback(err, response, body);
}
}
return next(resource, handleRedirect);
};
}
exports.createFollowRedirectFilter = createFollowRedirectFilter;
polishErrorCausedByArmProviderNotRegistered = function () {
return function handle(resource, next, callback) {
var nextStream = next(resource, function (err, response, body) {
if (err && err.message && response && response.statusCode === 409) {
var re = /.*registered to use namespace \'(.+)\'/i;
var found = re.exec(err.message);
var providerName = (found && found.length === 2) ? found[1] : null;
if (providerName) {
err.message = util.format('The subscription must be registered to use namespace "%s". ' +
'This can be achieved by executing the command: "azure provider ' +
'register %s".', providerName, providerName);
}
}
callback(err, response, body);
});
return nextStream;
};
};
exports.createScmManagementService = function (repository, auth) {
var authentication = auth.split(':');
var repositoryUrl = url.parse(repository);
var azureWebSite = require('azure-asm-website');
var service = azureWebSite.createScmService({
user: authentication[0],
pass: authentication[1]
}, {
host: repositoryUrl.hostname,
port: repositoryUrl.port
});
service.userAgent = getUserAgent();
return service;
};
exports.createBlobService = function () {
var storage = require('azure-storage');
var blobService = storage.createBlobService.apply(this, arguments);
blobService.userAgent = getUserAgent();
return blobService;
};
exports.createSqlService = function () {
var azureSqlMgmt = require('azure-asm-sql');
var sqlService = azureSqlMgmt.createSqlService.apply(this, arguments);
sqlService.userAgent = getUserAgent();
return sqlService;
};
exports.getLocaleString = function (string) {
var result = locale[string];
if (!result) {
if (process.env.AZURE_DEBUG_LABELS) {
throw new Error(util.format('Invalid resource %s', string));
} else {
return string;
}
}
return result;
};
function RequestLogFilter(logger) {
this.logger = logger;
}
RequestLogFilter.prototype.handle = function (requestOptions, next) {
var self = this;
this.logger.silly('requestOptions');
this.logger.json('silly', requestOptions);
if (next) {
next(requestOptions, function (returnObject, finalCallback, nextPostCallback) {
self.logger.silly('returnObject');
self.logger.json('silly', returnObject);
if (nextPostCallback) {
nextPostCallback(returnObject);
} else if (finalCallback) {
finalCallback(returnObject);
}
});
}
};
exports.RequestLogFilter = RequestLogFilter;
exports.isSha1Hash = function (str) {
return (/\b([a-fA-F0-9]{40})\b/).test(str);
};
exports.webspaceFromName = function (name) {
return (name.replace(/ /g, '').toLowerCase() + 'webspace');
};
exports.getCertFingerprint = function (pem) {
var certBase64 = exports.extractBase64CertFromPEM(pem);
// Calculate sha1 hash of the cert
var cert = new Buffer(certBase64, 'base64');
var sha1 = crypto.createHash('sha1');
sha1.update(cert);
return sha1.digest('hex');
};
exports.isPemCert = function (data) {
return data.indexOf(BEGIN_CERT) !== -1 && data.indexOf(END_CERT) !== -1;
};
exports.extractBase64CertFromPEM = function (pem) {
// Extract the base64 encoded cert out of pem file
var beginCert = pem.indexOf(BEGIN_CERT) + BEGIN_CERT.length;
if (pem[beginCert] === '\n') {
beginCert = beginCert + 1;
} else if (pem[beginCert] === '\r' && pem[beginCert + 1] === '\n') {
beginCert = beginCert + 2;
}
var endCert = '\n' + pem.indexOf(END_CERT);
if (endCert === -1) {
endCert = '\r\n' + pem.indexOf(END_CERT);
}
return pem.substring(beginCert, endCert);
};
exports.getOrCreateBlobStorage = function (cli, storageClient, location, affinityGroup, name, storagePrefix, callback) {
var progress;
/*jshint camelcase:false*/
function callback_(error, blobStorageUrl) {
progress.end();
callback(error, blobStorageUrl);
}
function createNewStorageAccount_() {
if (exports.stringIsNullOrEmpty(storagePrefix)) {
storagePrefix = name;
}
var storageAccountName = blobUtils.normalizeServiceName(storagePrefix + (new Date()).getTime().toString());
cli.output.verbose('Creating a new storage account \'' + storageAccountName + '\'');
var storageOptions = {
name: storageAccountName,
label: storageAccountName,
geoReplicationEnabled: false,
accountType: 'Standard_LRS'
};
if (affinityGroup) {
storageOptions.affinityGroup = affinityGroup;
} else if (location) {
storageOptions.location = location;
} else {
throw new Error('location or affinityGroup must be specified');
}
progress = cli.interaction.progress('Creating a new storage account \'' + storageAccountName + '\'');
storageClient.storageAccounts.create(storageOptions, function (error) {
if (error) {
callback_(error);
} else {
cli.output.verbose('Storage account successfully created');
cli.output.verbose('Getting properties for \'' + storageAccountName + '\' storage account');
storageClient.storageAccounts.get(storageAccountName, function (error, response) {
if (error) {
callback_(error);
} else {
var storageAccount = response.storageAccount;
if (storageAccount) {
var blobStorageUrl = storageAccount.properties.endpoints[0];
if (blobStorageUrl.slice(-1) === '/') {
blobStorageUrl = blobStorageUrl.slice(0, -1);
}
callback_(null, blobStorageUrl);
} else {
callback_(new Error('No storage account found'));
}
}
});
}
});
}
progress = cli.interaction.progress('Retrieving storage accounts');
cli.output.verbose('Getting list of available storage accounts');
storageClient.storageAccounts.list(function (error, response) {
if (error) {
callback_(error);
} else {
var storageAccounts = response.storageAccounts;
for (var i = 0; i < storageAccounts.length; i++) {
if ((location && storageAccounts[i].properties.location && storageAccounts[i].properties.location.toLowerCase() === location.toLowerCase()) ||
affinityGroup && storageAccounts[i].properties.affinityGroup && storageAccounts[i].properties.affinityGroup.toLowerCase() === affinityGroup.toLowerCase()) {
if (!exports.stringIsNullOrEmpty(storagePrefix)) {
if (!exports.stringStartsWith(storageAccounts[i].name, storagePrefix)) {
continue;
}
}
var blobStorageUrl = storageAccounts[i].properties.endpoints[0];
if (blobStorageUrl.slice(-1) === '/') {
blobStorageUrl = blobStorageUrl.slice(0, -1);
}
callback_(null, blobStorageUrl);
return;
}
}
createNewStorageAccount_();
}
});
};
exports.writeFileSyncMode = function writeFileSyncMode(path, data, encoding, mode) {
mode = mode || parseInt('600', 8); // maximum protection by default
var fd = fs.openSync(path, 'w', mode);
try {
if (typeof data === 'string') {
fs.writeSync(fd, data, 0, encoding);
} else {
fs.writeSync(fd, data, 0, data.length, 0);
}
} finally {
fs.closeSync(fd);
}
};
exports.getDnsPrefix = function (dnsName, allowEmpty) {
if (dnsName) {
// remove protocol if any, take the last element
dnsName = dnsName.split('://').slice(-1)[0];
// take first element
dnsName = dnsName.split('.', 1)[0];
}
if (!dnsName && !allowEmpty) {
throw new Error('Missing or invalid dns-name');
}
return dnsName;
};
/**
* Resolve location name if 'name' is location display name.
*
* @param {string} name The display name or location name. Required
* @param {function} callback The callback function called on completion. Required.
*/
exports.resolveLocationName = function (managementClient, name, callback) {
managementClient.locations.list(function (error, response) {
var resolvedLocation = null;
if (!error) {
if (response.locations.length > 0) {
for (var i = 0; i < response.locations.length; i++) {
var locationInfo = response.locations[i];
if (exports.ignoreCaseEquals(locationInfo.name, name)) {
callback(null, locationInfo);
return;
} else if (!resolvedLocation && (exports.ignoreCaseEquals(locationInfo.DisplayName, name))) {
// This is the first matched display name save the corresponding location
// We ignore further matched display name, but will continue with location
// matching
resolvedLocation = locationInfo;
}
}
if (resolvedLocation) {
callback(null, resolvedLocation);
} else {
callback({
message: 'No location found which has DisplayName or Name same as value of --location',
code: 'Not Found'
}, name);
}
} else {
// Return a valid error
callback({ message: 'Server returns empty location list', code: 'Not Found' }, name);
}
} else {
callback(error, null);
}
});
};
exports.parseInt = function (value) {
var intValue = parseInt(value, 10);
if (intValue != value || value >= 65536 * 65536) { // just some limits
return NaN;
}
return intValue;
};
exports.parseBool = function (value, paramName) {
if (typeof value === 'boolean') {
return value;
}
if (!this.ignoreCaseEquals(value, 'true') && !this.ignoreCaseEquals(value, 'false')) {
throw new Error(util.format('%s parameter must be true or false', paramName));
}
return value.toLowerCase() === 'true';
};
/**
* Creates a anonymous function that validator if the given string is a valid datetime.
*
* @param {string} stringDateTime The datetime string.
* @return {Date}
*/
exports.parseDateTime = function (stringDateTime) {
try {
return new Date(stringDateTime);
} catch (e) {
throw new Error($('The date format is incorrect'));
}
};
exports.getUTCTimeStamp = function () {
var now = new Date();
return (now.getUTCFullYear() + '-' +
('0' + (now.getUTCMonth() + 1)).slice(-2) + '-' +
('0' + now.getUTCDate()).slice(-2) + ' ' +
('0' + now.getUTCHours()).slice(-2) + ':' +
('0' + now.getUTCMinutes()).slice(-2));
};
exports.logLineFormat = function logLineFormat(object, logFunc, prefix) {
prefix = prefix || '';
switch (typeof object) {
case 'object':
// if this is a date then we call toISOString and print that
if (_.isDate(object)) {
logFunc(prefix.cyan + object.toISOString().green);
} else {
for (var i in object) {
logLineFormat(object[i], logFunc, prefix + i + ' ');
}
}
return;
case 'string':
logFunc(prefix.cyan + ('"' + object + '"').green);
return;
case 'boolean':
logFunc(prefix.cyan + object.toString().green);
return;
case 'number':
logFunc(prefix.cyan + object.toString().green);
return;
case 'undefined':
return;
default:
logFunc(prefix.cyan + '?' + object + '?'); // unknown type
}
};
exports.validateEndpoint = function (endpoint) {
if (!exports.stringStartsWith(endpoint, 'http://') && !exports.stringStartsWith(endpoint, 'https://')) {
// Default to https
endpoint = 'https://' + endpoint;
}
var parts = url.parse(endpoint);
if (!parts.hostname) {
throw new Error('Invalid endpoint format.');
}
parts.port = (parts.port && parseInt(parts.port, 10)) || (/https/i.test(parts.protocol) ?
constants.DEFAULT_HTTPS_PORT :
constants.DEFAULT_HTTP_PORT);
return url.format(parts);
};
/**
* Determines if a string is null or empty.
*
* @param {string} text The string to test.
* @return {Bool} True if the string string is null or empty; false otherwise.
*/
exports.stringIsNullOrEmpty = function (text) {
return text === null ||
text === undefined ||
text.trim() === '';
};
exports.stripBOM = function (content) {
if (Buffer.isBuffer(content)) {
content = content.toString();
}
if (content.charCodeAt(0) === 0xFEFF) {
content = content.slice(1);
}
return content;
};
/**
* Determines if a string ends with another.
*
* @param {string} text The string to assert.
* @param {string} suffix The string suffix.
* @param {bool} ignoreCase Boolean value indicating if casing should be ignored.
* @return {Bool} True if the string ends with the suffix; false otherwise.
*/
exports.stringEndsWith = function (text, suffix, ignoreCase) {
if (_.isNull(suffix)) {
return true;
}
if (ignoreCase) {
text = text.toLowerCase();
suffix = suffix.toLowerCase();
}
return text.substr(text.length - suffix.length) === suffix;
};
exports.stringTrimEnd = function (text, charToTrim) {
if (!text) {
return text;
}
if (!charToTrim) {
charToTrim = ' ';
}
var subtract = 0;
while (subtract < text.length && text[text.length - (subtract + 1)] === charToTrim) {
subtract++;
}
return text.substr(0, text.length - subtract);
};
exports.logError = function (log, message, err) {
if (arguments.length == 1) {
err = message;
message = undefined;
} else {
log.error(message);
}
if (err) {
if (err.message) {
// log.error(err.message);
log.verbose('stack', err.stack);
log.json('silly', err);
}
else if (err.Message) {
// log.error(err.Message);
log.json('verbose', err);
}
}
};
exports.clearConfig = function () {
var azureConfigPath = path.join(exports.azureDir(), 'config.json');
if (exports.pathExistsSync(azureConfigPath)) {
fs.unlinkSync(azureConfigPath);
return true;
}
};
exports.copyIisNodeWhenServerJsPresent = function (log, rootPath, callback) {
try {
var iisnodeyml = 'iisnode.yml';
log.silly('copyWebConfigWhenServerJsPresent');
if (!exports.pathExistsSync(iisnodeyml) && (exports.pathExistsSync(path.join(rootPath, 'server.js')) || exports.pathExistsSync(path.join(rootPath, 'app.js')))) {
log.info('Creating default ' + iisnodeyml + ' file');
var sourcePath = path.join(__dirname, '../templates/node/' + iisnodeyml);
fs.readFile(sourcePath, function (err, result) {
if (err) {
callback(err);
return;
}
fs.writeFile(path.join(rootPath, iisnodeyml), result, callback);
});
}
else {
callback();
}
}
catch (e) {
callback(e);
}
};
exports.normalizeParameters = function (paramDescription) {
var key, positionalValue, optionValue;
var paramNames = Object.keys(paramDescription);
var finalValues = {};
for (var i = 0; i < paramNames.length; ++i) {
key = paramNames[i];
positionalValue = paramDescription[key][0];
optionValue = paramDescription[key][1];
if (!_.isUndefined(positionalValue) && !_.isUndefined(optionValue)) {
return { err: new Error('You must specify ' + key + ' either positionally or by name, but not both') };
} else {
finalValues[key] = positionalValue || optionValue;
}
}
return { values: finalValues };
};
/**
* fs.exists wrapper for streamline
*/
exports.fileExists = function (filePath, cb) {
var func = fs.exists;
if (!func) {
func = path.exists;
}
func(filePath, function (exists) {
cb(null, exists);
});
};
/**
* Wildcard Util only support two wildcard character * and ?
*/
exports.Wildcard = {
/**
* does the specified the character contain wildcards
*/
containWildcards: function (str) {
var wildcardReg = /[*?]/img;
return str !== null && wildcardReg.test(str);
},
/**
* Get the max prefix string of the specified string which doesn't contain wildcard
*/
getNonWildcardPrefix: function (str) {
var nonWildcardReg = /[^*?]*/img;
var prefix = '';
if (str !== null) {
var result = str.match(nonWildcardReg);
if (result !== null && result.length > 0) {
prefix = result[0];
}
}
return prefix;
},
/**
* Convert wildcard pattern to regular expression
*/
wildcardToRegexp: function (str, isCaseInsensitive) {
var strRegexp = '';
if (str !== null) {
strRegexp = str.replace(/\?/g, '.').replace(/\*/g, '.*');
}
var regexp = new RegExp();
if (isCaseInsensitive && isCaseInsensitive === true) {
regexp.compile('^' + strRegexp + '$', 'ig');
}
else {
regexp.compile('^' + strRegexp + '$');
}
return regexp;
},
/**
* Is the specified string match the case sensitive specified wildcard pattern
*/
isMatch: function (str, pattern) {
var reg = exports.Wildcard.wildcardToRegexp(pattern);
return reg.test(str);
},
/**
* Is the specified string match the case insensitive specified wildcard pattern
*/
isMatchCaseInsensitive: function (str, pattern) {
var reg = exports.Wildcard.wildcardToRegexp(pattern, true);
return reg.test(str);
}
};
/**
* Invalid file name chars in windows.
* http://msdn.microsoft.com/en-us/library/system.io.path.getinvalidfilenamechars.aspx
*/
exports.invalidFileNameChars = [34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47];
/**
* Reserved file name in windows
*/
exports.reservedBaseFileNamesInWindows = ['con', 'prn', 'aux', 'nul', 'com1', 'com2', 'com3', 'com4', 'com5', 'com6', 'com7', 'com8', 'com9', 'lpt1', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9'];
/**
* Is the reserved file name in windows
*/
exports.isReservedFileNameInWindows = function (name) {
name = (name || '').toLowerCase();
var index = exports.reservedBaseFileNamesInWindows.indexOf(name);
return index !== -1;
};
/*
* Escape file path
*/
exports.escapeFilePath = function (name) {
if (exports.isWindows()) {
//only escape file name on windows
var regExp = exports.getReplaceRegExpFromCharCode(exports.invalidFileNameChars);
name = name.replace(regExp, function (code) {
return '%' + code.charCodeAt(0).toString(16);
});
var extName = path.extname(name);
var baseName = path.basename(name, extName);
if (exports.isReservedFileNameInWindows(baseName)) {
name = util.format('%s (1)%s', baseName, extName);
}
}
return name;
};
/**
* Is windows platform
*/
exports.isWindows = function () {
return !!process.platform.match(/^win/);
};
/**
* Join the char code into a replace regular expression
* For example,
* [65,66] => /A|B/img
* [63,66] => /\?|B/img
*/
exports.getReplaceRegExpFromCharCode = function (charCodeArray) {
function charCodeToRegChar(charCode) {
var str = String.fromCharCode(charCode);
switch (str) {
case '*':
case '?':
case '.':
case '\\':
case '|':
case '/':
str = '\\' + str;
break;
}
return str;
}
var regExp = new RegExp();
if (charCodeArray.length) {
var regStr = charCodeToRegChar(charCodeArray[0]);
for (var i = 1; i < charCodeArray.length; i++) {
regStr += '|' + charCodeToRegChar(charCodeArray[i]);
}
regExp.compile(regStr, 'gim');
}
return regExp;
};
/**
* Add function overloads to an object that vary by
* declared argument length.
*
* @param {function} func the function overloads.
*
* @returns The 'overloaded' function
*/
exports.overload = function () {
function final() {
throw new Error(util.format($('Unknown overload for %s parameters'), arguments.length));
}
var func = final;
/* jshint loopfunc: true */
for (var i = 0; i < arguments.length; ++i) {
func = (function (old, func) {
return function () {
if (func.length === arguments.length) {
return func.apply(this, arguments);
} else if (typeof old === 'function') {
return old.apply(this, arguments);
}
};
})(func, arguments[i]);
}
return func;
};
//"<root>\test\framework\cli-test.js" contains associated test stubs. Please keep them in sync.
exports.uuidGen = function () {
return uuid.v4();
};
//Provides a random string starting with the given (string) prefix. If prefix is not provided
//then it provides a random alphanumeric string
exports.getRandomString = function (prefix) {
var randomStr = Math.random().toString(36).substr(2, 12);
if (prefix !== null && prefix !== undefined && typeof prefix.valueOf() === 'string') {
return prefix + randomStr;
}
return randomStr;
};
exports.toLowerCaseAndRemoveSpace = function (str) {
if (!str) {
return str;
}
return str.replace(/ /gi, '').toLowerCase();
};
exports.ignoreCaseAndSpaceEquals = function (a, b) {
return a === b || (exports.toLowerCaseAndRemoveSpace(a) === exports.toLowerCaseAndRemoveSpace(b));
};
exports.atLeastOneParameIsSet = function (params) {
for (var i = 0; i < params.length; i++) {
if (!exports.stringIsNullOrEmpty(params[i])) {
return true;
}
}
return false;
};
exports.allParamsAreSet = function (params) {
for (var i = 0; i < params.length; i++) {
if (exports.stringIsNullOrEmpty(params[i])) {
return false;
}
}
return true;
};
// Many of the commands accepts arguments whose valid values can be from an enum. For example
// protocol argument for endpoints create, valid values are ['tcp', 'udp', 'http'].
// This method can be used to validate user provided input against the possible valid
// values (supportedTypes). This method do case ignore comparison and return matched enum
// value. If no match found exception will be thrown and exception message will inform valid
// values.
exports.verifyParamExistsInCollection = function (supportedTypes, paramToCheck, paramName) {
var i = _.indexOf(_.map(supportedTypes, function (s) {
return s.toLowerCase();
}), paramToCheck.toLowerCase());
if (i === -1) {
throw new Error(util.format(exports.getLocaleString('Given %s "%s" is invalid, supported values are: %s'), paramName, paramToCheck, supportedTypes.join(', ')));
}
return supportedTypes[i];
};
exports.hasValidProperty = function (object, propName) {
if (object === null || object === undefined) {
return false;
}
if (!object.hasOwnProperty(propName)) {
return false;
}
if (object[propName] === null || object[propName] === undefined) {
return false;
}
return true;
};
exports.parseResourceReferenceUri = function (referenceUri) {
var parts = referenceUri.split('/');
return {
subscriptionId: parts[2],
resourceGroupName: parts[4],
provider: parts[6], // e.g. Microsoft.Network
parentResource: parts.slice(7, parts.length - 1).join('/'), // e.g. virtualNetworks/<vnet-name>/subnets
resourceName: parts[parts.length - 1] // e.g. <subnet-name>
};
};
exports.isAttributesMatched = function (item, attributes) {
for (var key in attributes) {
var value1 = attributes[key];
var value2 = item[key];
if (typeof value1 === 'string' && typeof value2 === 'string') {
value1 = value1.toLowerCase();
value2 = value2.toLowerCase();
}
if (value1 !== value2) return false;
}
return true;
};
/**
* Looks through the list and returns the element that matches attributes,
* case-insensitive.
*/
exports.findFirstCaseIgnore = function (list, attributes) {
if (_.isEmpty(attributes)) {
return undefined;
}
return _.find(list, function (item) {
return exports.isAttributesMatched(item, attributes);
});
};
/**
* Looks through the list and returns the index of element that matches attributes or -1 if it is not present,
* case-insensitive.
*/
exports.indexOfCaseIgnore = function (list, attributes) {
if (_.isEmpty(list) || _.isEmpty(attributes)) {
return -1;
}
for (var i = 0; i < list.length; i++) {
var item = list[i];
var match = exports.isAttributesMatched(item, attributes);
if (match) return i;
}
return -1;
};
exports.argHasValue = function (argument) {
return (argument !== true && argument !== '\'\'');
};
exports.trimTrailingChar = function (str, charToTrim) {
while (str.length > 0 && str.charAt(str.length - 1) == charToTrim) {
str = str.substr(0, str.length - 1);
}
return str;
};
exports.appendArray = function (array, otherArray) {
for (var i = 0; i < otherArray.length; i++) {
array.push(otherArray[i]);
}
};
exports.capitalizeFirstLetter = function (str) {
return str.charAt(0).toUpperCase() + str.slice(1);
};
exports.toRange = function (array) {
return '[' + array[0] + '-' + array[1] + ']';
};
exports.setIndent = function(num) {
if (num > 0) {
return new Array(num + 1).join(' ');
}
return '';
};
exports.getHash = function (name) {
// Define Utility Functions - Reference: http://www.cse.yorku.ca/~oz/hash.html
var hash = 5381;
var seedstr = name;
for (var i = 0; i < seedstr.length; i++) {
var c = parseInt(seedstr.charCodeAt(i));
hash = ((((hash << 5) + hash) + c) % Number.MAX_VALUE) >>> 0;
}
return hash;
};
exports.vmImageAliasUrl = 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/arm-compute/quickstart-templates/aliases.json';
exports.getImageAliasFilePath = function() {
return __dirname + '/aliases/image.json';
};
exports.getImageAliasFileContent = function() {
var content = fs.readFileSync(exports.getImageAliasFilePath(), 'utf8');
content = content.replace(/^\uFEFF/, '');
return content;
};
exports.parseImageAliasDict = function(aliasObj) {
var aliasDict = {};
var key = null;
for (key in aliasObj.outputs.aliases.value.Windows) {
aliasDict[key] = aliasObj.outputs.aliases.value.Windows[key];
}
for (key in aliasObj.outputs.aliases.value.Linux) {
aliasDict[key] = aliasObj.outputs.aliases.value.Linux[key];
}
return aliasDict;
};
exports.getImageAliasUrn = function(alias, aliasObj) {
if (!aliasObj) {
var content = exports.getImageAliasFileContent();
aliasObj = JSON.parse(content);
}
var aliasArr = exports.parseImageAliasDict(aliasObj);
for (var i in aliasArr) {
if (i.toLowerCase() === alias.toLowerCase()) {
return [aliasArr[i].publisher, aliasArr[i].offer, aliasArr[i].sku, aliasArr[i].version].join(':');
}
}
return null;
};
exports.getImageAliasList = function() {
var content = null;
if (fs.existsSync(exports.getImageAliasFilePath())) {
content = exports.getImageAliasFileContent();
}
else {
var request = require('sync-request');
var response = request('GET', exports.vmImageAliasUrl);
content = response.getBody();
exports.writeFileSyncMode(exports.getImageAliasFilePath(), content, 'utf-8');
}
var aliasObj = JSON.parse(content);
var list = [];
var aliasArr = exports.parseImageAliasDict(aliasObj);
for (var i in aliasArr) {
list.push(i + ' = ' + exports.getImageAliasUrn(i, aliasObj));
}
return list;
};
exports.takeDefault = function(output, defValue, paramName) {
output.warn(util.format(('Using default %s %s'), paramName, defValue));
return defValue;
};
exports.getPublicIp = function(vm) {
var publicIPAddress;
if(!vm.networkProfile.networkInterfaces[0].expanded.ipConfigurations[0].publicIPAddress) {
publicIPAddress = 'N/A';
}
else {
publicIPAddress = vm.networkProfile.networkInterfaces[0].expanded.ipConfigurations[0].publicIPAddress.expanded.ipAddress;
}
return publicIPAddress;
};
/**
* trunc
*
* truncates the string with '...' endings
* @returns {string}
*/
functio