azure-cli
Version:
Microsoft Azure Cross Platform Command Line tool
1,405 lines (1,242 loc) • 199 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 _ = require('underscore');
var fs = require('fs');
var url = require('url');
var async = require('async');
var util = require('util');
var utils = require('../../../util/utils');
var blobUtils = require('../../../util/blobUtils');
var vmConstants = require('../../../util/vmConstants');
var pageBlob = require('../iaas/upload/pageBlob');
var CommunityUtil = require('../../../util/communityUtil');
var crypto = require('crypto');
var VNetUtil = require('../../../util/vnet.util');
var EndPointUtil = require('../../../util/endpointUtil');
var underscore = require('underscore');
var $ = utils.getLocaleString;
var profile = require('../../../util/profile');
var path = require('path');
var openssl = require('openssl-wrapper');
var exec = require('child_process').exec;
var vmUtils = require('./vmUtils');
var certUtils = require('../../../util/certUtils');
var CHEFPUBLISHER = 'Chef.Bootstrap.WindowsAzure';
function VMClient(cli, subscription) {
this.cli = cli;
this.subscription = subscription;
}
_.extend(VMClient.prototype, {
createVM: function(dnsName, imageName, userName, password, options, callback, logger) {
var self = this;
var dnsPrefix = utils.getDnsPrefix(dnsName);
var vmSize = getVMSize(options, logger);
if (options.rdp) {
if (typeof options.rdp === 'boolean') {
options.rdp = 3389;
} else if ((options.rdp != parseInt(options.rdp, 10)) || (options.rdp > 65535)) {
return callback(new Error($('--rdp [port] must be an integer less than or equal to 65535')));
}
}
// Note: The optional argument --no-ssh-password maps to options.sshPassword.
// if --no-ssh-password is specified in the command line then options.sshPassword
// will be set to 'false' by commander. If --no-ssh-password is not specified as
// an option then options.sshPassword will be set to true by commander.
if (options.ssh) {
if (typeof options.ssh === 'boolean') {
options.ssh = 22;
} else if ((options.ssh != parseInt(options.ssh, 10)) || (options.ssh > 65535)) {
return callback(new Error($('--ssh [port] must be an integer less than or equal to 65535')));
}
} else if ((!options.sshPassword || options.sshCert || options.generateSshKeys) && options.sshEndpoint) {
return callback(new Error($('--no-ssh-password, --ssh-cert and --generate-ssh-keys can only be used with --ssh or --no-ssh-endpoint parameter')));
}
if (!options.sshPassword && (!options.sshCert && !options.generateSshKeys)) {
return callback(new Error($('--no-ssh-password can only be used with the --ssh-cert or --generate-ssh-keys parameter')));
}
if (options.customData) {
// Size of customData file should be less then 64 KB
var stats = fs.statSync(options.customData);
var maxSize = 65535; // 64 KB
if (stats['size'] > maxSize) {
return callback(new Error($('--custom-data must be less than 64 KB')));
}
}
if (options.staticIp) {
var vnetUtil = new VNetUtil();
var parsedIp = vnetUtil.parseIPv4(options.staticIp);
if (parsedIp.error) {
return callback(parsedIp.error);
}
if (!options.virtualNetworkName) {
return callback(new Error($('--virtual-network-name must be specified when the --static-ip option is given')));
}
if (options.subnetNames) {
logger.warn('--static-ip, --subnet-names will be ignored and the static ip subnet will be used');
options.subnetNames = null;
}
} else if (options.subnetNames) {
if (!options.virtualNetworkName) {
return callback(new Error($('--virtual-network-name must be specified when the --subnet-names option is given')));
}
}
var nicConfiguration = parseNICParams(options.nicConfig);
if (nicConfiguration.error) {
return callback(new Error(nicConfiguration.error));
}
if (nicConfiguration.networkInterfaces.length !== 0) {
if (!options.staticIp) {
if (!options.subnetNames || !options.virtualNetworkName) {
return callback(new Error($('--virtual-network-name and --subnet-names must be specified when the --nic-config option is given')));
}
}
}
var computeManagementClient = self.createComputeManagementClient();
var managementClient = self.createManagementClient();
var storageClient = self.createStorageClient();
var networkClient = self.createNetworkClient();
createVM({
dnsPrefix: dnsPrefix,
imageName: imageName,
password: password,
userName: userName,
subscription: options.subscription,
size: vmSize,
location: options.location,
affinityGroup: options.affinityGroup,
imageTarget: options.blobUrl,
ssh: options.ssh,
sshCert: options.sshCert,
sshEndpoint: options.sshEndpoint,
generateSshKeys: options.generateSshKeys,
logger: logger,
noSshPassword: options.sshPassword === false,
noSshEndpoint: options.sshEndpoint === false,
rdp: options.rdp,
connect: options.connect,
community: options.community,
vmName: options.vmName,
virtualNetworkName: options.virtualNetworkName,
subnetNames: options.subnetNames,
staticIp: options.staticIp,
reservedIp: options.reservedIp,
publicIp: options.publicIp,
availabilitySet: options.availabilitySet,
customData: options.customData,
bootDiagnosticsEnabled: (options.disableBootDiagnostics === true ? false : true),
networkInterfaces: nicConfiguration.networkInterfaces,
computeManagementClient: computeManagementClient,
managementClient: managementClient,
storageClient: storageClient,
networkClient: networkClient
}, callback, logger, self.cli);
},
createVMfromJson: function(dnsName, roleFile, options, callback, logger) {
var self = this;
function stripBOM(content) {
// Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
// because the buffer-to-string conversion in `fs.readFileSync()`
// translates it to FEFF, the UTF-16 BOM.
if (content.charCodeAt(0) === 0xFEFF || content.charCodeAt(0) === 0xFFFE) {
content = content.slice(1);
}
return content;
}
var dnsPrefix = utils.getDnsPrefix(dnsName);
logger.verbose(util.format($('Loading role file: %s'), roleFile));
var jsonFile = fs.readFileSync(roleFile, 'utf8');
var role = JSON.parse(stripBOM(jsonFile));
// remove resourceExtensionReferences if empty
if (role.resourceExtensionReferences.length === 0) {
delete role.resourceExtensionReferences;
}
var computeManagementClient = self.createComputeManagementClient();
var managementClient = self.createManagementClient();
var storageClient = self.createStorageClient();
var networkClient = self.createNetworkClient();
createVM({
subscription: options.subscription,
location: options.location,
affinityGroup: options.affinityGroup,
dnsPrefix: dnsPrefix,
connect: options.connect,
role: role,
sshCert: options.sshCert,
virtualNetworkName: options.virtualNetworkName,
computeManagementClient: computeManagementClient,
managementClient: managementClient,
storageClient: storageClient,
networkClient: networkClient
}, callback, logger, self.cli);
},
listVMs: function(options, callback, logger) {
var self = this;
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
var vms = [];
if (deployments.length > 0) {
for (var i = 0; i < deployments.length; i++) {
var roles = deployments[i].deploy.roles;
if (roles) {
for (var j = 0; j < roles.length; j++) {
if (roles[j].roleType === 'PersistentVMRole') {
var vm = createVMView(roles[j], deployments[i], logger);
if (vm !== null) {
vms.push(vm);
}
}
}
}
}
}
self.cli.interaction.formatOutput(vms, function(outputData) {
if (outputData.length === 0) {
logger.info($('No VMs found'));
} else {
logger.table(outputData, function(row, item) {
row.cell($('Name'), item.VMName);
row.cell($('Status'), item.InstanceStatus);
row.cell($('Location'), item.Location ? item.Location : item.AffinityGroup);
row.cell($('DNS Name'), item.DNSName);
row.cell($('IP Address'), item.IPAddress);
});
}
});
return callback();
}
});
},
showVM: function(name, options, callback, logger) {
var self = this;
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
var vms = [];
for (var i = 0; i < deployments.length; i++) {
var roles = deployments[i].deploy.roles;
if (roles) {
for (var j = 0; j < roles.length; j++) {
if (roles[j].roleType === 'PersistentVMRole' &&
roles[j].roleName === name) {
var vm = createVMView(roles[j], deployments[i], logger);
if (vm !== null) {
vms.push(vm);
}
}
}
}
}
// got vms, show detailed info about it
if (vms.length > 0) {
var vmOut = vms.length === 1 ? vms[0] : vms;
if (logger.format().json) {
logger.json(vmOut);
} else {
utils.logLineFormat(vmOut, logger.data);
}
} else {
logger.warn($('No VMs found'));
}
return callback();
}
});
},
setVM: function(vmName, options, callback, logger) {
var self = this;
// get list of vms
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
}
// find the vm we're interested in
var result = getVMDeployment(deployments, vmName);
if (result.error) {
return callback(result.error);
}
var role = _.find(result.deployment.deploy.roles, function(r) {
return utils.ignoreCaseEquals(r.roleName, vmName);
});
if (role === null) {
logger.warn($('No VMs found'));
return;
}
// set bootDiagnosticsEnabled
if (options.bootDiagnosticsEnabled === true || options.bootDiagnosticsEnabled === 'true') {
options.bootDiagnosticsEnabled = true;
}
else if (options.bootDiagnosticsEnabled === false || options.bootDiagnosticsEnabled === 'false') {
options.bootDiagnosticsEnabled = false;
}
else {
options.bootDiagnosticsEnabled = null;
}
// update settings
updateDebugSettings(role, options);
async.series([
function configureExtension(cb) {
// update the vm
var progress = self.cli.interaction.progress('Updating VM');
var computeManagementClient = self.createComputeManagementClient(options);
computeManagementClient.virtualMachines.update(
result.deployment.svc,
result.deployment.deploy.name,
vmName, role,
function(error) {
progress.end();
return cb(error);
});
}
], function(err) {
return callback(err);
});
});
},
deleteVM: function(vmName, options, callback, logger) {
var self = this;
var computeManagementClient = self.createComputeManagementClient();
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
options.dnsPrefix = options.dnsName;
var found = null;
var role = null;
for (var i = 0; i < deployments.length; i++) {
var roles = deployments[i].deploy.roles;
if (roles) {
for (var j = 0; j < roles.length; j++) {
if (roles[j].roleType === 'PersistentVMRole' &&
utils.ignoreCaseEquals(roles[j].roleName, vmName)) {
if (found) {
// found duplicates, emit error
return callback(new Error($('VM name is not unique')));
}
found = deployments[i];
role = roles[j];
}
}
}
}
// got unique vm, delete it
if (found) {
var deleteVMInternal = function() {
var progress = self.cli.interaction.progress($('Deleting VM'));
deleteRoleOrDeployment(computeManagementClient, found.svc, found.deploy, vmName, options, self.cli, callback, progress);
};
// confirm deleting if required
if (options.quiet)
deleteVMInternal();
else self.cli.interaction.confirm(util.format($('Delete the VM %s ? [y/n] '), vmName), function(dummy, shouldDelete) {
if (shouldDelete) {
deleteVMInternal();
} else {
return callback();
}
});
} else {
logger.warn($('No VMs found'));
return callback();
}
}
});
},
startVM: function(name, options, callback, logger) {
var self = this;
var computeManagementClient = self.createComputeManagementClient();
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
var found = null;
for (var i = 0; i < deployments.length; i++) {
var roles = deployments[i].deploy.roles;
if (roles) {
for (var j = 0; j < roles.length; j++) {
if (roles[j].roleType === 'PersistentVMRole' &&
utils.ignoreCaseEquals(roles[j].roleName, name)) {
if (found) {
// found duplicates, emit error
return callback(new Error($('VM name is not unique')));
}
found = deployments[i];
found.roleInstance = getRoleInstance(roles[j].roleName, deployments[i].deploy);
}
}
}
}
// got unique vm, start it
if (found) {
var progress = self.cli.interaction.progress($('Starting VM'));
computeManagementClient.virtualMachines.start(found.svc, found.deploy.name,
found.roleInstance.instanceName,
function(error) {
progress.end();
return callback(error);
});
} else {
logger.warn($('No VMs found'));
return callback();
}
}
});
},
restartVM: function(name, options, callback, logger) {
var self = this;
var computeManagementClient = self.createComputeManagementClient();
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
var found = null;
for (var i = 0; i < deployments.length; i++) {
var roles = deployments[i].deploy.roles;
if (roles) {
for (var j = 0; j < roles.length; j++) {
if (roles[j].roleType === 'PersistentVMRole' &&
utils.ignoreCaseEquals(roles[j].roleName, name)) {
if (found) {
// found duplicates, emit error
return callback(new Error($('VM name is not unique')));
}
found = deployments[i];
found.roleInstance = getRoleInstance(roles[j].roleName, deployments[i].deploy);
}
}
}
}
// got unique vm, restart it
if (found) {
var progress = self.cli.interaction.progress($('Restarting VM'));
computeManagementClient.virtualMachines.restart(found.svc, found.deploy.name,
found.roleInstance.instanceName,
function(error) {
progress.end();
return callback(error);
});
} else {
logger.warn($('No VMs found'));
return callback();
}
}
});
},
shutdownVM: function(name, options, callback, logger) {
var self = this;
var computeManagementClient = self.createComputeManagementClient();
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
var found = null;
for (var i = 0; i < deployments.length; i++) {
var roles = deployments[i].deploy.roles;
if (roles) {
for (var j = 0; j < roles.length; j++) {
if (roles[j].roleType === 'PersistentVMRole' &&
utils.ignoreCaseEquals(roles[j].roleName, name)) {
if (found) {
// found duplicates, emit error
return callback(new Error($('VM name is not unique')));
}
found = deployments[i];
found.roleInstance = getRoleInstance(roles[j].roleName, deployments[i].deploy);
}
}
}
}
// got unique vm, shutting down it
if (found) {
var parameters = {
postShutdownAction: 'StoppedDeallocated'
};
// if --stay-provisioned argument is provided shutdown vm to "Stopped" state
if (options.stayProvisioned) {
parameters.postShutdownAction = 'Stopped';
}
var progress = self.cli.interaction.progress($('Shutting down VM'));
computeManagementClient.virtualMachines.shutdown(found.svc, found.deploy.name,
found.roleInstance.instanceName, parameters,
function(error) {
progress.end();
return callback(error);
});
} else {
logger.warn($('No VMs found'));
return callback();
}
}
});
},
captureVM: function(vmName, targetImageName, options, callback, logger) {
var self = this;
var vmImageTypes = ['Generalized', 'Specialized'];
var result = validateVMCaptureParams(vmImageTypes, options.osState, options['delete']);
if (result.error) {
return callback(new Error(result.error));
}
var computeManagementClient = self.createComputeManagementClient();
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
var found = null;
for (var i = 0; i < deployments.length; i++) {
var roles = deployments[i].deploy.roles;
if (roles) {
for (var j = 0; j < roles.length; j++) {
if (roles[j].roleType === 'PersistentVMRole' &&
roles[j].roleName === vmName) {
if (found) {
// found duplicates, emit error
return callback($('VM name is not unique'));
}
found = deployments[i];
found.roleInstance = getRoleInstance(roles[j].roleName, deployments[i].deploy);
}
}
}
}
if (found) {
progress = self.cli.interaction.progress(util.format($('Checking image with name %s exists'), targetImageName));
vmUtils.getImageInfo(computeManagementClient, targetImageName, function(error, response) {
progress.end();
if (!error) {
var image = response.vmImage || response.osImage;
if (image) {
var imageType = 'OS Image';
if (response.vmImage) {
if (response.vmImage.oSDiskConfiguration.oSState === 'Specialized') {
imageType = 'Specialized VM Image';
} else {
imageType = 'Generalized VM Image';
}
return callback(new Error(util.format($('Another image of type "%s" exists with the same name. Image capture is being aborted to avoid duplicates and potential conflicts. Please use another name for the image'), imageType)));
}
}
return captureVMIntern();
} else {
return callback(error);
}
});
var captureVMIntern = function() {
if (!options.osState) {
var osImageCaptureOptions = {
postCaptureAction: 'Delete',
targetImageName: targetImageName,
targetImageLabel: options.label || targetImageName // does not work without label
};
progress = self.cli.interaction.progress($('Capturing VM'));
computeManagementClient.virtualMachines.captureOSImage(found.svc, found.deploy.name, found.roleInstance.instanceName, osImageCaptureOptions, function(error) {
progress.end();
return callback(error);
});
} else {
if (found.roleInstance.instanceStatus === 'ReadyRole') {
logger.warn($('The VM image capture operation has been started while the VM is still running. This may cause data corruption while creating VMs from this image. Please shutdown the VM using the "azure vm shutdown" command before capturing the image'));
}
var vmImageCaptureOptions = {
oSState: result.vmImageType,
vMImageName: targetImageName,
vMImageLabel: options.label || targetImageName // does not work without label
};
var progress = self.cli.interaction.progress($('Capturing VM'));
computeManagementClient.virtualMachines.captureVMImage(found.svc, found.deploy.name, found.roleInstance.instanceName, vmImageCaptureOptions, function(error) {
progress.end();
return callback(error);
});
}
};
} else {
logger.warn($('No VMs found'));
return callback();
}
}
});
},
exportVM: function(vmName, filePath, options, callback, logger) {
var self = this;
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
var found = null;
for (var i = 0; i < deployments.length; i++) {
var roles = deployments[i].deploy.roles;
if (roles) {
for (var j = 0; j < roles.length; j++) {
if (roles[j].roleType === 'PersistentVMRole' &&
roles[j].roleName === vmName) {
if (found) {
// found duplicates, emit error
return callback(new Error($('VM name is not unique')));
}
found = roles[j];
}
}
}
}
// got unique role, export to file
if (found) {
var progress = self.cli.interaction.progress('Exporting the VM');
var prepareForExport = function(role) {
for (var key in role) {
// Remove namespace @ node
if (key === '@' || key === 'OsVersion') {
delete role[key];
} else if (key === 'dataVirtualHardDisks') {
// Remove Links of all DataVirtualHardDisks since
// while importing we need to pass only DiskName
// which will be already linked with a vhd
for (var i = 0; i < role[key].length; i++) {
delete role[key][i].mediaLink;
//IOType is impicitly determined from the media link hence it is not required
//when a vm is created from the exported json file
if (role[key][i].iOType) {
delete role[key][i].iOType;
}
}
} else if (key === 'oSVirtualHardDisk') {
delete role[key].mediaLink;
delete role[key].sourceImageName;
//IOType is impicitly determined from the media link hence it is not required
//when a vm is created from the exported json file
if (role[key].iOType) {
delete role[key].iOType;
}
}
// Remove namespace in inner objects
if (typeof role[key] === 'object') {
prepareForExport(role[key]);
}
}
};
prepareForExport(found);
if (found.dataVirtualHardDisks.length && !found.dataVirtualHardDisks[0].logicalUnitNumber) {
found.dataVirtualHardDisks[0].logicalUnitNumber = '0';
}
progress.end();
var roleAsString = JSON.stringify(found, null, 2);
fs.writeFile(filePath, roleAsString, function(err) {
if (err) {
return callback(err);
} else {
logger.info(util.format($('VM %s exported to %s'), vmName, filePath));
return callback();
}
});
} else {
logger.warn($('No VMs found'));
return callback();
}
}
});
},
/*
* Server does not support changing nic collection, addNic can be used once server start
* support it, (can be used to enable PS Set-AzureNetworkInterfaceConfig equivalent)
*/
addNic: function (vmName, nicName, options, callback) {
var self = this;
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
}
var computeManagementClient = self.createComputeManagementClient();
getVMDeploymentExtended(deployments, vmName, self.cli, computeManagementClient, function (error, vmDeployment) {
if (error) {
return callback(error);
}
var persistentVMRole = vmDeployment.persistentVMRole;
var networkConfiguration = getNetworkConfigSet(persistentVMRole);
if (!networkConfiguration) {
return callback($('Network configuration not found on the VM'));
}
if (!networkConfiguration.networkInterfaces) {
networkConfiguration.networkInterfaces = [];
}
var networkInterface = utils.findFirstCaseIgnore(networkConfiguration.networkInterfaces, { name: nicName });
if (networkInterface) {
return callback(util.format($('NIC with name "%s" already exists'), nicName));
}
networkInterface = {
name: nicName,
iPConfigurations: [
{
subnetName: options.subnetName,
staticVirtualNetworkIPAddress: options.staticIp
}
]
};
networkConfiguration.networkInterfaces.push(networkInterface);
var progress = self.cli.interaction.progress($('Updating network configuration'));
updateDebugSettings(persistentVMRole, options);
computeManagementClient.virtualMachines.update(vmDeployment.deployment.svc, vmDeployment.deployment.deploy.name, vmName, persistentVMRole, function(error) {
progress.end();
return callback(error);
});
});
});
},
listLocations: function(options, callback, logger) {
var self = this;
var managementClient = self.createManagementClient();
var progress = self.cli.interaction.progress($('Getting locations'));
managementClient.locations.list(function(error, response) {
progress.end();
if (error) {
return callback(error);
} else {
var locations = response.locations;
if (locations.length === 0) {
logger.info($('No locations found'));
} else {
self.cli.interaction.formatOutput(locations, function(outputData) {
if (outputData.length === 0) {
logger.info($('No locations'));
} else {
logger.table(outputData, function(row, item) {
row.cell($('Name'), item.name);
});
}
});
}
return callback();
}
});
},
createEP: function(vmName, publicPort, localPort, options, callback, logger) {
var self = this;
var endPointUtil = new EndPointUtil();
var epInput = {};
epInput.publicPort = {
'value': publicPort,
'argName': 'public-port'
};
if (localPort) {
epInput.localPort = {
'value': localPort,
'argName': 'local-port'
};
}
if (options.name) {
epInput.name = {
'value': options.name,
'argName': '--name'
};
}
if (options.protocol) {
epInput.protocol = {
'value': options.protocol,
'argName': '--protocol'
};
}
if (options.loadBalancedSetName) {
epInput.loadBalancedSetName = {
'value': options.loadBalancedSetName,
'argName': '--load-balanced-set-name'
};
}
if (options.probePort) {
epInput.probePort = {
'value': options.probePort,
'argName': '--probe-port'
};
}
if (options.probeProtocol) {
epInput.probeProtocol = {
'value': options.probeProtocol,
'argName': '--probe-protocol'
};
}
if (options.probePath) {
epInput.probePath = {
'value': options.probePath,
'argName': '--probe-path'
};
}
if (options.directServerReturn) {
epInput.directServerReturn = {
'value': options.directServerReturn,
'argName': '--direct-server-return'
};
}
if (options.internalLoadBalancerName) {
epInput.internalLoadBalancerName = {
'value': options.internalLoadBalancerName,
'argName': '--internal-load-balancer-name'
};
}
if (options.loadBalancerDistribution) {
epInput.loadBalancerDistribution = {
'value': options.loadBalancerDistribution,
'argName': '--load-balancer-distribution'
};
}
if (options.idleTimeout) {
epInput.idleTimeout = {
'value': options.idleTimeout,
'argName': '--idle-timeout'
};
}
if (options.probeInterval) {
epInput.probeInterval = {
'value': options.probeInterval,
'argName': '--probe-interval'
};
}
if (options.probeTimeout) {
epInput.probeTimeout = {
'value': options.probeTimeout,
'argName': '--probe-timeout'
};
}
var result = endPointUtil.verifyAndGetEndPointObj(epInput, [], false); // endpoint parameters validation
if (result.error) {
return callback(new Error(result.error));
}
var newEndPoints = [result.endPoint];
var newEndPointsResult = endPointUtil.verifyEndPoints(newEndPoints);
if (newEndPointsResult.error) {
return callback(new Error(newEndPointsResult.error));
}
var computeManagementClient = self.createComputeManagementClient();
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
var result = getVMDeployment(deployments, vmName);
if (result.error) {
return callback(result.error);
} else {
// Get all LB settings defined in this hosted service
var lbsetConfigs = endPointUtil.getAllLBSettings(result.deployment.deploy.roles);
// If any of the new endpoint has lb set name, if same lb settings is
// defined for this hosted service then overwrite user provided lb
// settings with this.
for (var l = 0; l < newEndPoints.length; l++) {
var lbSetName = newEndPoints[l].loadBalancedEndpointSetName;
if (lbSetName) {
lbSetName = lbSetName.toLowerCase();
if (lbSetName in lbsetConfigs) {
if (underscore.contains(lbsetConfigs[lbSetName].VmNames, vmName)) {
return callback(new Error(
util.format($('this VM already has an endpoint with lb set name %s. lb set name should be unique'),
lbSetName)));
}
logger.info(util.format($('cloud service already has an lb set defined with name %s, using this existing lb settings configuration'),
lbSetName));
newEndPoints[l].loadBalancerProbe =
lbsetConfigs[lbSetName].ProbSettings;
newEndPoints[l].enableDirectServerReturn =
lbsetConfigs[lbSetName].enableDirectServerReturn;
}
}
if (newEndPoints[l].loadBalancerName) {
var err = checkInternalLoadBalancerExists(result.deployment.deploy.loadBalancers, newEndPoints[l].loadBalancerName);
if (err) {
return callback(new Error(err));
}
}
}
var progress = self.cli.interaction.progress($('Reading network configuration'));
computeManagementClient.virtualMachines.get(result.deployment.svc, result.deployment.deploy.name, vmName, function(error, response) {
progress.end();
if (error) {
return callback(error);
} else {
var persistentVMRole = response;
var configurationSets = persistentVMRole.configurationSets;
var m = 0;
for (; m < configurationSets.length; m++) {
if (configurationSets[m].configurationSetType === 'NetworkConfiguration') {
break;
}
}
if (!configurationSets[m].inputEndpoints) {
configurationSets[m].inputEndpoints = [];
}
var endpoints = configurationSets[m].inputEndpoints;
var endpointCount = endpoints.length;
for (var n = 0; n < endpointCount; n++) {
var key = endpoints[n].port + ':' + endpoints[n].protocol;
if (key in newEndPointsResult.protocolPorts) {
return callback(new Error(
util.format($('this VM already has a %s load balancer port %s. lb port and protocol together should be unique'),
endpoints[n].protocol, endpoints[n].port)));
}
key = endpoints[n].name.toLowerCase();
if (key in newEndPointsResult.endPointNames) {
return callback(new Error(
util.format($('this VM already has an endpoint with name %s, endpoint name should unique'),
key)));
}
}
configurationSets[m].inputEndpoints = configurationSets[m].inputEndpoints.concat(newEndPoints);
progress = self.cli.interaction.progress($('Updating network configuration'));
updateDebugSettings(persistentVMRole, options);
computeManagementClient.virtualMachines.update(result.deployment.svc, result.deployment.deploy.name, vmName, persistentVMRole, function(error) {
progress.end();
return callback(error);
});
}
});
}
}
});
},
createMultipleEP: function(vmName, endpointsConfig, options, callback, logger) {
var self = this;
var message = 'each endpoint configuration in the endpoints configuration should be of the form \r\n <public-port>:<local-port>:<protocol>:<idle-timeout>:<direct-server-return>:<probe-protocol>:<probe-port>:<probe-path>:<probe-interval>:<probe-timeout>:<load-balanced-set-name>:<internal-load-balancer-name>:<load-balancer-distribution>';
var endpointPropMap = {
0: {
propName: 'publicPort',
argName: 'public-port'
},
1: {
propName: 'localPort',
argName: 'local-port'
},
2: {
propName: 'protocol',
argName: 'protocol'
},
3: {
propName: 'idleTimeout',
argName: 'idle-timeout'
},
4: {
propName: 'directServerReturn',
argName: 'direct-server-return'
},
5: {
propName: 'probeProtocol',
argName: 'probe-protocol'
},
6: {
propName: 'probePort',
argName: 'probe-port'
},
7: {
propName: 'probePath',
argName: 'probe-path'
},
8: {
propName: 'probeInterval',
argName: 'probe-interval'
},
9: {
propName: 'probeTimeout',
argName: 'probe-timeout'
},
10: {
propName: 'loadBalancedSetName',
argName: 'load-balanced-set-name'
},
11: {
propName: 'internalLoadBalancerName',
argName: 'internal-load-balancer-name'
},
12: {
propName: 'loadBalancerDistribution',
argName: 'load-balancer-distribution'
}
};
var newEndPoints = [];
var count = 1;
var endPointUtil = new EndPointUtil();
var endpointsConfigAsList = endpointsConfig.split(',');
endpointsConfigAsList.forEach(function(endpointConfig) {
// skip any empty entries
endpointConfig = endpointConfig.trim();
if (endpointConfig) {
var endpointConfigAsList = endpointConfig.split(':');
if (endpointConfigAsList.length !== Object.keys(endpointPropMap).length) {
return callback(new Error(message));
}
var intputEndpoint = {};
for (var key in endpointPropMap) {
if (endpointPropMap.hasOwnProperty(key)) {
var endpointProperty = (endpointConfigAsList[key]).trim();
if (endpointProperty) {
intputEndpoint[(endpointPropMap[key]).propName] = {
value: endpointProperty,
argName: (endpointPropMap[key]).argName
};
}
}
}
if (!_.isEmpty(intputEndpoint)) {
var result = endPointUtil.verifyAndGetEndPointObj(intputEndpoint, [], false);
if (result.error) {
return callback(new Error(util.format('%s (endpoint %s)', result.error, count)));
}
newEndPoints.push(result.endPoint);
}
}
count++;
});
var newEndPointsResult = endPointUtil.verifyEndPoints(newEndPoints);
if (newEndPointsResult.error) {
return callback(new Error(newEndPointsResult.error));
}
var computeManagementClient = self.createComputeManagementClient();
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
var result = getVMDeployment(deployments, vmName);
if (result.error) {
return callback(result.error);
} else {
// Get all LB settings defined in this hosted service
var lbsetConfigs = endPointUtil.getAllLBSettings(result.deployment.deploy.roles);
// If any of the new endpoint has lb set name, if same lb settings is
// defined for this hosted service then overwrite user provided lb
// settings with this.
for (var l = 0; l < newEndPoints.length; l++) {
var lbSetName = newEndPoints[l].loadBalancedEndpointSetName;
if (lbSetName) {
lbSetName = lbSetName.toLowerCase();
if (lbSetName in lbsetConfigs) {
if (underscore.contains(lbsetConfigs[lbSetName].VmNames, vmName)) {
return callback(new Error(
util.format($('this VM already has an endpoint with load balanced set %s. load balanced set name should be unique'),
lbSetName)));
}
logger.info(util.format($('cloud service already has an load balanced set defined with name %s, using this existing load balanced set configuration'),
lbSetName));
newEndPoints[l].loadBalancerProbe =
lbsetConfigs[lbSetName].ProbSettings;
newEndPoints[l].enableDirectServerReturn =
lbsetConfigs[lbSetName].EnableDirectServerReturn;
}
}
if (newEndPoints[l].loadBalancerName) {
var err = checkInternalLoadBalancerExists(result.deployment.deploy.loadBalancers, newEndPoints[l].loadBalancerName);
if (err) {
return callback(new Error(err));
}
}
}
var progress = self.cli.interaction.progress($('Reading network configuration'));
computeManagementClient.virtualMachines.get(result.deployment.svc, result.deployment.deploy.name, vmName, function(error, response) {
progress.end();
if (error) {
return callback(error);
} else {
var persistentVMRole = response;
var configurationSets = persistentVMRole.configurationSets;
var m = 0;
for (; m < configurationSets.length; m++) {
if (configurationSets[m].configurationSetType === 'NetworkConfiguration') {
break;
}
}
if (!configurationSets[m].inputEndpoints) {
configurationSets[m].inputEndpoints = [];
}
var endpoints = configurationSets[m].inputEndpoints;
var endpointCount = endpoints.length;
for (var n = 0; n < endpointCount; n++) {
var key = endpoints[n].port + ':' + endpoints[n].protocol;
if (key in newEndPointsResult.protocolPorts) {
return callback(new Error(
util.format($('this VM already has a %s load balancer port %s. public port and protocol together should be unique'),
endpoints[n].protocol, endpoints[n].port)));
}
key = endpoints[n].name.toLowerCase();
if (key in newEndPointsResult.endPointNames) {
return callback(new Error(
util.format($('this VM already has an endpoint with name %s, endpoint name should unique'),
key)));
}
}
configurationSets[m].inputEndpoints = configurationSets[m].inputEndpoints.concat(newEndPoints);
progress = self.cli.interaction.progress($('Updating network configuration'));
updateDebugSettings(persistentVMRole, options);
computeManagementClient.virtualMachines.update(result.deployment.svc, result.deployment.deploy.name, vmName, persistentVMRole, function(error) {
progress.end();
return callback(error);
});
}
});
}
}
});
},
listEPs: function(name, options, callback, logger) {
var self = this;
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
var role = null;
for (var i = 0; i < deployments.length; i++) {
var roles = deployments[i].deploy.roles;
if (roles) {
for (var j = 0; j < roles.length; j++) {
if (roles[j].roleType === 'PersistentVMRole' &&
utils.ignoreCaseEquals(roles[j].roleName, name)) {
if (role) {
// found duplicates, emit error
return callback(new Error($('VM name is not unique')));
}
role = roles[j];
}
}
}
}
var endpointName = options.endpointName;
if (role) {
var networkConfigSet = getNetworkConfigSet(role, endpointName);
if (_.isEmpty(networkConfigSet.inputEndpoints)) {
if (logger.format().json) {
logger.json([]);
} else {
logger.warn($('No endpoints found'));
}
return callback();
} else {
logger.table(networkConfigSet.inputEndpoints, function(row, item) {
row.cell('Name', item.name);
row.cell('Protocol', item.protocol);
row.cell('Public Port', item.port);
row.cell('Private Port', item.localPort);
row.cell('Virtual IP', item.virtualIPAddress || '');
row.cell('EnableDirectServerReturn', item.enableDirectServerReturn);
row.cell('Load Balanced', item.loadBalancedEndpointSetName ? 'Yes' : 'No');
});
return callback();
}
} else {
logger.warn($('No VMs found'));
return callback();
}
}
});
},
showStaticIP: function(vmName, options, callback, logger) {
var self = this;
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
var role = null;
for (var i = 0; i < deployments.length; i++) {
var roles = deployments[i].deploy.roles;
if (roles) {
for (var j = 0; j < roles.length; j++) {
if (roles[j].roleType === 'PersistentVMRole' &&
roles[j].roleName === vmName) {
if (role) {
// found duplicates, emit error
return callback(new Error($('VM name is not unique')));
}
role = roles[j];
}
}
}
}
if (role) {
var networkConfigSet = getNetworkConfigSet(role);
var ipAddress = networkConfigSet.staticVirtualNetworkIPAddress;
if (ipAddress) {
var staticIPConfig = {
Network: {
StaticIP: ipAddress
}
};
if (logger.format().json) {
logger.json(staticIPConfig);
} else {
utils.logLineFormat(staticIPConfig, logger.data);
}
} else {
logger.info(util.format($('No static IP address set for VM %s'), vmName));
}
return callback();
} else {
logger.warn($('No VMs found'));
}
}
});
},
setStaticIP: function(vmName, ipAddress, options, callback) {
var self = this;
var progress;
var vnetUtil = new VNetUtil();
var parsedIp = vnetUtil.parseIPv4(ipAddress);
if (parsedIp.error) {
return callback(parsedIp.error);
}
var computeManagementClient = self.createComputeManagementClient(options);
var networkClient = self.createNetworkClient();
self.getDeployments(options, function(error, deployments) {
if (error) {
return callback(error);
} else {
var result = getVMDeployment(deployments, vmName);
if (result.error) {
return callback(result.error);
} else {
var virtualNetworkName = result.deployment.deploy.virtualNetworkName;
if (!virtualNetworkName) {
return callback(new Error($('The VM does not belong to any virtual networks.')));
}
progress = self.cli.interaction.progress($('Looking up virtual network'));
getNetworkInfo(networkClient, virtualNetworkName, function(error, networkInfo) {
progress.end();
if (error) {
return callback(error);
} else {
var subnetResult = getIPAddressSubnet(networkInfo, ipAddress);
if (subnetResult.error) {
return callback(subnetResult.error);
}
if (!subnetResult.subnetName) {
return callback(new Error(util.format($('The static address %s doesn\'t belong to the address space defined by the role\'s subnets.'), ipAddress)));
}
progress = self.cli.interaction.progress($('Reading network configuration'));
computeManagementClient.virtualMachines.get(result.deployment.svc, result.deployment.deploy.name, vmName, function(error, response) {
progress.end();
if (error) {
return callback(error);
} else {
var role = response;
var networkConfigSet = getNetworkConfigSet(role);
networkConfigSet.staticVirtualNetworkIPAddress = ipAddress;
networkConfigSet.subnetNames = [
subnetResult.subnetName
];
progress = self.cli.interaction.progress($('Updating network configuration'));
updateDebugSettings(role, options);
computeManagementClient.virtualMachines.update(result.deployment.svc, result.deployment.deploy.name, vmName, role, function(error) {
progress.end();
return callback(error);
});
}
});
}
});
}
}
});
},
removeStaticIP: function(vmName, options, callback) {
var self = this;
var computeManagementClient = self.createComputeManagementClient(opt