Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #2057 from Azure/release-0.9.8

Integrating from release to master as a part of Release 0.9.8
  • Loading branch information...
commit c176bdcfbfb118bd40f9e3c6413779ecedb8e856 2 parents 7f033d4 + 5f5ea92
@amarzavery amarzavery authored
Showing with 24,675 additions and 15,129 deletions.
  1. +4 −0 .gitignore
  2. +45 −0 ChangeLog.txt
  3. +15 −7 README.md
  4. +1,794 −0 cli.njsproj
  5. +22 −0 cli.sln
  6. +10 −2 lib/cli.js
  7. +1 −1  lib/commands/account._js
  8. +0 −35 lib/commands/arm/armsdk/dns.js
  9. +0 −3,250 lib/commands/arm/armsdk/dnsManagementClient.js
  10. +48 −3 lib/commands/arm/group/group.deployment._js
  11. +5 −12 lib/commands/arm/group/groupUtils._js
  12. +1 −1  lib/commands/arm/network/constants._js
  13. +5 −39 lib/commands/arm/network/dnsRecordSet._js
  14. +55 −56 lib/commands/arm/network/loadBalancer._js
  15. +12 −9 lib/commands/arm/network/network._js
  16. +3 −6 lib/commands/arm/network/nic._js
  17. +23 −0 lib/commands/arm/role/rbacConstants.js
  18. +56 −53 lib/commands/arm/role/role.assignment._js
  19. +135 −36 lib/commands/arm/role/role.definition._js
  20. +4 −18 lib/commands/arm/role/roleAssignments._js
  21. +172 −0 lib/commands/arm/role/roleUtils._js
  22. +47 −250 lib/commands/storage/storage.blob._js
  23. +438 −33 lib/commands/storage/storage.file._js
  24. +1 −5 lib/commands/storage/storage.queue._js
  25. +223 −24 lib/commands/storage/storage.service._js
  26. +1 −5 lib/commands/storage/storage.table._js
  27. +1 −1  lib/locales/en-us.json
  28. +12,899 −9,311 lib/plugins.arm.json
  29. +4,837 −536 lib/plugins.asm.json
  30. +1 −4 lib/util/authentication/adalAuth.js
  31. +1 −1  lib/util/endpointUtil.js
  32. +19 −11 lib/util/extendedcommand.js
  33. +4 −2 lib/util/logging.js
  34. +115 −0 lib/util/sillyTransport.js
  35. +574 −36 lib/util/storage.util._js
  36. +1 −1  lib/util/utils.js
  37. +7 −0 lib/util/validation.js
  38. +2 −2 lib/util/vnet.util._js
  39. +8 −12 package.json
  40. +62 −4 test/commands/arm/group/arm.group.deployment-tests.js
  41. +38 −40 .../commands/arm/network/{arm.network.dns-record-set-tests.js → arm.network.dns-zone-record-set-tests.js}
  42. +26 −26 test/commands/arm/network/{arm.network.dnszone-tests.js → arm.network.dns-zone-tests.js}
  43. +126 −6 test/commands/arm/role/arm.role-tests.js
  44. +246 −64 test/commands/cli.storage.blob-tests.js
  45. +463 −4 test/commands/cli.storage.file-tests.js
  46. +28 −22 test/commands/cli.storage.queue-tests.js
  47. +107 −0 test/commands/cli.storage.service-tests.js
  48. +28 −22 test/commands/cli.storage.table-tests.js
  49. +10 −0 test/data/CustomRoleDefValid.json
  50. +10 −0 test/data/CustomRoleDefValidForUpdate.json
  51. +2 −2 test/data/arm-deployment-parameters.json
  52. +19 −0 test/data/arm-deployment-parametersv2.json
  53. +13 −7 test/data/arm-deployment-template.json
  54. +2 −2 test/data/startersite-parameters.json
  55. +2 −0  test/framework/cli-executor.js
  56. +5 −0 test/framework/test-logger.js
  57. +169 −100 ...ent-tests/arm_deployment_create_should_all_work_with_a_gallery_template_and_a_string_for_parameters.nock.js
  58. +176 −333 test/recordings/arm-cli-deployment-tests/arm_deployment_create_should_all_work_with_a_local_file.nock.js
  59. +375 −0 .../arm-cli-deployment-tests/arm_deployment_create_should_all_work_with_a_local_file_and_v2_parameters.nock.js
  60. +134 −83 ...ordings/arm-cli-deployment-tests/arm_deployment_create_should_all_work_with_a_string_for_parameters.nock.js
  61. +90 −57 ...yment-tests/arm_deployment_create_should_fail_when_a_parameter_is_missing_for_a_deployment_template.nock.js
  62. +67 −35 ...i-deployment-tests/arm_deployment_create_should_fail_when_an_incorrect_gallery_template_is_provided.nock.js
  63. +40 −59 ...t-tests/arm_deployment_create_should_fail_when_both_gallery_template_and_file_template_are_provided.nock.js
  64. +79 −95 test/recordings/arm-cli-deployment-tests/arm_deployment_create_should_work_with_a_remote_file.nock.js
  65. +257 −0 test/recordings/arm-cli-deployment-tests/arm_deployment_delete_should_work_properly.nock.js
  66. +86 −86 test/recordings/arm-cli-deployment-tests/arm_deployment_list_and_show_should_work_properly.nock.js
  67. +153 −117 ...hould_fail_when_the_deployment_name_is_not_provided_and_more_than_1_deployment_is_currently_running.nock.js
  68. +151 −83 ..._running_deployment_when_deployment_name_is_not_provided_and_only_1_deployment_is_currently_running.nock.js
  69. +76 −76 test/recordings/arm-cli-deployment-tests/arm_deployment_stop_should_work.nock.js
  70. +23 −22 ...es-tests/arm_group_template_download_should_create_directory_to_download_to_and_download_file_there.nock.js
  71. +23 −22 ...up-templates-tests/arm_group_template_download_should_download_template_file_using_name_of_template.nock.js
Sorry, we could not display the entire diff because it was too big.
View
4 .gitignore
@@ -2,6 +2,7 @@ projects/*
targets/*
# Visual Studio #
+.settings/
/app.js
/xPlat.sln
*.suo
@@ -13,6 +14,9 @@ targets/*
*.vspx
*.njsperf
+# Visual Studio Code
+.settings/
+
# Node #
node_modules/
npm-debug.log
View
45 ChangeLog.txt
@@ -1,3 +1,47 @@
+2015.08.19 Version 0.9.8
+* Storage
+ * Update azure-storage to 0.5.0 which supports Azure storage service version 2015-02-21
+ * Support append blob
+ * Supports share quota and share usage
+ * New commands for shared access signatures for shares and files
+ * azure storage share sas create [options] [share] [permissions] [expiry]
+ * azure storage file sas create [options] [share] [path] [permissions] [expiry]
+ * New commands for share ACL
+ * azure storage share policy create [options] [share] [name]
+ * azure storage share policy show [options] [share] [name]
+ * azure storage share policy list [options] [share]
+ * azure storage share policy set [options] [share] [name]
+ * azure storage share policy delete [options] [share] [name]
+ * New commands for file async copy
+ * azure storage file copy start [options] [sourceUri] [destShare]
+ * azure storage file copy show [options] [share] [path]
+ * azure storage file copy stop [options] [share] [path] [copyid]
+ * New commands for CORS (Cross-Origin Resource Sharing)
+ * azure storage cors set [options]
+ * azure storage cors show [options]
+ * azure storage cors delete [options]
+* ARM
+ * Display Outputs section from a template when submitting new deployments
+ * group delete command will now block until the resource group is deleted
+ * Support for submitting deployments with v2 version of template parameters
+ * "azure-arm-resource" package is updated to version 0.10.2
+ * Added delete deployment command
+* Authorization
+ * Role test fixes and authorization package updated to version 0.10.2
+ * Added support to display custom roles in role list command
+ * Added support to create and set role definitions with custom role
+* Network
+ * Fixed CIDR validation issues
+ * Added support for 'None' next hop type in ARM RouteTable Route
+ * Fixed the inability to add a nic in address-pool issue #2013
+* General command improvement
+ * Fixed service principal login issue on Mac #1958
+ * Upgraded adal-node to 0.1.15 to fix '&' in the password issue #1918
+ * Documentation updates for using Chinal Cloud fix issue #1995
+ * Fixed issues #1894, #1911, #1923
+ * Upgraded request library dependency to version 2.52.0
+ * Added default Visual Studio nodejs project for xplat cli
+
2015.08.05 Version 0.9.7
* General command improvement
* Fix the broken "help" command
@@ -18,6 +62,7 @@
* Network commands
* Route Tables
* NIC
+
2015.07.20 Version 0.9.6
* ASM
* Network
View
22 README.md
@@ -155,6 +155,13 @@ azure account import <file location>
azure site create --location "West US" mywebsite
```
+### azure cli with China Cloud
+```bash
+# This will log you into the China Cloud environment.
+# You can use same set of commands to manage your service/applications
+azure login -u <your organizational ID email address> -e AzureChinaCloud
+```
+
### azure cli on Ubuntu
If you want to run xplat cli on Ubuntu, then you should install **nodejs-legacy** instead of **nodejs**. For more information please check the following links:
- [why there is a problem with nodejs installation on ubuntu](http://stackoverflow.com/questions/14914715/express-js-no-such-file-or-directory/14914716#14914716)
@@ -200,19 +207,20 @@ After the VM is created. It can be used as a Docker host with the `-H` option or
Note: To run docker commands on windows make sure ssl agent is installed.
-## Setting up Fiddler for CLI
+## Error Diagnostic
+
+### use the -vv option to see the actual REST requests on the console.
+```bash
+azure site create --location "West US" mytestsite -vv
+```
-You need to set the following environment variables to capture the HTTP traffic generated from the execution of xplat cli commands
+### Use web debugging proxy
+Say, use 'Fiddler', setup the following environment variables before execute commands.
```bash
set NODE_TLS_REJECT_UNAUTHORIZED=0
set HTTPS_PROXY=http://127.0.0.1:8888
```
-## Want to know the underlying HTTP traffic when you execute the command
-You can use the -vv option to see the actual REST requests on the console.
-```bash
-azure site create --location "West US" mytestsite -vv
-```
## Running Tests
View
1,794 cli.njsproj
1,794 additions, 0 deletions not shown
View
22 cli.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.31101.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "cli", "cli.njsproj", "{E6309B69-D527-408B-8835-86367F414DBA}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E6309B69-D527-408B-8835-86367F414DBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E6309B69-D527-408B-8835-86367F414DBA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E6309B69-D527-408B-8835-86367F414DBA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E6309B69-D527-408B-8835-86367F414DBA}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
View
12 lib/cli.js
@@ -132,16 +132,23 @@ _.extend(AzureCli.prototype, {
return path.join(utilsCore.azureDir(), 'azure.err');
},
+ getSillyErrorFile: function () {
+ return path.join(utilsCore.azureDir(), 'azure.details.err');
+ },
+
recordError: function (err) {
- if (err && err.stack) {
+ if (err) {
var errorFile = this.getErrorFile();
try {
- fs.writeFileSync(errorFile, (new Date()) + ':\n' +
+ var writeFileFunction = process.env.AZURE_CLI_APPEND_LOGS ? fs.appendFileSync : fs.writeFileSync;
+ writeFileFunction(errorFile, (new Date()) + ':\n' +
util.inspect(err) + '\n' + err.stack + '\n');
(log.format().json ? log.error : log.info)('Error information has been recorded to ' + errorFile);
} catch (err2) {
log.warn('Cannot save error information :' + util.inspect(err2));
}
+
+ log.default.transports.silly.writeToFile(this.getSillyErrorFile(), process.env.AZURE_CLI_APPEND_LOGS);
}
},
@@ -569,6 +576,7 @@ _.extend(AzureCli.prototype, {
var args = name.split(/ +/);
var cmd = new AzureCli(args.shift(), this);
cmd.option('-v, --verbose', 'use verbose output');
+ cmd.option('-vv', 'more verbose with debug output');
cmd.option('--json', 'use json output');
var caller = callerId.getData();
View
2  lib/commands/account._js
@@ -120,7 +120,7 @@ exports.init = function (cli) {
if(!options.subscription && !options.environment) {
clearAll = true;
- var shouldClear = options.quiet || cli.interaction.confirm($('This will clear all account information. Are you sure? '), _);
+ var shouldClear = options.quiet || cli.interaction.confirm($('This will clear all account information. Are you sure? [y/n] '), _);
if (!shouldClear) {
return;
}
View
35 lib/commands/arm/armsdk/dns.js
@@ -1,35 +0,0 @@
-//
-// 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 exports = module.exports;
-
-var DnsManagementClient = require('./dnsManagementClient');
-exports.DnsManagementClient = DnsManagementClient;
-
-/**
- * Creates a new {@link DnsManagementClient} object.
- *
- * NOTE: These APIs are still in development and should not be used.
- *
- * @param {string} [credentials.subscriptionId] The subscription identifier.
- * @param {string} [credentials.token] The access token.
- * @param {string} [baseUri] The base uri.
- * @param {array} [filters] Optional array of service filters
- * @return {DnsManagementClient} A new DnsManagementClient object.
- */
-exports.createDnsManagementClient = function (credentials, baseUri, filters) {
- return new exports.DnsManagementClient.DnsManagementClient(credentials, baseUri, filters);
-};
View
3,250 lib/commands/arm/armsdk/dnsManagementClient.js
0 additions, 3,250 deletions not shown
View
51 lib/commands/arm/group/group.deployment._js
@@ -201,6 +201,41 @@ exports.init = function (cli) {
}
}
});
+
+ deployment.command('delete [resource-group] [name]')
+ .usage('[options] <resource-group> <deployment-name>')
+ .description($('Deletes a deployment'))
+ .option('-g --resource-group <resourceGroup>', $('the name of the resource group.'))
+ .option('-n --name <name>', $('the name of the deployment.'))
+ .option('-q, --quiet', $('quiet mode (do not ask for delete confirmation)'))
+ .option('--subscription <subscription>', $('subscription containing the deployment to display (optional)'))
+ .execute(function (resourceGroup, name, options, _) {
+ if (!resourceGroup) {
+ return cli.missingArgument('resourceGroup');
+ }
+ if (!name) {
+ return cli.missingArgument('name');
+ }
+ if (!options.quiet && !cli.interaction.confirm(util.format($('Delete deployment %s? [y/n] '), name), _)) {
+ return;
+ }
+ var subscription = profile.current.getSubscription(options.subscription);
+ var client = utils.createResourceClient(subscription);
+ try {
+ client.deployments.checkExistence(resourceGroup, name, _);
+ }
+ catch(err) {
+ throw new Error($('The deployment does not exist.'));
+ }
+
+ var progress = cli.interaction.progress($('Deleting deployment'));
+ try{
+ client.deployments.deleteMethod(resourceGroup, name, _);
+ }
+ finally {
+ progress.end();
+ }
+ });
};
function retrieveDeployments(client, resourceGroup, state, _) {
@@ -232,10 +267,20 @@ function displayDeployment(deployment, resourceGroup, showDetail, log) {
log.data($('TemplateLink :'), deployment.properties.templateLink.uri);
log.data($('ContentVersion :'), deployment.properties.templateLink.contentVersion);
}
- log.table(deployment.properties.parameters, function (row, item) {
+ if (deployment.properties.parameters && Object.keys(deployment.properties.parameters).length > 0) {
+ log.table(deployment.properties.parameters, function (row, item) {
+ row.cell($('Name'), item);
+ row.cell($('Type'), deployment.properties.parameters[item].type);
+ row.cell($('Value'), deployment.properties.parameters[item].value);
+ });
+ }
+ }
+ if (deployment.properties.outputs && Object.keys(deployment.properties.outputs).length > 0) {
+ log.data($('Outputs :'));
+ log.table(deployment.properties.outputs, function (row, item) {
row.cell($('Name'), item);
- row.cell($('Type'), deployment.properties.parameters[item].type);
- row.cell($('Value'), deployment.properties.parameters[item].value);
+ row.cell($('Type'), deployment.properties.outputs[item].type);
+ row.cell($('Value'), deployment.properties.outputs[item].value);
});
}
}
View
17 lib/commands/arm/group/groupUtils._js
@@ -81,24 +81,13 @@ exports.createDeployment = function (cli, resourceGroup, name, options, _) {
var result = cli.interaction.withProgress($('Creating a deployment'),
function (log, _) {
- var validationResponse = client.deployments.validate(resourceGroup, name, templateParameters, _);
+ client.deployments.validate(resourceGroup, name, templateParameters, _);
var createResponse = client.deployments.createOrUpdate(resourceGroup, name, templateParameters, _);
- createResponse.requiredProviders = getTemplateProviders(validationResponse);
return createResponse;
}, _);
cli.output.info(util.format($('Created template deployment "%s"'), name));
- cli.interaction.withProgress($('Registering providers'),
- function (log, _) {
- for (var i = 0; i < result.requiredProviders.length; i++) {
- var namespace = result.requiredProviders[i];
- log.info(util.format($('Registering provider %s'), namespace));
- subscription.registerArmProvider(namespace, false, _);
- }
- },
- _);
-
return result.deployment;
};
@@ -263,6 +252,10 @@ function createDeploymentParameters(cli, subscription, resourceGroup, options, _
if (options.parametersFile) {
var jsonFile = fs.readFileSync(options.parametersFile, 'utf8');
deploymentParameters = JSON.parse(utils.stripBOM(jsonFile));
+ // Handle v2 version of parameters file that has $schema
+ if (deploymentParameters.parameters) {
+ deploymentParameters = deploymentParameters.parameters;
+ }
} else if (options.parameters) {
deploymentParameters = JSON.parse(options.parameters);
} else {
View
2  lib/commands/arm/network/constants._js
@@ -61,7 +61,7 @@ module.exports = {
vnetGatewaySizes: ['G1', 'G2', 'G3'],
route: {
- nextHopType: ['VirtualAppliance', 'VirtualNetworkGateway', 'VNETLocal', 'Internet', 'Null']
+ nextHopType: ['VirtualAppliance', 'VirtualNetworkGateway', 'VNETLocal', 'Internet', 'None']
},
toRange: function (array) {
View
44 lib/commands/arm/network/dnsRecordSet._js
@@ -126,8 +126,8 @@ __.extend(DnsRecordSet.prototype, {
self.output.table(outputData, function (row, recordSet) {
row.cell($('Name'), recordSet.name);
row.cell($('TTL'), recordSet.properties.ttl);
- row.cell($('Type'), self._detectType(recordSet.type));
- row.cell($('Tags'), tagUtils.getTagsInfo(recordSet.tags));
+ row.cell($('Type'), self._detectType(recordSet.id));
+ row.cell($('Tags'), tagUtils.getTagsInfo(recordSet.tags) || '');
});
}
});
@@ -319,43 +319,9 @@ __.extend(DnsRecordSet.prototype, {
return type;
},
- _detectType: function (fullTypeName) {
- var type;
- switch (fullTypeName) {
- case 'Microsoft.Network/dnszones' :
- case 'Microsoft.Network/dnszones/NS' :
- type = 'NS';
- break;
- case 'Microsoft.Network/dnszones/A' :
- type = 'A';
- break;
- case 'Microsoft.Network/dnszones/AAAA' :
- type = 'AAAA';
- break;
- case 'Microsoft.Network/dnszones/CNAME' :
- type = 'CNAME';
- break;
- case 'Microsoft.Network/dnszones/MX' :
- type = 'MX';
- break;
- case 'Microsoft.Network/dnszones/SRV' :
- type = 'SRV';
- break;
- case 'Microsoft.Network/dnszones/TXT' :
- type = 'TXT';
- break;
- case 'Microsoft.Network/dnszones/SOA' :
- type = 'SOA';
- break;
- case 'Microsoft.Network/dnszones/PTR' :
- type = 'PTR';
- break;
- default :
- type = 'UNKNOWN';
- break;
- }
-
- return type;
+ _detectType: function (id) {
+ var resourceInfo = resourceUtils.getResourceInformation(id);
+ return resourceInfo.resourceType.split('/')[2];
},
_deleteRecordsIfEmpty: function (recordSet) {
View
111 lib/commands/arm/network/loadBalancer._js
@@ -33,7 +33,7 @@ function LoadBalancer(cli, networkResourceProviderClient) {
}
__.extend(LoadBalancer.prototype, {
- create: function(resourceGroupName, lbName, location, options, _) {
+ create: function (resourceGroupName, lbName, location, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
if (lb) {
@@ -57,7 +57,7 @@ __.extend(LoadBalancer.prototype, {
self.show(resourceGroupName, lbName, options, _);
},
- list: function(resourceGroupName, _) {
+ list: function (resourceGroupName, _) {
var self = this;
var progress = self.interaction.progress($('Getting the load balancers'));
var lbs = null;
@@ -67,11 +67,11 @@ __.extend(LoadBalancer.prototype, {
progress.end();
}
- self.interaction.formatOutput(lbs.loadBalancers, function(outputData) {
+ self.interaction.formatOutput(lbs.loadBalancers, function (outputData) {
if (outputData.length === 0) {
self.output.warn($('No load balancers found'));
} else {
- self.output.table(outputData, function(row, lb) {
+ self.output.table(outputData, function (row, lb) {
row.cell($('Name'), lb.name);
row.cell($('Location'), lb.location);
});
@@ -79,7 +79,7 @@ __.extend(LoadBalancer.prototype, {
});
},
- show: function(resourceGroupName, lbName, options, _) {
+ show: function (resourceGroupName, lbName, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
@@ -101,7 +101,7 @@ __.extend(LoadBalancer.prototype, {
}
}
- self.interaction.formatOutput(lb.loadBalancer, function(lb) {
+ self.interaction.formatOutput(lb.loadBalancer, function (lb) {
lbShowUtil.show(lb, self.output);
});
@@ -115,7 +115,7 @@ __.extend(LoadBalancer.prototype, {
}
},
- get: function(resourceGroupName, lbName, _, message) {
+ get: function (resourceGroupName, lbName, _, message) {
var self = this;
message = message || util.format($('Looking up the load balancer "%s"'), lbName);
var progress = self.interaction.progress(message);
@@ -132,7 +132,7 @@ __.extend(LoadBalancer.prototype, {
}
},
- delete: function(resourceGroupName, lbName, options, _) {
+ delete: function (resourceGroupName, lbName, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
if (!lb) {
@@ -151,7 +151,7 @@ __.extend(LoadBalancer.prototype, {
}
},
- update: function(resourceGroupName, lbName, lbProfile, _) {
+ update: function (resourceGroupName, lbName, lbProfile, _) {
var self = this;
var progress = self.interaction.progress(util.format($('Updating load balancer "%s"'), lbName));
try {
@@ -165,7 +165,7 @@ __.extend(LoadBalancer.prototype, {
* Commands to manage Probes
*/
- createProbe: function(resourceGroupName, lbName, probeName, options, _) {
+ createProbe: function (resourceGroupName, lbName, probeName, options, _) {
var self = this;
var probeProfile = self._parseProbe(probeName, options, true);
var lb = self.get(resourceGroupName, lbName, _);
@@ -184,7 +184,7 @@ __.extend(LoadBalancer.prototype, {
}
},
- setProbe: function(resourceGroupName, lbName, probeName, options, _) {
+ setProbe: function (resourceGroupName, lbName, probeName, options, _) {
var self = this;
var probeProfile = self._parseProbe(probeName, options, false);
var lb = self.get(resourceGroupName, lbName, _);
@@ -213,7 +213,7 @@ __.extend(LoadBalancer.prototype, {
}
},
- listProbes: function(resourceGroupName, lbName, options, _) {
+ listProbes: function (resourceGroupName, lbName, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
if (!lb) {
@@ -222,9 +222,9 @@ __.extend(LoadBalancer.prototype, {
var probes = lb.loadBalancer.probes;
- self.interaction.formatOutput(probes, function(outputData) {
+ self.interaction.formatOutput(probes, function (outputData) {
if (outputData.length !== 0) {
- self.output.table(outputData, function(row, probe) {
+ self.output.table(outputData, function (row, probe) {
row.cell($('Name'), probe.name);
row.cell($('Protocol'), probe.protocol);
row.cell($('Port'), probe.port);
@@ -242,7 +242,7 @@ __.extend(LoadBalancer.prototype, {
});
},
- deleteProbe: function(resourceGroupName, lbName, probeName, options, _) {
+ deleteProbe: function (resourceGroupName, lbName, probeName, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
if (!lb) {
@@ -267,7 +267,7 @@ __.extend(LoadBalancer.prototype, {
* Commands to manage Frontend IP configurations
*/
- createFrontendIP: function(resourceGroupName, lbName, ipConfigName, options, _) {
+ createFrontendIP: function (resourceGroupName, lbName, ipConfigName, options, _) {
var self = this;
var frontendIpConfResult = self._getFrontendIP(resourceGroupName, lbName, ipConfigName, _);
var frontendIpConf = frontendIpConfResult.object;
@@ -294,7 +294,7 @@ __.extend(LoadBalancer.prototype, {
self.showFrontendIP(newFrontendIpConf);
},
- setFrontendIP: function(resourceGroupName, lbName, ipConfigName, options, _) {
+ setFrontendIP: function (resourceGroupName, lbName, ipConfigName, options, _) {
var self = this;
var frontendIpConfResult = self._getFrontendIP(resourceGroupName, lbName, ipConfigName, _);
var frontendIPConf = frontendIpConfResult.object;
@@ -311,7 +311,7 @@ __.extend(LoadBalancer.prototype, {
self.showFrontendIP(newFrontendIpConf);
},
- listFrontendIPs: function(resourceGroupName, lbName, options, _) {
+ listFrontendIPs: function (resourceGroupName, lbName, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
@@ -320,9 +320,9 @@ __.extend(LoadBalancer.prototype, {
}
var ipConfigurations = lb.loadBalancer.frontendIpConfigurations;
- self.interaction.formatOutput(ipConfigurations, function(outputData) {
+ self.interaction.formatOutput(ipConfigurations, function (outputData) {
if (outputData.length !== 0) {
- self.output.table(outputData, function(row, fip) {
+ self.output.table(outputData, function (row, fip) {
row.cell($('Name'), fip.name);
row.cell($('Provisioning state'), fip.provisioningState);
row.cell($('Private IP allocation method'), fip.privateIpAllocationMethod);
@@ -338,14 +338,14 @@ __.extend(LoadBalancer.prototype, {
});
},
- showFrontendIP: function(ipConfig) {
+ showFrontendIP: function (ipConfig) {
var self = this;
- self.interaction.formatOutput(ipConfig, function(ipConfig) {
+ self.interaction.formatOutput(ipConfig, function (ipConfig) {
lbShowUtil.showFrontendIpConfig(ipConfig, self.output);
});
},
- deleteFrontendIP: function(resourceGroupName, lbName, ipConfigName, options, _) {
+ deleteFrontendIP: function (resourceGroupName, lbName, ipConfigName, options, _) {
var self = this;
var frontendIpConfResult = self._getFrontendIP(resourceGroupName, lbName, ipConfigName, _);
var frontendIpConfIndex = frontendIpConfResult.index;
@@ -367,7 +367,7 @@ __.extend(LoadBalancer.prototype, {
* Commands to manage Backend Address Pools
*/
- createBackendAddressPool: function(resourceGroupName, lbName, poolName, options, _) {
+ createBackendAddressPool: function (resourceGroupName, lbName, poolName, options, _) {
var self = this;
var backendAddressPoolObj = self._getBackendAddressPool(resourceGroupName, lbName, poolName, _);
var lb = backendAddressPoolObj.loadBalancer;
@@ -388,7 +388,7 @@ __.extend(LoadBalancer.prototype, {
self.showBackendAddressPool(newBackendAddressPool);
},
- listBackendAddressPools: function(resourceGroupName, lbName, options, _) {
+ listBackendAddressPools: function (resourceGroupName, lbName, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
@@ -397,9 +397,9 @@ __.extend(LoadBalancer.prototype, {
}
var pools = lb.loadBalancer.backendAddressPools;
- self.interaction.formatOutput(pools, function(outputData) {
+ self.interaction.formatOutput(pools, function (outputData) {
if (outputData.length !== 0) {
- self.output.table(outputData, function(row, pool) {
+ self.output.table(outputData, function (row, pool) {
row.cell($('Name'), pool.name);
row.cell($('Provisioning state'), pool.provisioningState);
});
@@ -413,14 +413,14 @@ __.extend(LoadBalancer.prototype, {
});
},
- showBackendAddressPool: function(backendAddressPool) {
+ showBackendAddressPool: function (backendAddressPool) {
var self = this;
- self.interaction.formatOutput(backendAddressPool, function(backendAddressPool) {
+ self.interaction.formatOutput(backendAddressPool, function (backendAddressPool) {
lbShowUtil.showBackendAddressPool(backendAddressPool, self.output);
});
},
- deleteBackendAddressPool: function(resourceGroupName, lbName, poolName, options, _) {
+ deleteBackendAddressPool: function (resourceGroupName, lbName, poolName, options, _) {
var self = this;
var backendAddressPoolObj = self._getBackendAddressPool(resourceGroupName, lbName, poolName, _);
var lb = backendAddressPoolObj.loadBalancer;
@@ -442,7 +442,7 @@ __.extend(LoadBalancer.prototype, {
* Commands to manage load balancing Rules
*/
- createRule: function(resourceGroupName, lbName, ruleName, options, _) {
+ createRule: function (resourceGroupName, lbName, ruleName, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
if (!lb) {
@@ -478,7 +478,7 @@ __.extend(LoadBalancer.prototype, {
self.showRule(newRule);
},
- setRule: function(resourceGroupName, lbName, ruleName, options, _) {
+ setRule: function (resourceGroupName, lbName, ruleName, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
if (!lb) {
@@ -505,7 +505,7 @@ __.extend(LoadBalancer.prototype, {
self.showRule(newRule);
},
- listRules: function(resourceGroupName, lbName, options, _) {
+ listRules: function (resourceGroupName, lbName, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
@@ -514,9 +514,9 @@ __.extend(LoadBalancer.prototype, {
}
var rules = lb.loadBalancer.loadBalancingRules;
- self.interaction.formatOutput(rules, function(outputData) {
+ self.interaction.formatOutput(rules, function (outputData) {
if (outputData.length !== 0) {
- self.output.table(outputData, function(row, rule) {
+ self.output.table(outputData, function (row, rule) {
row.cell($('Name'), rule.name);
row.cell($('Provisioning state'), rule.provisioningState);
row.cell($('Protocol'), rule.protocol);
@@ -537,14 +537,14 @@ __.extend(LoadBalancer.prototype, {
});
},
- showRule: function(rule) {
+ showRule: function (rule) {
var self = this;
- self.interaction.formatOutput(rule, function(rule) {
+ self.interaction.formatOutput(rule, function (rule) {
lbShowUtil.showLBRule(rule, self.output);
});
},
- deleteRule: function(resourceGroupName, lbName, ruleName, options, _) {
+ deleteRule: function (resourceGroupName, lbName, ruleName, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
if (!lb) {
@@ -572,7 +572,7 @@ __.extend(LoadBalancer.prototype, {
* Commands to manage inbound NAT Rules
*/
- createInboundNatRule: function(resourceGroupName, lbName, name, options, _) {
+ createInboundNatRule: function (resourceGroupName, lbName, name, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
if (!lb) {
@@ -604,7 +604,7 @@ __.extend(LoadBalancer.prototype, {
self.showInboundRule(newRule);
},
- setInboundNatRule: function(resourceGroupName, lbName, name, options, _) {
+ setInboundNatRule: function (resourceGroupName, lbName, name, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
if (!lb) {
@@ -629,7 +629,7 @@ __.extend(LoadBalancer.prototype, {
self.showInboundRule(updatedRule);
},
- listInboundNatRules: function(resourceGroupName, lbName, options, _) {
+ listInboundNatRules: function (resourceGroupName, lbName, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
@@ -638,9 +638,9 @@ __.extend(LoadBalancer.prototype, {
}
var rules = lb.loadBalancer.inboundNatRules;
- self.interaction.formatOutput(rules, function(outputData) {
+ self.interaction.formatOutput(rules, function (outputData) {
if (outputData.length !== 0) {
- self.output.table(outputData, function(row, rule) {
+ self.output.table(outputData, function (row, rule) {
row.cell($('Name'), rule.name);
row.cell($('Provisioning state'), rule.provisioningState);
row.cell($('Protocol'), rule.protocol);
@@ -660,14 +660,14 @@ __.extend(LoadBalancer.prototype, {
});
},
- showInboundRule: function(rule) {
+ showInboundRule: function (rule) {
var self = this;
- self.interaction.formatOutput(rule, function(rule) {
+ self.interaction.formatOutput(rule, function (rule) {
lbShowUtil.showInboundRule(rule, self.output);
});
},
- deleteInboundNatRule: function(resourceGroupName, lbName, name, options, _) {
+ deleteInboundNatRule: function (resourceGroupName, lbName, name, options, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
if (!lb) {
@@ -693,7 +693,7 @@ __.extend(LoadBalancer.prototype, {
}
},
- _parseProbe: function(probeName, params, useDefaults) {
+ _parseProbe: function (probeName, params, useDefaults) {
var self = this;
var probeProfile = {
@@ -762,7 +762,7 @@ __.extend(LoadBalancer.prototype, {
return probeProfile;
},
- _parseRule: function(lb, rule, options, useDefaults) {
+ _parseRule: function (lb, rule, options, useDefaults) {
var self = this;
if (options.protocol) {
@@ -906,7 +906,7 @@ __.extend(LoadBalancer.prototype, {
return rule;
},
- _parseInboundNatRule: function(resourceGroupName, lb, inboundRule, options, useDefaults) {
+ _parseInboundNatRule: function (resourceGroupName, lb, inboundRule, options, useDefaults) {
var self = this;
if (options.protocol) {
@@ -975,12 +975,11 @@ __.extend(LoadBalancer.prototype, {
}
} else if (useDefaults) {
if (!inboundRule.frontendIPConfiguration) {
- var frontendIpConfFoundList = lb.frontendIpConfigurations;
- if (!frontendIpConfFoundList) {
- throw new Error(util.format($('Load balancer with name "%s" has no frontend IP config'), lb.name));
+ if (lb.frontendIpConfigurations.length === 0) {
+ throw new Error(util.format($('Load balancer with name "%s" has no frontend IP configurations'), lb.name));
}
inboundRule.frontendIPConfiguration = {
- id: frontendIpConfFoundList[0].id
+ id: lb.frontendIpConfigurations[0].id
};
self.output.verbose($('Setting default inbound rule frontend IP configuration'));
}
@@ -989,7 +988,7 @@ __.extend(LoadBalancer.prototype, {
return inboundRule;
},
- _parseFrontendIP: function(resourceGroupName, frontendIPConfig, options, _) {
+ _parseFrontendIP: function (resourceGroupName, frontendIPConfig, options, _) {
var self = this;
if (options.privateIpAddress && options.publicIpName) {
throw new Error($('Both optional parameters --private-ip-address and --public-ip-name cannot be specified together'));
@@ -1083,7 +1082,7 @@ __.extend(LoadBalancer.prototype, {
return frontendIPConfig;
},
- _getFrontendIP: function(resourceGroupName, lbName, ipConfigName, _) {
+ _getFrontendIP: function (resourceGroupName, lbName, ipConfigName, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
if (!lb) {
@@ -1106,7 +1105,7 @@ __.extend(LoadBalancer.prototype, {
};
},
- _getBackendAddressPool: function(resourceGroupName, lbName, poolName, _) {
+ _getBackendAddressPool: function (resourceGroupName, lbName, poolName, _) {
var self = this;
var lb = self.get(resourceGroupName, lbName, _);
if (!lb) {
View
21 lib/commands/arm/network/network._js
@@ -1214,7 +1214,10 @@ exports.init = function (cli) {
nsg.deleteRule(resourceGroup, nsgName, name, options, _);
});
- var dnsZone = network.category('dns-zone')
+ var dns = network.category('dns')
+ .description($('Commands to manage DNS'));
+
+ var dnsZone = dns.category('zone')
.description($('Commands to manage DNS zone'));
dnsZone.command('create [resource-group] [name]')
@@ -1303,14 +1306,14 @@ exports.init = function (cli) {
dnsZone.delete(resourceGroup, name, options, _);
});
- var dnsRecordSet = network.category('dns-record-set')
+ var dnsRecordSet = dns.category('record-set')
.description($('Commands to manage record sets in DNS zone'));
dnsRecordSet.command('create [resource-group] [dns-zone-name] [name] [type]')
.description($('Create a DNS zone record set'))
.usage('[options] <resource-group> <dns-zone-name> <name> <type>')
.option('-g, --resource-group <resource-group>', $('the name of the resource group'))
- .option('-z, --dns-zone <dns-zone>', $('the name of the DNS zone'))
+ .option('-z, --dns-zone-name <dns-zone-name>', $('the name of the DNS zone'))
.option('-n, --name <name>', $('the relative name of the record set within the DNS zone'))
.option('-y, --type <type>', $('the type of the record set.' +
'\n Valid values are [A, AAAA, CNAME, MX, NS, SOA, SRV, TXT, PTR]'))
@@ -1335,7 +1338,7 @@ exports.init = function (cli) {
.description($('Set a DNS zone record set'))
.usage('[options] <resource-group> <dns-zone-name> <name> <type>')
.option('-g, --resource-group <resource-group>', $('the name of the resource group'))
- .option('-z, --dns-zone <dns-zone>', $('the name of the DNS zone'))
+ .option('-z, --dns-zone-name <dns-zone-name>', $('the name of the DNS zone'))
.option('-n, --name <name>', $('the relative name of the record set within the DNS zone'))
.option('-y, --type <type>', $('the type of the record set.' +
'\n Valid values are [A, AAAA, CNAME, MX, NS, SOA, SRV, TXT, PTR]'))
@@ -1362,7 +1365,7 @@ exports.init = function (cli) {
.description($('Get all record sets in a DNS zone'))
.usage('[options] <resource-group> <dns-zone-name> [type]')
.option('-g, --resource-group <resource-group>', $('the name of the resource group'))
- .option('-z, --dns-zone <dns-zone>', $('the name of the DNS zone'))
+ .option('-z, --dns-zone-name <dns-zone-name>', $('the name of the DNS zone'))
.option('-y, --type <type>', $('the type of the record set.' +
'\n If specified only record sets of this type will be listed.' +
'\n Valid values are [A, AAAA, CNAME, MX, NS, SOA, SRV, TXT, PTR]'))
@@ -1381,7 +1384,7 @@ exports.init = function (cli) {
.description($('Get a record set in a DNS zone'))
.usage('[options] <resource-group> <dns-zone-name> <name> <type>')
.option('-g, --resource-group <resource-group>', $('the name of the resource group'))
- .option('-z, --dns-zone <dns-zone>', $('the name of the DNS zone'))
+ .option('-z, --dns-zone-name <dns-zone-name>', $('the name of the DNS zone'))
.option('-n, --name <name>', $('the relative name of the record set within the DNS zone'))
.option('-y, --type <type>', $('the type of the record set.' +
'\n Valid values are [A, AAAA, CNAME, MX, NS, SOA, SRV, TXT, PTR]'))
@@ -1401,7 +1404,7 @@ exports.init = function (cli) {
.description($('Delete a record set from a DNS zone'))
.usage('[options] <resource-group> <dns-zone-name> <name> <type>')
.option('-g, --resource-group <resource-group>', $('the name of the resource group'))
- .option('-z, --dns-zone <dns-zone>', $('the name of the DNS zone'))
+ .option('-z, --dns-zone-name <dns-zone-name>', $('the name of the DNS zone'))
.option('-n, --name <name>', $('the relative name of the record set within the DNS zone'))
.option('-y, --type <type>', $('the type of the record set.' +
'\n If specified only record sets of this type will be listed.' +
@@ -1423,7 +1426,7 @@ exports.init = function (cli) {
.description($('Add a record in a record set under a DNS zone'))
.usage('[options] <resource-group> <dns-zone-name> <record-set-name> <type>')
.option('-g, --resource-group <resource-group>', $('the name of the resource group'))
- .option('-z, --dns-zone <dns-zone>', $('the name of the DNS zone'))
+ .option('-z, --dns-zone-name <dns-zone-name>', $('the name of the DNS zone'))
.option('-n, --record-set-name <record-set-name>', $('the name of the record set'))
.option('-y, --type <type>', $('the type of the record set.' +
'\n If specified only record sets of this type will be listed.' +
@@ -1473,7 +1476,7 @@ exports.init = function (cli) {
.description($('Delete a record from a record set under a DNS zone'))
.usage('[options] <resource-group> <dns-zone> <record-set-name> <type>')
.option('-g, --resource-group <resource-group>', $('the name of the resource group'))
- .option('-z, --dns-zone <dns-zone>', $('the name of the DNS zone'))
+ .option('-z, --dns-zone-name <dns-zone-name>', $('the name of the DNS zone'))
.option('-n, --record-set-name <record-set-name>', $('the name of the record set'))
.option('-y, --type <type>', $('the type of the record set.' +
'\n If specified only record sets of this type will be listed.' +
View
9 lib/commands/arm/network/nic._js
@@ -28,7 +28,7 @@ var VNetUtil = require('../../../util/vnet.util');
function Nic(cli, serviceClients) {
this.networkResourceProviderClient = serviceClients.networkResourceProviderClient;
this.subnetCrud = new Subnet(cli, serviceClients.networkResourceProviderClient);
- this.loadBalancerCrud = new LoadBalancer(cli, serviceClients);
+ this.loadBalancerCrud = new LoadBalancer(cli, serviceClients.networkResourceProviderClient);
this.nsgCrud = new Nsg(cli, serviceClients.networkResourceProviderClient);
this.publicIpCrud = new PublicIp(cli, serviceClients.networkResourceProviderClient);
this.vnetUtil = new VNetUtil();
@@ -263,8 +263,6 @@ __.extend(Nic.prototype, {
var progress = self.interaction.progress(util.format($('Updating network interface "%s"'), nicName));
try {
self.networkResourceProviderClient.networkInterfaces.createOrUpdate(resourceGroupName, nicName, nicProfile, _);
- } catch (e) {
- throw e;
} finally {
progress.end();
}
@@ -393,10 +391,9 @@ __.extend(Nic.prototype, {
throw new Error(util.format($('A load balancer with name "%s" not found in the resource group "%s'), options.lbName, resourceGroupName));
}
- var inboundNatRule = utils.findFirstCaseIgnore(lb.loadBalancer.loadBalancerInboundNatRules, {name: options.inboundNatRuleName});
-
+ var inboundNatRule = utils.findFirstCaseIgnore(lb.loadBalancer.inboundNatRules, {name: options.inboundNatRuleName});
if (!inboundNatRule) {
- throw new Error(util.format($('An inbound NAT rule with name "%s" not found in the load balancer "%s" resource group "%s"'), options.inboundNatRuleName, options.lbName, resourceGroupName));
+ throw new Error(util.format($('An inbound NAT rule with name "%s" not found in the load balancer "%s"'), options.inboundNatRuleName, options.lbName));
} else {
ruleId = inboundNatRule.id;
}
View
23 lib/commands/arm/role/rbacConstants.js
@@ -0,0 +1,23 @@
+//
+// 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.
+//
+
+exports = module.exports;
+
+var rbacConstants = {
+ CUSTOM_ROLE_TYPE: 'CustomRole'
+};
+
+module.exports = rbacConstants;
View
109 lib/commands/arm/role/role.assignment._js
@@ -46,69 +46,72 @@ exports.init = function (cli) {
.option('--parent <parent>', $('Parent resource of the resource to assign the role to, if there is any.'))
.option('--subscription <subscription>', $('Subscription id or name of where the role assignment will be created.'))
.execute(function (objectId, upn, mail, spn, role, scope, resourceGroup, resourceType, resourceName, options, _) {
- if (!role) {
- return cli.missingArgument('role');
- }
- adUtils.validateParameters({
+ if (!role) {
+ return cli.missingArgument('role');
+ }
+ adUtils.validateParameters({
+ objectId: objectId,
+ upn: upn,
+ mail: mail,
+ spn: spn
+ });
+
+ var subscription = profile.current.getSubscription(options.subscription);
+ var authzClient = rbacClients.getAuthzClient(subscription);
+ var graphClient = adUtils.getADGraphClient(subscription);
+
+ scope = RoleAssignments.buildScopeString({
+ scope: scope,
+ subscriptionId: subscription.id,
+ resourceGroup: resourceGroup,
+ resourceType: resourceType,
+ resourceName: resourceName,
+ parent: options.parent
+ });
+
+ objectId = adUtils.getObjectId(
+ {
objectId: objectId,
upn: upn,
mail: mail,
spn: spn
+ }, graphClient, true, _);
+
+ var matchedRoles;
+ var progress = cli.interaction.progress($('Getting role definition id'));
+ try {
+ matchedRoles = authzClient.roleDefinitions.list(_);
+ matchedRoles = matchedRoles.roleDefinitions.filter(function (r) {
+ return utils.ignoreCaseEquals(r.properties.roleName, role);
});
+ } finally {
+ progress.end();
+ }
+
+ var roleId;
+ if (matchedRoles && matchedRoles.length > 0) {
+ roleId = matchedRoles[0].id;
+ }
+ if (!roleId) {
+ throw new Error(util.format($('Role of \'%s\' does not exist'), role));
+ }
- var subscription = profile.current.getSubscription(options.subscription);
- var authzClient = rbacClients.getAuthzClient(subscription);
- var graphClient = adUtils.getADGraphClient(subscription);
-
- scope = RoleAssignments.buildScopeString({
- scope: scope,
- subscriptionId: subscription.id,
- resourceGroup: resourceGroup,
- resourceType: resourceType,
- resourceName: resourceName,
- parent: options.parent
- });
-
- objectId = adUtils.getObjectId(
- {
- objectId: objectId,
- upn: upn,
- mail: mail,
- spn: spn
- }, graphClient, true, _);
-
- var matchedRoles;
- var progress = cli.interaction.progress($('Getting role definition id'));
- try {
- matchedRoles = authzClient.roleDefinitions.list(_);
- matchedRoles = matchedRoles.roleDefinitions.filter(function (r) {
- return utils.ignoreCaseEquals(r.properties.roleName, role);
- });
- } finally {
- progress.end();
- }
-
- var roleId;
- if (matchedRoles && matchedRoles.length > 0) {
- roleId = matchedRoles[0].id;
- }
- if (!roleId) {
- throw new Error(util.format($('Role of \'%s\' does not exist'), role));
- }
-
- var parameter = {
+ var parameter = {
+ properties: {
principalId: objectId,
roleDefinitionId: roleId,
scope: scope
- };
- var roleAssignmentNameGuid = utils.uuidGen();
- progress = cli.interaction.progress($('Creating role assignment'));
- try {
- authzClient.roleAssignments.create(scope, roleAssignmentNameGuid, parameter, _);
- } finally {
- progress.end();
}
- });
+ };
+
+ var roleAssignmentNameGuid = utils.uuidGen();
+ progress = cli.interaction.progress($('Creating role assignment'));
+ try {
+ authzClient.roleAssignments.create(scope, roleAssignmentNameGuid, parameter, _);
+ } finally {
+ progress.end();
+ }
+ });
roleAssignment.command('list [objectId] [upn] [mail] [spn] [role] [scope] [resource-group] [resource-type] [resource-name]')
.description($('Get role assignment at a given scope'))
View
171 lib/commands/arm/role/role.definition._js
@@ -18,74 +18,173 @@
var permissionsUtils = require('./permissionsUtils');
var profile = require('../../../util/profile');
var utils = require('../../../util/utils');
+var util = require('util');
var rbacClients = require('./rbacClients');
+var roleUtils = require('./roleUtils');
+var rbacConstants = require('./rbacConstants');
var $ = utils.getLocaleString;
exports.init = function (cli) {
var log = cli.output;
-
var role = cli.category('role')
.description($('Commands to manage your Azure roles'));
role.command('list')
+ .option('--custom', $('If given, display only the custom roles instead of all role definitions'))
+ .option('--subscription <subscription>', $('the subscription identifier'))
.description($('Get all available role definitions'))
.execute(function (options, _) {
+ var subscription = profile.current.getSubscription(options.subscription);
+ var client = rbacClients.getAuthzClient(subscription);
+ var progress = cli.interaction.progress($('Listing role definitions'));
+ var result;
+ try {
+ result = client.roleDefinitions.list(_);
+ } finally {
+ progress.end();
+ }
+
+ if (options.custom) {
+ result.roleDefinitions = result.roleDefinitions.filter(function (r) {
+ return utils.ignoreCaseEquals(r.properties.type, rbacConstants.CUSTOM_ROLE_TYPE);
+ });
+ }
+
+ cli.interaction.formatOutput(result.roleDefinitions, function (data) {
+ if (data.length === 0) {
+ log.info($('No role definition defined'));
+ } else {
+ log.table(data, displayARoleDefinition);
+ }
+ });
+ });
+
+ role.command('show [name]')
+ .description($('Get an available role definition'))
+ .option('-n --name <name>', $('the role definition name'))
+ .option('--subscription <subscription>', $('the subscription identifier'))
+ .execute(function(name, options, _) {
+ if (!name) {
+ return cli.missingArgument('name');
+ }
var subscription = profile.current.getSubscription(options.subscription);
var client = rbacClients.getAuthzClient(subscription);
- var progress = cli.interaction.progress($('Listing role definitions'));
+ var progress = cli.interaction.progress($('Getting role definitions'));
var result;
try {
+ //'roleDefinitions.get' only takes guid, so we just do list and find by name ourselves
result = client.roleDefinitions.list(_);
} finally {
progress.end();
}
- cli.interaction.formatOutput(result.roleDefinitions, function (data) {
+ var roles = result.roleDefinitions.filter(function(r) {
+ return utils.ignoreCaseEquals(r.properties.roleName, name);
+ });
+
+ cli.interaction.formatOutput(roles, function(data) {
if (data.length === 0) {
- log.info($('No role definition defined'));
+ log.info($('No role definition found'));
} else {
log.table(data, displayARoleDefinition);
}
});
});
- role.command('show [name]')
- .description($('Get an available role definition'))
- .option('-n --name <name>', $('the role definition name'))
- .execute(function (name, options, _) {
- if (!name) {
- return cli.missingArgument('name');
- }
- var subscription = profile.current.getSubscription(options.subscription);
- var client = rbacClients.getAuthzClient(subscription);
- var progress = cli.interaction.progress($('Getting role definitions'));
- var result;
- try {
- //'roleDefinitions.get' only takes guid, so we just do list and find by name ourselves
- result = client.roleDefinitions.list(_);
- } finally {
- progress.end();
- }
+ role.command('create [inputfile] [roledefinition]')
+ .description($('create a new role definition'))
+ .option('-f --inputfile <inputfile>', $('File name containing a single role definition.'))
+ .option('-r --roledefinition <roledefinition>', $('A JSON-formatted string containing the role definition. For e.g. {"Name": "Test Role","Description": "Test role","Actions": ["Microsoft.Support/*/read"],"Notactions": [],"AssignableScopes": ["/subscriptions/4004a9fd-d58e-48dc-aeb2-4a4aec58606f"]}'))
+ .option('--subscription <subscription>', $('The subscription identifier'))
+ .execute(function(inputfile, roledefinition, options, _) {
+ if (inputfile && roledefinition) {
+ throw new Error($('Either inputfile or roledefinition need to be specified. Not both.'));
+ }
+
+ if (!inputfile && !roledefinition) {
+ throw new Error($('At least one of inputfile or roledefinition need to be specified.'));
+ }
+
+ var roleToCreate = roleUtils.getRoleToCreateOrUpdate(inputfile, roledefinition);
+ var parameters = roleUtils.validateAndConstructCreateParameters(cli, roleToCreate);
+
+ var subscription = profile.current.getSubscription(options.subscription);
+ var authzClient = rbacClients.getAuthzClient(subscription);
+
+ var roleDefinitionIdGuid = parameters.roleDefinition.name;
+ var doneMessage = util.format($('Created role definition %s'), roleDefinitionIdGuid);
+ var roleDef = null;
+ cli.interaction.withProgress(util.format($('Creating role definition "%s"'), roleDefinitionIdGuid),
+ function(log, _) {
+ roleDef = authzClient.roleDefinitions.createOrUpdate(roleDefinitionIdGuid, parameters, _);
+ }, _);
- var roles = result.roleDefinitions.filter(function (r) {
- return utils.ignoreCaseEquals(r.properties.roleName, name);
+ log.info(doneMessage);
+ cli.interaction.formatOutput(roleDef, function(role) {
+ if (role) {
+ roleUtils.showRoleDefinition(role, log);
+ }
+ });
});
- cli.interaction.formatOutput(roles, function (data) {
- if (data.length === 0) {
- log.info($('No role definition found'));
- } else {
- log.table(data, displayARoleDefinition);
+ role.command('set [inputfile] [roledefinition]')
+ .description($('update an existing role definition'))
+ .option('-f --inputfile <inputfile>', $('File name containing a single role definition.'))
+ .option('-r --roledefinition <roledefinition>', $('A JSON-formatted string containing the role definition. For e.g. {"Name": "Test Role","Description": "Test role","Actions": ["Microsoft.Support/*/read"],"Notactions": [],"AssignableScopes": ["/subscriptions/5004a9fd-d58e-48dc-aeb2-4a4aec58606f"]}'))
+ .option('--subscription <subscription>', $('The subscription identifier'))
+ .execute(function(inputfile, roledefinition, options, _) {
+ if (inputfile && roledefinition) {
+ throw new Error($('Either inputfile or roledefinition need to be specified. Not both.'));
+ }
+
+ if (!inputfile && !roledefinition) {
+ throw new Error($('At least one of inputfile or roledefinition need to be specified.'));
}
+
+ var inputRole = roleUtils.getRoleToCreateOrUpdate(inputfile, roledefinition);
+
+ var subscription = profile.current.getSubscription(options.subscription);
+ var authzClient = rbacClients.getAuthzClient(subscription);
+ var progress = cli.interaction.progress($('Getting role definition'));
+ var getResult = null;
+ try {
+ getResult = authzClient.roleDefinitions.getById(inputRole.id, _);
+ } finally {
+ progress.end();
+ }
+
+ if (!getResult) {
+ throw new Error($('Cannot find roledefinition with id: %s', inputRole.id));
+ }
+
+ var parameters = roleUtils.constructRoleDefinitionUpdateParameters(cli, inputRole, getResult);
+ var roleDefinitionIdGuid = parameters.roleDefinition.name;
+ var doneMessage = util.format($('Updated role definition %s'), roleDefinitionIdGuid);
+
+ var roleDef = null;
+ cli.interaction.withProgress(util.format($('Updating role definition "%s"'), roleDefinitionIdGuid),
+ function(log, _) {
+ roleDef = authzClient.roleDefinitions.createOrUpdate(roleDefinitionIdGuid, parameters, _);
+ }, _);
+
+ log.info(doneMessage);
+ cli.interaction.formatOutput(roleDef, function(role) {
+ if (role) {
+ roleUtils.showRoleDefinition(role, log);
+ }
+ });
});
- });
-};
-function displayARoleDefinition(row, role) {
- row.cell($('Name'), role.properties.roleName);
- var permissionDetails = permissionsUtils.getPermissionDetails(role.properties.permissions);
- row.cell($('Actions'), permissionDetails.actions);
- row.cell($('NotActions'), permissionDetails.notActions);
-}
+ function displayARoleDefinition(row, role) {
+ row.cell($('Name'), role.properties.roleName);
+ row.cell($('Id'), role.id);
+ row.cell($('IsCustom'), role.properties.type === rbacConstants.CUSTOM_ROLE_TYPE);
+ row.cell($('Description'), role.properties.description);
+ var permissionDetails = permissionsUtils.getPermissionDetails(role.properties.permissions);
+ row.cell($('Actions'), permissionDetails.actions);
+ row.cell($('NotActions'), permissionDetails.notActions);
+ row.cell($('AssignableScopes'), role.properties.assignableScopes);
+ }
+};
View
22 lib/commands/arm/role/roleAssignments._js
@@ -20,6 +20,7 @@ var underscore = require('underscore');
var adUtils = require('../ad/adUtils');
var resourceUtils = require('../resource/resourceUtils');
var utils = require('../../../util/utils');
+var permissionsUtils = require('./permissionsUtils');
var $ = utils.getLocaleString;
@@ -141,8 +142,9 @@ underscore.extend(RoleAssignments.prototype, {
for (var i = 0; i < roleDefinitions.length; i++) {
var roleDefinition = roleDefinitions[i];
roleDefinitionId = roleDefinition.name; //Note, the 'name' field here really means the 'id'
- rolePermissionActionsList[roleDefinitionId] = self.serializeActionList(roleDefinition.properties.permissions);
- rolePermissionNotActionsList[roleDefinitionId] = self.serializeNotActionList(roleDefinition.properties.permissions);
+ var permissionDetails = permissionsUtils.getPermissionDetails(roleDefinition.properties.permissions);
+ rolePermissionActionsList[roleDefinitionId] = permissionDetails.actions;
+ rolePermissionNotActionsList[roleDefinitionId] = permissionDetails.notActions;
roleNames[roleDefinitionId] = roleDefinition.properties.roleName;
}
@@ -186,22 +188,6 @@ underscore.extend(RoleAssignments.prototype, {
});
return (propertyValues.length > 0);
},
-
- serializeActionList: function (permissions) {
- var actions = [];
- for (var i = 0; i < permissions.length; i++) {
- actions = actions.concat(permissions[i].actions);
- }
- return actions.join();
- },
-
- serializeNotActionList: function (permissions) {
- var notActions = [];
- for (var i = 0; i < permissions.length; i++) {
- notActions = notActions.concat(permissions[i].notActions);
- }
- return notActions.join();
- },
});
RoleAssignments.buildScopeString = function (scopeInfo) {
View
172 lib/commands/arm/role/roleUtils._js
@@ -0,0 +1,172 @@
+/**
+* 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.
+*/
+
+'use strict';
+
+var __ = require('underscore');
+var utils = require('../../../util/utils');
+var permissionsUtils = require('./permissionsUtils');
+var util = require('util');
+var fs = require('fs');
+var rbacConstants = require('./rbacConstants');
+
+var $ = utils.getLocaleString;
+
+function validateRole(role) {
+ if (__.isEmpty(role.name)) {
+ throw new Error($('RoleDefinition Name is invalid'));
+ }
+
+ if (__.isEmpty(role.assignableScopes)) {
+ throw new Error($('RoleDefinition AssignableScopes is invalid'));
+ }
+
+ if (__.isEmpty(role.actions)) {
+ throw new Error($('RoleDefinition Actions is invalid'));
+ }
+}
+
+function toCamelCase(obj) {
+ var key, destKey, value;
+ var camelCasedObj = {};
+ if (obj && typeof obj === 'object')
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ destKey = (key.charAt(0).toLowerCase() + key.substring(1)).toString();
+ value = obj[key];
+ camelCasedObj[destKey] = value;
+ }
+ }
+
+ return camelCasedObj;
+}
+
+exports.showRoleDefinition = function(role, log) {
+ log.data($('Name :'), role.roleDefinition.properties.roleName);
+ log.data($('Id :'), role.roleDefinition.id);
+ log.data($('Description :'), role.roleDefinition.properties.description);
+ var permissionDetails = permissionsUtils.getPermissionDetails(role.roleDefinition.properties.permissions);
+ log.data($('Actions :') + permissionDetails.actions);
+ log.data($('NotActions :') + permissionDetails.notActions);
+ log.data($('AssignableScopes :'), role.roleDefinition.properties.assignableScopes);
+ log.data($('IsCustom :'), role.roleDefinition.properties.type.toLowerCase() === rbacConstants.CUSTOM_ROLE_TYPE.toLowerCase() ? true : false);
+ log.data('');
+};
+
+exports.getRoleToCreateOrUpdate = function(inputfile, roledefinition) {
+ var roleToCreateOrUpdate;
+ if (inputfile) {
+ var exists = fs.existsSync(inputfile);
+
+ if (exists) {
+ var filecontent = fs.readFileSync(inputfile);
+ try {
+ roleToCreateOrUpdate = JSON.parse(filecontent);
+ } catch (e) {
+ throw new Error($('Deserializing the input role definition failed'));
+ }
+ } else {
+ // exists = false
+ throw new Error(util.format($('File %s does not exist'), inputfile));
+ }
+ } else {
+ // no inputfile, JSON string provided
+ try {
+ roleToCreateOrUpdate = JSON.parse(roledefinition);
+ } catch (e) {
+ throw new Error($('Deserializing the input role definition failed'));
+ }
+ }
+
+ return toCamelCase(roleToCreateOrUpdate);
+};
+
+exports.validateAndConstructCreateParameters = function (cli, role) {
+ cli.output.info($('Validating role definition'));
+
+ // Attempts to convert property names to camelCase by lower-casing the first letter of the property
+ // i.e. If user specifies "AssignableScopes" or "assignableScopes" as property-name this will work,
+ // but not if "assignablescopes" is specified
+ var newRole = toCamelCase(role);
+
+ validateRole(newRole);
+
+ var newRoleDefinitionNameGuid = utils.uuidGen();
+
+ var roleProperties = {
+ assignableScopes: newRole.assignableScopes,
+ description: newRole.description,
+ permissions: [
+ {
+ actions: newRole.actions,
+ notActions: newRole.notActions
+ }
+ ],
+ roleName: newRole.name,
+ type: rbacConstants.CUSTOM_ROLE_TYPE
+ };
+
+ var parameters = {
+ roleDefinition: {
+ name: newRoleDefinitionNameGuid,
+ properties: roleProperties
+ }
+ };
+
+ return parameters;
+};
+
+exports.constructRoleDefinitionUpdateParameters = function (cli, inputrole, roleFromService) {
+ // Attempts to convert property names of the (user) input role to camelCase by lower-casing the first letter of the property
+ // i.e. If user specifies "AssignableScopes" or "assignableScopes" as property-name this will work, but not if "assignablescopes" is specified
+ // roleFromService will already have properties camelcased.
+ var inputRoleCamelcased = toCamelCase(inputrole);
+
+ // Merge properties from user input and the GET result from service
+ var roleToUpdateRoleName = (!inputRoleCamelcased.name) ? roleFromService.roleDefinition.properties.roleName : inputRoleCamelcased.name;
+ var roleToUpdateActions = (!inputRoleCamelcased.actions) ? roleFromService.roleDefinition.properties.actions : inputRoleCamelcased.actions;
+ var roleToUpdateNotActions = (!inputRoleCamelcased.notActions) ? roleFromService.roleDefinition.properties.notActions : inputRoleCamelcased.notActions;
+ var roleToUpdateAssignableScopes = (!inputRoleCamelcased.assignableScopes) ? roleFromService.roleDefinition.properties.assignableScopes : inputRoleCamelcased.assignableScopes;
+ var roleToUpdateDescription = (!inputRoleCamelcased.description) ? roleFromService.roleDefinition.properties.description : inputRoleCamelcased.description;
+
+ var roleProperties = {
+ assignableScopes: roleToUpdateAssignableScopes,
+ description: roleToUpdateDescription,
+ permissions: [
+ {
+ actions: roleToUpdateActions,
+ notActions: roleToUpdateNotActions
+ }
+ ],
+ roleName: roleToUpdateRoleName,
+ type: rbacConstants.CUSTOM_ROLE_TYPE
+ };
+
+ // Get the last segment as the roleid(name)
+ var scopes = roleFromService.roleDefinition.id.split('/');
+ var roleDefinitionId = scopes[scopes.length - 1];
+
+ var parameters = {
+ roleDefinition: {
+ id: roleFromService.roleDefinition.id,
+ name: roleDefinitionId,
+ properties: roleProperties
+ }
+ };
+
+ return parameters;
+};
+
+
View
297 lib/commands/storage/storage.blob._js
@@ -14,7 +14,6 @@
// limitations under the License.
//
-var azureCommon = require('azure-common');
var storage = require('azure-storage');
var util = require('util');
var commander = require('commander');
@@ -23,10 +22,7 @@ var path = require('path');
var StorageUtil = require('../../util/storage.util');
var utils = require('../../util/utils');
var validation = require('../../util/validation');
-var blobUtils = require('../../util/blobUtils');
-var splitDestinationUri = blobUtils.splitDestinationUri;
var Wildcard = utils.Wildcard;
-var getStorageSettings = StorageUtil.getStorageServiceSettings;
var performStorageOperation = StorageUtil.performStorageOperation;
var startProgress = StorageUtil.startProgress;
var endProgress = StorageUtil.endProgress;
@@ -203,7 +199,7 @@ exports.init = function(cli) {
.option('-f, --file <file>', $('the local file path'))
.option('--container <container>', $('the storage container name'))
.option('-b, --blob <blobName>', $('the storage blob name'))
- .option('-t, --blobtype <blobtype>', $('the storage blob type(Page, Block)'))
+ .option('-t, --blobtype <blobtype>', util.format($('the storage blob type(%s)'), getAvailableBlobTypes()))
.option('-p, --properties <properties>', $('the storage blob properties for uploaded file. Properties are key=value pairs and separated with semicolon(;). Available properties are contentType, contentEncoding, contentLanguage, cacheControl'))
.option('-m, --metadata <metadata>', $('the storage blob metadata for uploaded file. Metadata are key=value pairs and separated with semicolon(;)'))
.option('--concurrenttaskcount <concurrenttaskcount>', $('the maximum number of concurrent upload requests'))
@@ -229,17 +225,18 @@ exports.init = function(cli) {
copy.command('start [sourceUri] [destContainer]')
.usage('[options] [sourceUri] [destContainer]')
- .description($('Start to copy the specified storage blob which completes asynchronously'))
- .option('--sas-token <sasToken>', $('deprecated. This option is deprecated and will be removed in a future version. Please use \"--source-sas\" instead'))
+ .description($('Start to copy the resource to the specified storage blob which completes asynchronously'))
.option('--source-sas <sourceSas>', $('the shared access signature of the source storage'))
- .option('--source-container <sourceContainer>', $('the source storage container name'))
- .option('--source-blob <sourceBlob>', $('the source storage blob name'))
- .option('--source-uri <sourceUri>', $('the source storage blob absolute uri'))
+ .option('--source-uri <sourceUri>', $('the source storage blob or file absolute uri'))
+ .option('--source-container <sourceContainer>', $('the source storage container name when copies a blob to a blob'))
+ .option('--source-blob <sourceBlob>', $('the source storage blob name when copies a blob to a blob'))
+ .option('--source-share <sourceShare>', $('the source storage share name when copies a file to a blob'))
+ .option('--source-path <sourcePath>', $('the source storage file path when copies a file to a blob'))
.option('--dest-account-name <destAccountName>', $('the destination storage account name'))
.option('--dest-account-key <destAccountKey>', $('the destination storage account key'))
.option('--dest-connection-string <destConnectionString>', $('the destination storage connection string'))
- .option('--dest-container <destContainer>', $('the destination storage container name'))
.option('--dest-sas <destSas>', $('the shared access signature of the destination storage container or blob'))
+ .option('--dest-container <destContainer>', $('the destination storage container name'))
.option('--dest-blob <destBlob>', $('the destination storage blob name'))
.option('-q, --quiet', $('overwrite the destination blob without confirmation'))
.addStorageAccountOption()
@@ -250,7 +247,7 @@ exports.init = function(cli) {
.description($('Show the copy status'))
.option('--container <container>', $('the destination container in the blob copy start operation'))
.option('--blob <blob>', $('the destination blob in the blob copy start operation'))
- .option('--sas <sas>', $('the shared access signature of the destination storage containe or blob'))
+ .option('--sas <sas>', $('the shared access signature of the destination storage container or blob'))
.addStorageAccountOption()
.execute(showBlobCopy);
@@ -287,11 +284,7 @@ exports.init = function(cli) {
* @return {StorageOperation} storage blob operation
*/
function getStorageBlobOperation(serviceClient, operationName) {
- var operation = new StorageUtil.StorageOperation();
- operation.type = StorageUtil.OperationType.Blob;
- operation.operation = operationName;
- operation.service = serviceClient;
- return operation;
+ return StorageUtil.getStorageOperation(serviceClient, StorageUtil.OperationType.Blob, operationName);
}
/**
@@ -455,8 +448,8 @@ exports.init = function(cli) {
try
{
var aclOperation = getStorageBlobOperation(blobService, 'setContainerAcl');
- var accessLevel = StorageUtil.stringToContainerAccessLevel(permission);
- performStorageOperation(aclOperation, _, container, null, accessLevel, storageOptions);
+ storageOptions.publicAccessLevel = StorageUtil.stringToContainerAccessLevel(permission);
+ performStorageOperation(aclOperation, _, container, null, storageOptions);
} catch (e) {
logger.warn($('Current storage account doesn\'t support setting ACL'));
}
@@ -528,8 +521,8 @@ exports.init = function(cli) {
var operation = getStorageBlobOperation(blobService, 'setContainerAcl');
var storageOptions = getStorageBlobOperationDefaultOption();
validation.isValidEnumValue(permission, Object.keys(BlobUtilities.BlobContainerPublicAccessType));
- var accessLevel = StorageUtil.stringToContainerAccessLevel(permission);
- performStorageOperation(operation, _, container, null, accessLevel, storageOptions);
+ storageOptions.publicAccessLevel = StorageUtil.stringToContainerAccessLevel(permission);
+ performStorageOperation(operation, _, container, null, storageOptions);
} catch (e) {
logger.warn($('Current storage account doesn\'t support setting ACL'));
}
@@ -906,12 +899,15 @@ exports.init = function(cli) {
if (blobTypeName.toLowerCase() === 'page') {
//Upload page blob
operation = getStorageBlobOperation(blobService, 'createPageBlobFromLocalFile');
- performStorageOperation(operation, _, specifiedContainerName, specifiedBlobName, specifiedFileName, storageOptions);
- } else {
+ } else if (blobTypeName.toLowerCase() === 'block'){
//Upload block blob
operation = getStorageBlobOperation(blobService, 'createBlockBlobFromLocalFile');
- performStorageOperation(operation, _, specifiedContainerName, specifiedBlobName, specifiedFileName, storageOptions);
+ } else if (blobTypeName.toLowerCase() === 'append') {
+ //Upload append blob
+ storageOptions.absorbConditionalErrorsOnRetry = true;
+ operation = getStorageBlobOperation(blobService, 'createAppendBlobFromLocalFile');
}
+ performStorageOperation(operation, _, specifiedContainerName, specifiedBlobName, specifiedFileName, storageOptions);
} catch (e) {
printer(true);
throw e;
@@ -979,7 +975,7 @@ exports.init = function(cli) {
storageOptions.parallelOperationThreadCount = options.concurrenttaskcount || storageOptions.parallelOperationThreadCount;
var summary = new SpeedSummary(specifiedBlobName);
storageOptions.speedSummary = summary;
- storageOptions.checkMD5sum = options.checkmd5;
+ storageOptions.disableContentMD5Validation = !options.checkmd5;
startProgress(tips);
endProgress();
@@ -1059,248 +1055,49 @@ exports.init = function(cli) {
}
/**
- * Get destination account options
- */
- function getDestAccountOptions(options) {
- var isNameDefined = options.destAccountName !== undefined;
- var isKeyDefined = options.destAccountKey !== undefined;
- var isSasDefined = options.destSas !== undefined;
- var isConnectionStringDefined = options.destConnectionString !== undefined;
- var isAccountDefined = isNameDefined || isKeyDefined;
- var isUserDefined = isAccountDefined || isSasDefined;
- var destOptions = options; // Inherit account info from source
-
- if (isConnectionStringDefined && isUserDefined) {
- throw new Error($('Please only define one of them: 1. --dest-connection-string. 2 --dest-account-name and --dest-account-key. 3 --dest-account-name and --dest-sas'));
- } else {
- if (isConnectionStringDefined) {
- destOptions.connectionString = options.destConnectionString;
- } else if (isUserDefined) {
- if (isNameDefined) {
- if (isSasDefined && isKeyDefined) {
- throw new Error($('Please only define --dest-account-key or --dest-sas when --dest-account-name is defined'));
- } else if (isKeyDefined) {
- destOptions.connectionString = util.format('DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s', options.destAccountName, options.destAccountKey);
- } else {
- destOptions.accountName = options.destAccountName;
- destOptions.sas = options.destSas;
- }
- } else {
- throw new Error($('Please set --dest-account-name and --dest-account-key or --dest-account-name and --dest-sas'));
- }
- }
-
- // Erase the source account information when the destination connection string is available.
- if (destOptions.connectionString) {
- delete destOptions.accountName;
- delete destOptions.accountKey;
- }
- }
-
- return destOptions;
- }
-
- /**
- * Get source URI from input
- */
- function getSourceUri(options, _) {
- var source;
- if (!options.sourceContainer && !options.sourceBlob) {
- source = interaction.promptIfNotGiven($('Source URI: '), source, _);
- } else {
- if (!options.sourceContainer) {
- options.sourceContainer = interaction.promptIfNotGiven($('Source container: '), options.sourceContainer, _);
- } else if (!options.sourceBlob) {
- options.sourceBlob = interaction.promptIfNotGiven($('Source blob: '), options.sourceBlob, _);
- }
-
- var settings = getStorageSettings(options);
- var host = settings._blobEndpoint.primaryHost;
- if (host === undefined) {
- throw new Error($('The blob endpoint is invalid'));
- }
- if (host.lastIndexOf('/') !== host.length - 1) {
- source = host + '/';
- } else {
- source = host;
- }
- if (options.sourceContainer !== '$root') {
- source += (options.sourceContainer + '/');
- }
- source += encodeURIComponent(options.sourceBlob);
- }
- return source;
- }
-
- /**
- * Get source SAS token
- */
- function getSourceSASToken(sourceContainer, sourceBlob, embeddedSas, options, _) {
- var sasToken = embeddedSas ? undefined : (options.sourceSas || options.sasToken);
- if (sasToken) {
- var isNameDefined = options.accountName !== undefined;
- var isKeyDefined = options.accountKey !== undefined;
- var isConnectionStringDefined = options.connectionString !== undefined;
- if (isConnectionStringDefined || (isNameDefined && isKeyDefined)) {
- throw new Error($('Please only define one of them: 1. --connection-string. 2 --account-name and --account-key 3. --account-name and --sas'));
- }
- sasToken = StorageUtil.normalizeSasToken(sasToken);
- } else if (!embeddedSas) {
- var sourceblobService = getBlobServiceClient(options);
- var aclOperation = getStorageBlobOperation(sourceblobService, 'getContainerAcl');
- var showOptions = getStorageBlobOperationDefaultOption();
- var permission = performStorageOperation(aclOperation, _, sourceContainer, showOptions);
- if (BlobUtilities.BlobContainerPublicAccessType.OFF == permission.publicAccessLevel) {
- // Grant temporary SAS token to the source blob
- var sharedAccessPolicy = {
- AccessPolicy: {
- Permissions: BlobUtilities.SharedAccessPermissions.READ,
- Expiry: azureCommon.date.daysFromNow(7)
- },
- };
- sasToken = sourceblobService.generateSharedAccessSignature(sourceContainer, sourceBlob, sharedAccessPolicy);
- if (!sasToken) {
- throw new Error($('The source blob is not accessible'));
- }
- }
- }
- return sasToken;
- }
-
- /**
* Start blob copy
*/
function startBlobCopy(sourceUri, destContainer, options, _) {
- // Make up the source blob Uri
- var source = sourceUri;
- if (!sourceUri) {
- source = getSourceUri(options, _);
- }
- var sourceContainer = options.sourceContainer;
- var sourceBlob = options.sourceBlob;
-
- // Get parameters for the ACL checking
- var embeddedSas = false;
- var blobResource = splitDestinationUri(source);
- if (!sourceContainer) {
- sourceContainer = blobResource.container;
- }
- if (!sourceBlob) {
- if (!blobResource.blobName) {
- throw new Error($('The source blob is invalid'));
- }
-
- // Parse the blob name from URI when sourceUri is specified with SAS token.
- var index = blobResource.blobName.lastIndexOf('?');
- if (index != -1) {
- embeddedSas = true;
- blobResource.blobName = blobResource.blobName.substring(0, index);
- }
- sourceBlob = decodeURIComponent(blobResource.blobName);
- }
-
- // Make sure the read access to the source blob
- var sasToken = getSourceSASToken(sourceContainer, sourceBlob, embeddedSas, options, _);
- source += (sasToken === undefined ? '' : ('?' + sasToken));
-
- // Check destination information
- var destBlobName = options.destBlob ? options.destBlob : sourceBlob;
- var destContainerName = interaction.promptIfNotGiven($('Destination container name: '), destContainer, _);
- if (!destContainerName) {
- throw new Error($('The destination container name is required'));
- }
-
- // Start copy operation
- var destOption = getDestAccountOptions(options);
- var destBlobService = getBlobServiceClient(destOption);
- var operation = getStorageBlobOperation(destBlobService, 'startCopyBlob');
- var tips = util.format($('Start copying blob %s'), source);
- var storageOptions = getStorageBlobOperationDefaultOption();
-
- var copyOp;
- var retry;
- startProgress(tips);
- while (retry === true || retry === undefined) {
- try {
- if (retry === undefined && !options.quiet) {
- storageOptions.accessConditions = { 'if-none-match': '*' };
- } else {
- storageOptions.accessConditions = {};
- }
- retry = false;
- copyOp = performStorageOperation(operation, _, source, destContainerName, destBlobName, storageOptions);
- } catch (e) {
- if (StorageUtil.isBlobExistsException(e)) {
- retry = interaction.confirm(util.format($('Do you want to overwrite the existing blob %s in container %s? (Y/N) '), destBlobName, destContainerName), _);
- }
- if (!retry) {
- throw e;
- }
- } finally {
- if (!retry) {
- endProgress();
- }
- }
- }
-
- cli.interaction.formatOutput(copyOp, function(outputData) {
- var output = [outputData];
- logger.table(output, function(row, item) {
- row.cell($('Copy ID'), item.copyId);
- row.cell($('Status'), item.copyStatus);
- });
- });
+ var startCopyParams = StorageUtil.getStartCopyParameters(StorageUtil.CopyTypes.CopyToBlob, sourceUri, options);
+ StorageUtil.startAsyncCopy(startCopyParams, sourceUri, destContainer, options, _);
}
/**
* Show blob copy status
*/
function showBlobCopy(container, blob, options, _) {
- container = interaction.promptIfNotGiven($('Destination container: '), container, _);
- blob = interaction.promptIfNotGiven($('Destination blob: '), blob, _);
-
- var destOption = getDestAccountOptions(options);
- var blobProps = getAzureBlobProperties(container, blob, destOption, _);
+ var showCopyParams = {
+ type: StorageUtil.CopyTypes.CopyToBlob,
+ getProperties: getAzureBlobProperties
+ };
- if (blobProps.copyId === undefined) {
- throw new Error($('Can not find copy task on specified blob'));
- } else {
- cli.interaction.formatOutput(blobProps, function(outputData) {
- var output = [outputData];
- logger.table(output, function(row, item) {
- row.cell($('Copy ID'), item.copyId);
- row.cell($('Progress'), item.copyProgress);
- row.cell($('Status'), item.copyStatus);
- if (item.copyStatusDescription) {
- row.cell($('Description'), item.copyStatusDescription);
- }
- });
- });
- }
+ StorageUtil.showAsyncCopy(showCopyParams, container, blob, options, _);
}
/**
* Stop blob copy
*/
function stopBlobCopy(container, blob, copyid, options, _) {
- container = interaction.promptIfNotGiven($('Destination container: '), container, _);
- blob = interaction.promptIfNotGiven($('Destination blob: '), blob, _);
- copyid = interaction.promptIfNotGiven($('Copy ID: '), copyid, _);
-
- var destOption = getDestAccountOptions(options);
- var blobService = getBlobServiceClient(destOption);
- var operation = getStorageBlobOperation(blobService, 'abortCopyBlob');
- var tips = util.format($('Stop copying blob %s in container %s of copy id %s'), blob, container, copyid);
- var storageOptions = getStorageBlobOperationDefaultOption();
+ var getStopOperation = function (serviceClient) {
+ var operationInfo = {};
+ operationInfo.operation = getStorageBlobOperation(serviceClient, 'abortCopyBlob');
+ operationInfo.options = getStorageBlobOperationDefaultOption();
+ return operationInfo;
+ };
- var stopOp;
- startProgress(tips);
- try {
- stopOp = performStorageOperation(operation, _, container, blob, copyid, storageOptions);
- } finally {
- endProgress();
- }