diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..122a98a2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +sudo: false +node_js: + - "6" diff --git a/.vscode/launch.json b/.vscode/launch.json index 38dde347..4ec07356 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -28,6 +28,26 @@ ], "env": {} }, + { + "type": "node", + "request": "launch", + "name": "Live Validator", + "program": "${workspaceRoot}/lib/liveValidator.js", + "cwd": "${workspaceRoot}", + "env": {} + }, + { + "type": "node", + "request": "launch", + "name": "Mocha Tests", + "program": "${workspaceRoot}/node_modules/mocha/bin/mocha", + "cwd": "${workspaceRoot}", + "stopOnEntry": false, + "args": [ + "test/utilsTests.js" + ], + "env": {} + }, { "type": "node", "request": "attach", diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..394ba197 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "files.exclude": { + "**/.git": true, + "**/.svn": true, + "**/.DS_Store": true + }, + "[javascript]": { + "editor.formatOnSave": true, + "editor.formatOnPaste": true, + "editor.tabSize": 2, + "editor.detectIndentation": false + } +} \ No newline at end of file diff --git a/lib/liveValidator.js b/lib/liveValidator.js new file mode 100644 index 00000000..7106d75f --- /dev/null +++ b/lib/liveValidator.js @@ -0,0 +1,314 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +'use strict'; + +var util = require('util'), + path = require('path'), + os = require('os'), + _ = require('lodash'), + glob = require('glob'), + SpecValidator = require('./specValidator'), + Constants = require('./util/constants'), + log = require('./util/logging'), + utils = require('./util/utils'), + url = require("url"); + +/* + * @class + * Live Validator for Azure swagger APIs. + */ +class LiveValidator { + /** + * Constructs LiveValidator based on provided options. + * + * @param {object} options The configuration options. + * + * @param {array} [options.swaggerPaths] Array of swagger paths to be used for initializing Live Validator. + * + * @param {string} [options.git.url] The url of the github repository. Defaults to "https://github.com/Azure/azure-rest-api-specs.git". + * + * @param {string} [options.git.shouldClone] Specifies whether to clone the repository or not. Defaults to false. + * + * @param {string} [options.directory] The directory where to clone github repository or from where to find swaggers. Defaults to "repo" under user directory. + * + * @returns {object} CacheBuilder Returns the configured CacheBuilder object. + */ + constructor(options) { + this.options = options; + + if (this.options === null || this.options === undefined) { + this.options = {}; + } + if (typeof this.options !== 'object') { + throw new Error('options must be of type "object".'); + } + if (this.options.swaggerPaths === null || this.options.swaggerPaths === undefined) { + this.options.swaggerPaths = []; + } + if (!Array.isArray(this.options.swaggerPaths)) { + throw new Error(`options.swaggerPaths must be of type "array" instead of type "${typeof this.options.swaggerPaths}".`); + } + if (this.options.git === null || this.options.git === undefined) { + this.options.git = { + "url": "https://github.com/Azure/azure-rest-api-specs.git", + "shouldClone": false + }; + } + if (typeof this.options.git !== 'object') { + throw new Error('options.git must be of type "object".'); + } + if (this.options.git.url === null || this.options.git.url === undefined) { + this.options.git.url = "https://github.com/Azure/azure-rest-api-specs.git"; + } + if (typeof this.options.git.url.valueOf() !== 'string') { + throw new Error('options.git.url must be of type "string".'); + } + if (this.options.git.shouldClone === null || this.options.git.shouldClone === undefined) { + this.options.git.shouldClone = false; + } + if (typeof this.options.git.shouldClone !== 'boolean') { + throw new Error('options.git.shouldClone must be of type "boolean".'); + } + if (this.options.directory === null || this.options.directory === undefined) { + this.options.directory = path.resolve(os.homedir(), 'repo'); + } + if (typeof this.options.directory.valueOf() !== 'string') { + throw new Error('options.directory must be of type "string".'); + } + this.cache = {}; + } + + /* + * Initializes the Live Validator. + */ + initialize() { + let self = this; + + // Clone github repository if required + if (self.options.git.shouldClone) { + utils.gitClone(self.options.git.url, self.options.directory); + } + + // Construct array of swagger paths to be used for building a cache + let swaggerPaths; + if (self.options.swaggerPaths.length !== 0) { + swaggerPaths = self.options.swaggerPaths; + log.debug(`Using user provided swagger paths. Total paths: ${swaggerPaths.length}`); + } else { + swaggerPaths = glob.sync(path.join(self.options.directory, '/**/swagger/*.json')); + log.debug(`Using swaggers found from "${self.options.directory}" provided swagger paths. Total paths: ${swaggerPaths.length}`); + } + // console.log(swaggerPaths); + // Create array of promise factories that builds up cache + // Structure of the cache is + // { + // "provider1": { + // "api-version1": { + // "get": [ + // "operation1", + // "operation2", + // ], + // "put": [ + // "operation1", + // "operation2", + // ], + // ... + // }, + // ... + // }, + // "microsoft.unknown": { + // "unknown-api-version": { + // "post": [ + // "operation1" + // ] + // } + // } + // ... + // } + let promiseFactories = swaggerPaths.map((swaggerPath) => { + return () => { + log.info(`Building cache from: "${swaggerPath}"`); + let validator = new SpecValidator(swaggerPath); + return validator.initialize().then((api) => { + let operations = api.getOperations(); + let apiVersion = api.info.version.toLowerCase(); + + operations.forEach((operation) => { + let httpMethod = operation.method.toLowerCase(); + let provider = utils.getProvider(operation.pathObject.path); + log.debug(`${apiVersion}, ${operation.operationId}, ${operation.pathObject.path}, ${httpMethod}`); + + if (!provider) { + let title = api.info.title; + + // Whitelist lookups: Look up knownTitleToResourceProviders + // Putting the provider namespace onto operation for future use + if (title && Constants.knownTitleToResourceProviders[title]) { + operation.provider = Constants.knownTitleToResourceProviders[title]; + } + + // Put the operation into 'Microsoft.Unknown' RPs + provider = Constants.unknownResourceProvider; + apiVersion = Constants.unknownApiVersion; + log.warn(`Unable to find provider for path : "${operation.pathObject.path}". Bucketizing into provider: "${provider}"`); + } + provider = provider.toLowerCase(); + + // Get all api-version for given provider or initialize it + let apiVersions = self.cache[provider] || {}; + // Get methods for given apiVersion or initialize it + let allMethods = apiVersions[apiVersion] || {}; + // Get specific http methods array for given verb or initialize it + let operationsForHttpMethod = allMethods[httpMethod] || []; + + // Builds the cache + operationsForHttpMethod.push(operation); + allMethods[httpMethod] = operationsForHttpMethod; + apiVersions[apiVersion] = allMethods; + self.cache[provider] = apiVersions; + }); + + return Promise.resolve(self.cache); + }).catch(function (err) { + log.warn(`Unable to initialize "${swaggerPath}" file from SpecValidator. Error: ${err}`); + return Promise.reject(err); + }); + } + }); + + return utils.executePromisesSequentially(promiseFactories).then(() => { + log.info("Cache initialization complete."); + }); + } + + /** + * Gets list of potential operations objects for given url and method. + * + * @param {string} requestUrl The url for which to find potential operations. + * + * @param {string} requestMethod The http verb for the method to be used for lookup. + * + * @returns {Array} List of potential operations matching the url and method. + */ + getPotentialOperations(requestUrl, requestMethod) { + if (_.isEmpty(this.cache)) { + let msg = `Please call "liveValidator.initialize()" before calling this method, so that cache is populated.`; + throw new Error(msg); + } + + if (requestUrl === null || requestUrl === undefined || typeof requestUrl.valueOf() !== 'string' || + !requestUrl.trim().length) { + throw new Error('requestUrl is a required parameter of type "string" and it cannot be an empty string.'); + } + + if (requestMethod === null || requestMethod === undefined || typeof requestMethod.valueOf() !== 'string' || + !requestMethod.trim().length) { + throw new Error('requestMethod is a required parameter of type "string" and it cannot be an empty string.'); + } + + let self = this; + let potentialOperations = []; + let parsedUrl = url.parse(requestUrl, true); + let path = parsedUrl.pathname; + requestMethod = requestMethod.toLowerCase(); + if (path === null || path === undefined) { + throw new Error(`Could not find path from requestUrl: "${requestUrl}".`); + } + + // Lower all the keys of query parameters before searching for `api-version` + var queryObject = _.transform(parsedUrl.query, function (result, value, key) { + result[key.toLowerCase()] = value; + }); + let apiVersion = queryObject['api-version']; + let provider = utils.getProvider(path); + + // Provider would be provider found from the path or Microsoft.Unknown + provider = provider || Constants.unknownResourceProvider; + if (provider === Constants.unknownResourceProvider) { + apiVersion = Constants.unknownApiVersion; + } + provider = provider.toLowerCase(); + + // Search using provider + let allApiVersions = self.cache[provider]; + if (allApiVersions) { + // Search using api-version found in the requestUrl + if (apiVersion) { + let allMethods = allApiVersions[apiVersion]; + if (allMethods) { + let operationsForHttpMethod = allMethods[requestMethod]; + // Search using requestMethod provided by user + if (operationsForHttpMethod) { + // Find the best match using regex on path + potentialOperations = self.getPotentialOperationsHelper(path, requestMethod, operationsForHttpMethod); + } else { + log.warn(`Could not find any methods with verb "${requestMethod}" for api-version "${apiVersion}" and provider "${provider}" in the cache.`); + } + } else { + log.warn(`Could not find exact api-version "${apiVersion}" for provider "${provider}" in the cache but we'll search in the Microsoft.Unknown.`); + potentialOperations = self.getPotentialOperationsHelper(path, requestMethod, []); + } + } else { + log.warn(`Could not find api-version in requestUrl "${requestUrl}".`); + } + } else { + // provider does not exist in cache + log.warn(`Could not find provider "${provider}" in the cache but we'll search in the Microsoft.Unknown.`); + potentialOperations = self.getPotentialOperationsHelper(path, requestMethod, []); + } + + return potentialOperations; + } + + /** + * Gets list of potential operations objects for given path and method. + * + * @param {string} requestPath The path of the url for which to find potential operations. + * + * @param {string} requestMethod The http verb for the method to be used for lookup. + * + * @param {Array} operations The list of operations to search. + * + * @returns {Array} List of potential operations matching the requestPath. + */ + getPotentialOperationsHelper(requestPath, requestMethod, operations) { + if (requestPath === null || requestPath === undefined || typeof requestPath.valueOf() !== 'string' || + !requestPath.trim().length) { + throw new Error('requestPath is a required parameter of type string and it cannot be an empty string.'); + } + + if (requestMethod === null || requestMethod === undefined || typeof requestMethod.valueOf() !== 'string' || + !requestMethod.trim().length) { + throw new Error('requestMethod is a required parameter of type "string" and it cannot be an empty string.'); + } + + if (operations === null || operations === undefined || !Array.isArray(operations) || + !operations.length) { + throw new Error('operations is a required parameter of type array and it cannot be an empty array.'); + } + + let potentialOperations = []; + potentialOperations = operations.filter((operation) => { + let pathMatch = operation.pathObject.regexp.exec(requestPath); + return pathMatch === null ? false : true; + }); + + // If we do not find any match then we'll look into Microsoft.Unknown -> unknown-api-version + // for given requestMethod as the fall back option + if (!potentialOperations.length) { + if (self.cache[Constants.unknownResourceProvider] && + self.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]) { + operations = self.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion][requestMethod]; + potentialOperations = operations.filter((operation) => { + let pathMatch = operation.pathObject.regexp.exec(requestPath); + return pathMatch === null ? false : true; + }); + } + } + + return potentialOperations; + } +} + +module.exports = LiveValidator; diff --git a/lib/util/constants.js b/lib/util/constants.js index bb2a830e..f82bf5d3 100644 --- a/lib/util/constants.js +++ b/lib/util/constants.js @@ -40,6 +40,11 @@ var Constants = { AzureSubscriptionId: 'AZURE_SUBSCRIPTION_ID', AzureLocation: 'AZURE_LOCATION', AzureResourcegroup: 'AZURE_RESOURCE_GROUP' + }, + unknownResourceProvider: 'microsoft.unknown', + unknownApiVersion: 'unknown-api-version', + knownTitleToResourceProviders: { + 'ResourceManagementClient': 'Microsoft.Resources' } }; diff --git a/lib/util/utils.js b/lib/util/utils.js index 547ca131..223ae54c 100644 --- a/lib/util/utils.js +++ b/lib/util/utils.js @@ -3,6 +3,8 @@ 'use strict'; var fs = require('fs'), + sys = require('sys'), + execSync = require('child_process').execSync, util = require('util'), path = require('path'), jsonPointer = require('json-pointer'), @@ -363,6 +365,64 @@ exports.removeObject = function removeObject(doc, ptr) { }; /** +/* + * Gets provider namespace from the given path. In case of multiple, last one will be returned. + * @param {string} path The path of the operation. + * Example "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/ + * {parentResourcePath}/{resourceType}/{resourceName}/providers/Microsoft.Authorization/roleAssignments" + * will return "Microsoft.Authorization". + * + * @returns {string} result - provider namespace from the given path. + */ +exports.getProvider = function getProvider(path) { + if (path === null || path === undefined || typeof path.valueOf() !== 'string' || !path.trim().length) { + throw new Error('path is a required parameter of type string and it cannot be an empty string.'); + } + + let providerRegEx = new RegExp('/providers/(\:?[^{/]+)', 'gi'); + let result; + let pathMatch; + + // Loop over the paths to find the last matched provider namespace + while ((pathMatch = providerRegEx.exec(path)) != null) { + result = pathMatch[1]; + } + + return result; +}; + +/* + * Clones a github repository in the given directory. + * @param {string} github url to be cloned. + * Example "https://github.com/Azure/azure-rest-api-specs.git" or + * "git@github.com:Azure/azure-rest-api-specs.git". + * + * @param {string} path where to clone the repository. + */ +exports.gitClone = function gitClone(url, directory) { + if (url === null || url === undefined || typeof url.valueOf() !== 'string' || !url.trim().length) { + throw new Error('url is a required parameter of type string and it cannot be an empty string.'); + } + + if (directory === null || directory === undefined || typeof directory.valueOf() !== 'string' || !directory.trim().length) { + throw new Error('directory is a required parameter of type string and it cannot be an empty string.'); + } + + if (fs.existsSync(directory) && fs.lstatSync(directory).isDirectory()) { + throw new Error(`directory "${directory}" already exists. Please delete it first and then try again.`); + } else { + fs.mkdirSync(directory); + } + + try { + let cmd = `git clone ${url} ${directory}`; + let result = execSync(cmd, { encoding: 'utf8' }); + } catch (err) { + throw new Error(`An error occurred while cloning git repository: ${util.inspect(err, { depth: null })}.`); + } +}; + +/* * Finds the first content-type that contains "/json". Only supported Content-Types are * "text/json" & "application/json" so we perform first best match that contains '/json' * diff --git a/package.json b/package.json index b388fb69..0898b2b6 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,15 @@ "request": "^2.79.0", "sway": "amarzavery/sway#validation", "winston": "^2.3.0", - "yargs": "^6.6.0" + "yargs": "^6.6.0", + "glob": "^5.0.14" + }, + "devDependencies": { + "jshint": "2.9.4", + "mocha": "^3.2.0", + "should": "5.2.0", + "@types/mocha": "^2.2.40", + "@types/should": "^8.1.30" }, "homepage": "https://github.com/azure/openapi-validaton-tools", "repository": { @@ -29,5 +37,8 @@ "url": "http://github.com/azure/openapi-validaton-tools/issues" }, "main": "./index.js", - "bin": { "oav": "./cli.js" } + "bin": { "oav": "./cli.js" }, + "scripts": { + "test": "./node_modules/mocha/bin/mocha test/*" + } } diff --git a/test/liveValidatorTests.js b/test/liveValidatorTests.js new file mode 100644 index 00000000..fecf773d --- /dev/null +++ b/test/liveValidatorTests.js @@ -0,0 +1,215 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +var assert = require('assert'), + path = require('path'), + os = require('os'), + LiveValidator = require('../lib/liveValidator.js'), + Constants = require('../lib/util/constants'); + +describe('Live Validator', function () { + describe('Initialization', function () { + it('should initialize with defaults', function () { + let options = { + "swaggerPaths": [], + "git": { + "url": "https://github.com/Azure/azure-rest-api-specs.git", + "shouldClone": false + }, + "directory": path.resolve(os.homedir(), 'repo') + }; + let validator = new LiveValidator(); + assert.deepEqual(validator.cache, {}); + assert.deepEqual(validator.options, options); + }); + it('should initialize with user provided swaggerPaths', function () { + let swaggerPaths = ["swaggerPath1", "swaggerPath2"]; + let options = { + "swaggerPaths": swaggerPaths, + "git": { + "url": "https://github.com/Azure/azure-rest-api-specs.git", + "shouldClone": false + }, + "directory": path.resolve(os.homedir(), 'repo') + }; + let validator = new LiveValidator({ "swaggerPaths": swaggerPaths }); + assert.deepEqual(validator.cache, {}); + assert.deepEqual(validator.options, options); + }); + it('should initialize with user provided swaggerPaths & directory', function () { + let swaggerPaths = ["swaggerPath1", "swaggerPath2"]; + let directory = "/Users/username/repos/" + let options = { + "swaggerPaths": swaggerPaths, + "git": { + "url": "https://github.com/Azure/azure-rest-api-specs.git", + "shouldClone": false + }, + "directory": directory + }; + let validator = new LiveValidator({ "swaggerPaths": swaggerPaths, "directory": directory }); + assert.deepEqual(validator.cache, {}); + assert.deepEqual(validator.options, options); + }); + it('should initialize with user provided partial git configuration', function () { + let swaggerPaths = ["swaggerPath1", "swaggerPath2"]; + let directory = "/Users/username/repos/" + let git = { + "url": "https://github.com/vishrutshah/azure-rest-api-specs.git" + } + let options = { + "swaggerPaths": swaggerPaths, + "git": { + "url": git.url, + "shouldClone": false + }, + "directory": directory + }; + let validator = new LiveValidator({ "swaggerPaths": swaggerPaths, "directory": directory, "git": git }); + assert.deepEqual(validator.cache, {}); + assert.deepEqual(validator.options, options); + }); + it('should initialize with user provided full git configuration', function () { + let swaggerPaths = ["swaggerPath1", "swaggerPath2"]; + let directory = "/Users/username/repos/" + let git = { + "url": "https://github.com/vishrutshah/azure-rest-api-specs.git", + "shouldClone": true + } + let options = { + "swaggerPaths": swaggerPaths, + "git": git, + "directory": directory + }; + let validator = new LiveValidator({ "swaggerPaths": swaggerPaths, "directory": directory, "git": git }); + assert.deepEqual(validator.cache, {}); + assert.deepEqual(validator.options, options); + }); + it('should throw on invalid options types', function () { + assert.throws(() => { + new LiveValidator('string'); + }, /must be of type "object"/); + assert.throws(() => { + new LiveValidator({ "swaggerPaths": "should be array" }); + }, /must be of type "array"/); + assert.throws(() => { + new LiveValidator({ "git": 1 }); + }, /must be of type "object"/); + assert.throws(() => { + new LiveValidator({ "git": { "url": [] } }); + }, /must be of type "string"/); + assert.throws(() => { + new LiveValidator({ "git": { "url": "url", "shouldClone": "no" } }); + }, /must be of type "boolean"/); + }); + }); + describe('Initialize cache', function () { + it('should initialize for arm-mediaservices', function (done) { + let expectedProvider = 'microsoft.media'; + let expectedApiVersion = '2015-10-01'; + let options = { + "directory": "./test/swaggers/arm-mediaservices" + }; + let validator = new LiveValidator(options); + validator.initialize().then(function () { + assert.equal(true, expectedProvider in validator.cache); + assert.equal(1, Object.keys(validator.cache).length); + assert.equal(true, expectedApiVersion in (validator.cache[expectedProvider])); + assert.equal(1, Object.keys(validator.cache[expectedProvider]).length); + assert.equal(2, validator.cache[expectedProvider][expectedApiVersion]['get'].length); + assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['put'].length); + assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['patch'].length); + assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['delete'].length); + assert.equal(4, validator.cache[expectedProvider][expectedApiVersion]['post'].length); + done(); + }).catch((err) => { + assert.ifError(err); + done(); + }).catch(done); + }); + it('should initialize for arm-resources', function (done) { + let expectedProvider = 'microsoft.resources'; + let expectedApiVersion = '2016-09-01'; + let options = { + "directory": "./test/swaggers/arm-resources" + }; + let validator = new LiveValidator(options); + validator.initialize().then(function () { + assert.equal(true, expectedProvider in validator.cache); + assert.equal(2, Object.keys(validator.cache).length); + assert.equal(true, expectedApiVersion in (validator.cache[expectedProvider])); + assert.equal(1, Object.keys(validator.cache[expectedProvider]).length); + // 'microsoft.resources' -> '2016-09-01' + assert.equal(2, validator.cache[expectedProvider][expectedApiVersion]['get'].length); + assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['delete'].length); + assert.equal(3, validator.cache[expectedProvider][expectedApiVersion]['post'].length); + assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['head'].length); + assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['put'].length); + // 'microsoft.unknown' -> 'unknown-api-version' + assert.equal(4, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['post'].length); + assert.equal(11, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['get'].length); + assert.equal(3, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['head'].length); + assert.equal(5, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['put'].length); + assert.equal(5, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['delete'].length); + assert.equal(1, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['patch'].length); + done(); + }).catch((err) => { + assert.ifError(err); + done(); + }).catch(done); + }); + it('should initialize for all swaggers', function (done) { + let options = { + "directory": "./test/swaggers" + }; + let validator = new LiveValidator(options); + validator.initialize().then(function () { + assert.equal(5, Object.keys(validator.cache).length); + assert.equal(2, validator.cache['microsoft.resources']['2016-09-01']['get'].length); + assert.equal(1, validator.cache['microsoft.resources']['2016-09-01']['head'].length); + assert.equal(1, validator.cache['microsoft.media']['2015-10-01']['patch'].length); + assert.equal(4, validator.cache['microsoft.media']['2015-10-01']['post'].length); + assert.equal(2, validator.cache['microsoft.search']['2015-02-28']['get'].length); + assert.equal(3, validator.cache['microsoft.search']['2015-08-19']['get'].length); + assert.equal(1, validator.cache['microsoft.storage']['2015-05-01-preview']['patch'].length); + assert.equal(4, validator.cache['microsoft.storage']['2015-06-15']['get'].length); + assert.equal(3, validator.cache['microsoft.storage']['2016-01-01']['post'].length); + done(); + }).catch((err) => { + assert.ifError(err); + done(); + }).catch(done); + }); + }); + describe('Initialize cache and search', function () { + it('should return one matched operation for arm-storage', function (done) { + let options = { + "directory": "./test/swaggers/arm-storage" + }; + let listRequestUrl = "https://management.azure.com/subscriptions/subscriptionId/providers/Microsoft.Storage/storageAccounts?api-version=2015-06-15"; + let postRequestUrl = "https://management.azure.com/subscriptions/subscriptionId/providers/Microsoft.Storage/checkNameAvailability?api-version=2015-06-15"; + let deleteRequestUrl = "https://management.azure.com/subscriptions/subscriptionId/resourceGroups/myRG/providers/Microsoft.Storage/storageAccounts/accname?api-version=2015-06-15"; + let validator = new LiveValidator(options); + validator.initialize().then(function () { + // Operations to match is StorageAccounts_List + let operations = validator.getPotentialOperations(listRequestUrl, 'Get'); + assert.equal(1, operations.length); + assert.equal("/subscriptions/{subscriptionId}/providers/Microsoft.Storage/storageAccounts", operations[0].pathObject.path); + + // Operations to match is StorageAccounts_CheckNameAvailability + operations = validator.getPotentialOperations(postRequestUrl, 'PoSt'); + assert.equal(1, operations.length); + assert.equal("/subscriptions/{subscriptionId}/providers/Microsoft.Storage/checkNameAvailability", operations[0].pathObject.path); + + // Operations to match is StorageAccounts_Delete + operations = validator.getPotentialOperations(deleteRequestUrl, 'delete'); + assert.equal(1, operations.length); + assert.equal("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}", operations[0].pathObject.path); + done(); + }).catch((err) => { + assert.ifError(err); + done(); + }).catch(done); + }); + }); +}); diff --git a/arm-mediaservices/2015-10-01/swagger/media.json b/test/swaggers/arm-mediaservices/2015-10-01/swagger/media.json similarity index 100% rename from arm-mediaservices/2015-10-01/swagger/media.json rename to test/swaggers/arm-mediaservices/2015-10-01/swagger/media.json diff --git a/test/swaggers/arm-resources/2016-09-01/swagger/resources.json b/test/swaggers/arm-resources/2016-09-01/swagger/resources.json new file mode 100644 index 00000000..b2194982 --- /dev/null +++ b/test/swaggers/arm-resources/2016-09-01/swagger/resources.json @@ -0,0 +1,2693 @@ +{ + "swagger": "2.0", + "info": { + "title": "ResourceManagementClient", + "version": "2016-09-01", + "description": "Provides operations for working with resources and resource groups." + }, + "host": "management.azure.com", + "schemes": [ + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "security": [ + { + "azure_auth": [ + "user_impersonation" + ] + } + ], + "securityDefinitions": { + "azure_auth": { + "type": "oauth2", + "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize", + "flow": "implicit", + "description": "Azure Active Directory OAuth2 Flow", + "scopes": { + "user_impersonation": "impersonate your user account" + } + } + }, + "paths": { + "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/{deploymentName}": { + "delete": { + "tags": [ + "Deployments" + ], + "operationId": "Deployments_Delete", + "summary": "Deletes a deployment from the deployment history.", + "description": "A template deployment that is currently running cannot be deleted. Deleting a template deployment removes the associated deployment operations. Deleting a template deployment does not affect the state of the resource group. This is an asynchronous operation that returns a status of 202 until the template deployment is successfully deleted. The Location response header contains the URI that is used to obtain the status of the process. While the process is running, a call to the URI in the Location header returns a status of 202. When the process finishes, the URI in the Location header returns a status of 204 on success. If the asynchronous request failed, the URI in the Location header returns an error-level status code.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group with the deployment to delete. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "deploymentName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the deployment to delete.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 64 + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "202": { + "description": "Accepted - Returns this status until the asynchronous operation has completed." + }, + "204": { + "description": "No Content" + } + }, + "x-ms-long-running-operation": true + }, + "head": { + "tags": [ + "Deployments" + ], + "operationId": "Deployments_CheckExistence", + "description": "Checks whether the deployment exists.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group with the deployment to check. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "deploymentName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the deployment to check.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 64 + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "404": { + "description": "Not Found" + } + } + }, + "put": { + "tags": [ + "Deployments" + ], + "operationId": "Deployments_CreateOrUpdate", + "summary": "Deploys resources to a resource group.", + "description": "You can provide the template and parameters directly in the request or link to JSON files.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group to deploy the resources to. The name is case insensitive. The resource group must already exist.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "deploymentName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the deployment.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 64 + }, + { + "name": "parameters", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Deployment" + }, + "description": "Additional parameters supplied to the operation." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns information about the deployment, including provisioning status.", + "schema": { + "$ref": "#/definitions/DeploymentExtended" + } + }, + "201": { + "description": "Created - Returns information about the deployment, including provisioning status.", + "schema": { + "$ref": "#/definitions/DeploymentExtended" + } + } + }, + "x-ms-long-running-operation": true + }, + "get": { + "tags": [ + "Deployments" + ], + "operationId": "Deployments_Get", + "description": "Gets a deployment.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "deploymentName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the deployment to get.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 64 + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns information about the deployment, including provisioning status.", + "schema": { + "$ref": "#/definitions/DeploymentExtended" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/{deploymentName}/cancel": { + "post": { + "tags": [ + "Deployments" + ], + "operationId": "Deployments_Cancel", + "summary": "Cancels a currently running template deployment.", + "description": "You can cancel a deployment only if the provisioningState is Accepted or Running. After the deployment is canceled, the provisioningState is set to Canceled. Canceling a template deployment stops the currently running template deployment and leaves the resource group partially deployed.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "deploymentName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the deployment to cancel.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 64 + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/{deploymentName}/validate": { + "post": { + "tags": [ + "Deployments" + ], + "operationId": "Deployments_Validate", + "description": "Validates whether the specified template is syntactically correct and will be accepted by Azure Resource Manager..", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group the template will be deployed to. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "deploymentName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the deployment.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 64 + }, + { + "name": "parameters", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/Deployment" + }, + "description": "Parameters to validate." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns the validation result.", + "schema": { + "$ref": "#/definitions/DeploymentValidateResult" + } + }, + "400": { + "description": "Returns the validation result.", + "schema": { + "$ref": "#/definitions/DeploymentValidateResult" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/{deploymentName}/exportTemplate": { + "post": { + "tags": [ + "Deployments" + ], + "operationId": "Deployments_ExportTemplate", + "description": "Exports the template used for specified deployment.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "deploymentName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the deployment from which to get the template.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 64 + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns the template.", + "schema": { + "$ref": "#/definitions/DeploymentExportResult" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/": { + "get": { + "tags": [ + "Deployments" + ], + "operationId": "Deployments_List", + "description": "Get all the deployments for a resource group.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group with the deployments to get. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "$filter", + "in": "query", + "required": false, + "type": "string", + "description": "The filter to apply on the operation. For example, you can use $filter=provisioningState eq '{state}'." + }, + { + "name": "$top", + "in": "query", + "required": false, + "type": "integer", + "format": "int32", + "description": "The number of results to get. If null is passed, returns all deployments." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns an array of deployments.", + "schema": { + "$ref": "#/definitions/DeploymentListResult" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + }, + "x-ms-odata": "#/definitions/DeploymentExtendedFilter" + } + }, + "/subscriptions/{subscriptionId}/providers/{resourceProviderNamespace}/unregister": { + "post": { + "tags": [ + "Providers" + ], + "operationId": "Providers_Unregister", + "description": "Unregisters a subscription from a resource provider.", + "parameters": [ + { + "name": "resourceProviderNamespace", + "in": "path", + "required": true, + "type": "string", + "description": "The namespace of the resource provider to unregister." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns informatin about the resource provider.", + "schema": { + "$ref": "#/definitions/Provider" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/providers/{resourceProviderNamespace}/register": { + "post": { + "tags": [ + "Providers" + ], + "operationId": "Providers_Register", + "description": "Registers a subscription with a resource provider.", + "parameters": [ + { + "name": "resourceProviderNamespace", + "in": "path", + "required": true, + "type": "string", + "description": "The namespace of the resource provider to register." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns information about the resource provider.", + "schema": { + "$ref": "#/definitions/Provider" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/providers": { + "get": { + "tags": [ + "Providers" + ], + "operationId": "Providers_List", + "description": "Gets all resource providers for a subscription.", + "parameters": [ + { + "name": "$top", + "in": "query", + "required": false, + "type": "integer", + "format": "int32", + "description": "The number of results to return. If null is passed returns all deployments." + }, + { + "name": "$expand", + "in": "query", + "required": false, + "type": "string", + "description": "The properties to include in the results. For example, use &$expand=metadata in the query string to retrieve resource provider metadata. To include property aliases in response, use $expand=resourceTypes/aliases." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns an array of resource providers.", + "schema": { + "$ref": "#/definitions/ProviderListResult" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/subscriptions/{subscriptionId}/providers/{resourceProviderNamespace}": { + "get": { + "tags": [ + "Providers" + ], + "operationId": "Providers_Get", + "description": "Gets the specified resource provider.", + "parameters": [ + { + "name": "$expand", + "in": "query", + "required": false, + "type": "string", + "description": "The $expand query parameter. For example, to include property aliases in response, use $expand=resourceTypes/aliases." + }, + { + "name": "resourceProviderNamespace", + "in": "path", + "required": true, + "type": "string", + "description": "The namespace of the resource provider." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns information about the resource provider.", + "schema": { + "$ref": "#/definitions/Provider" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/resources": { + "get": { + "tags": [ + "ResourceGroups" + ], + "operationId": "ResourceGroups_ListResources", + "description": "Get all the resources for a resource group.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The resource group with the resources to get.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "$filter", + "in": "query", + "required": false, + "type": "string", + "description": "The filter to apply on the operation." + }, + { + "name": "$expand", + "in": "query", + "required": false, + "type": "string", + "description": "The $expand query parameter" + }, + { + "name": "$top", + "in": "query", + "required": false, + "type": "integer", + "format": "int32", + "description": "The number of results to return. If null is passed, returns all resources." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns an array of resources", + "schema": { + "$ref": "#/definitions/ResourceListResult" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + }, + "x-ms-odata": "#/definitions/GenericResourceFilter" + } + }, + "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}": { + "head": { + "tags": [ + "ResourceGroups" + ], + "operationId": "ResourceGroups_CheckExistence", + "description": "Checks whether a resource group exists.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group to check. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "404": { + "description": "Not Found" + } + } + }, + "put": { + "tags": [ + "ResourceGroups" + ], + "operationId": "ResourceGroups_CreateOrUpdate", + "description": "Creates a resource group.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group to create or update.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "parameters", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ResourceGroup" + }, + "description": "Parameters supplied to the create or update a resource group." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "201": { + "description": "Created - Returns information about the new resource group.", + "schema": { + "$ref": "#/definitions/ResourceGroup" + } + }, + "200": { + "description": "OK - Returns information about the new resource group.", + "schema": { + "$ref": "#/definitions/ResourceGroup" + } + } + } + }, + "delete": { + "tags": [ + "ResourceGroups" + ], + "operationId": "ResourceGroups_Delete", + "summary": "Deletes a resource group.", + "description": "When you delete a resource group, all of its resources are also deleted. Deleting a resource group deletes all of its template deployments and currently stored operations.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group to delete. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "202": { + "description": "Accepted" + }, + "200": { + "description": "OK" + } + }, + "x-ms-long-running-operation": true + }, + "get": { + "tags": [ + "ResourceGroups" + ], + "operationId": "ResourceGroups_Get", + "description": "Gets a resource group.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group to get. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns information about the resource group.", + "schema": { + "$ref": "#/definitions/ResourceGroup" + } + } + } + }, + "patch": { + "tags": [ + "ResourceGroups" + ], + "operationId": "ResourceGroups_Patch", + "summary": "Updates a resource group.", + "description": "Resource groups can be updated through a simple PATCH operation to a group address. The format of the request is the same as that for creating a resource group. If a field is unspecified, the current value is retained.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group to update. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "parameters", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ResourceGroup" + }, + "description": "Parameters supplied to update a resource group." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns information about the resource group.", + "schema": { + "$ref": "#/definitions/ResourceGroup" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/exportTemplate": { + "post": { + "tags": [ + "ResourceGroups" + ], + "operationId": "ResourceGroups_ExportTemplate", + "description": "Captures the specified resource group as a template.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group to export as a template.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "parameters", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ExportTemplateRequest" + }, + "description": "Parameters for exporting the template." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns the result of the export.", + "schema": { + "$ref": "#/definitions/ResourceGroupExportResult" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/resourcegroups": { + "get": { + "tags": [ + "ResourceGroups" + ], + "operationId": "ResourceGroups_List", + "description": "Gets all the resource groups for a subscription.", + "parameters": [ + { + "name": "$filter", + "in": "query", + "required": false, + "type": "string", + "description": "The filter to apply on the operation." + }, + { + "name": "$top", + "in": "query", + "required": false, + "type": "integer", + "format": "int32", + "description": "The number of results to return. If null is passed, returns all resource groups." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns an array of resource groups.", + "schema": { + "$ref": "#/definitions/ResourceGroupListResult" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + }, + "x-ms-odata": "#/definitions/ResourceGroupFilter" + } + }, + "/subscriptions/{subscriptionId}/resourceGroups/{sourceResourceGroupName}/moveResources": { + "post": { + "tags": [ + "Resources" + ], + "operationId": "Resources_MoveResources", + "summary": "Moves resources from one resource group to another resource group.", + "description": "The resources to move must be in the same source resource group. The target resource group may be in a different subscription. When moving resources, both the source group and the target group are locked for the duration of the operation. Write and delete operations are blocked on the groups until the move completes. ", + "parameters": [ + { + "name": "sourceResourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group containing the rsources to move.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "parameters", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ResourcesMoveInfo" + }, + "description": "Parameters for moving resources." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "202": { + "description": "Accepted" + }, + "204": { + "description": "No Content" + } + }, + "x-ms-long-running-operation": true + } + }, + "/subscriptions/{subscriptionId}/resources": { + "get": { + "tags": [ + "Resources" + ], + "operationId": "Resources_List", + "description": "Get all the resources in a subscription.", + "parameters": [ + { + "name": "$filter", + "in": "query", + "required": false, + "type": "string", + "description": "The filter to apply on the operation." + }, + { + "name": "$expand", + "in": "query", + "required": false, + "type": "string", + "description": "The $expand query parameter." + }, + { + "name": "$top", + "in": "query", + "required": false, + "type": "integer", + "format": "int32", + "description": "The number of results to return. If null is passed, returns all resource groups." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns an array of resources.", + "schema": { + "$ref": "#/definitions/ResourceListResult" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + }, + "x-ms-odata": "#/definitions/GenericResourceFilter" + } + }, + "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{parentResourcePath}/{resourceType}/{resourceName}": { + "head": { + "tags": [ + "Resources" + ], + "operationId": "Resources_CheckExistence", + "description": "Checks whether a resource exists.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group containing the resource to check. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "resourceProviderNamespace", + "in": "path", + "required": true, + "type": "string", + "description": "The resource provider of the resource to check." + }, + { + "name": "parentResourcePath", + "in": "path", + "required": true, + "type": "string", + "description": "The parent resource identity.", + "x-ms-skip-url-encoding": true + }, + { + "name": "resourceType", + "in": "path", + "required": true, + "type": "string", + "description": "The resource type.", + "x-ms-skip-url-encoding": true + }, + { + "name": "resourceName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource to check whether it exists." + }, + { + "name": "api-version", + "in": "query", + "required": true, + "type": "string", + "description": "The API version to use for the operation." + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "tags": [ + "Resources" + ], + "operationId": "Resources_Delete", + "description": "Deletes a resource.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group that contains the resource to delete. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "resourceProviderNamespace", + "in": "path", + "required": true, + "type": "string", + "description": "The namespace of the resource provider." + }, + { + "name": "parentResourcePath", + "in": "path", + "required": true, + "type": "string", + "description": "The parent resource identity.", + "x-ms-skip-url-encoding": true + }, + { + "name": "resourceType", + "in": "path", + "required": true, + "type": "string", + "description": "The resource type.", + "x-ms-skip-url-encoding": true + }, + { + "name": "resourceName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource to delete." + }, + { + "name": "api-version", + "in": "query", + "required": true, + "type": "string", + "description": "The API version to use for the operation." + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK" + }, + "204": { + "description": "No Content" + }, + "202": { + "description": "Accepted" + } + }, + "x-ms-long-running-operation": true + }, + "put": { + "tags": [ + "Resources" + ], + "operationId": "Resources_CreateOrUpdate", + "description": "Creates a resource.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group for the resource. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "resourceProviderNamespace", + "in": "path", + "required": true, + "type": "string", + "description": "The namespace of the resource provider." + }, + { + "name": "parentResourcePath", + "in": "path", + "required": true, + "type": "string", + "description": "The parent resource identity.", + "x-ms-skip-url-encoding": true + }, + { + "name": "resourceType", + "in": "path", + "required": true, + "type": "string", + "description": "The resource type of the resource to create.", + "x-ms-skip-url-encoding": true + }, + { + "name": "resourceName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource to create." + }, + { + "name": "api-version", + "in": "query", + "required": true, + "type": "string", + "description": "The API version to use for the operation." + }, + { + "name": "parameters", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GenericResource" + }, + "description": "Parameters for creating or updating the resource." + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "201": { + "description": "Created - Returns information about the resource.", + "schema": { + "$ref": "#/definitions/GenericResource" + } + }, + "200": { + "description": "OK - Returns information about the resource.", + "schema": { + "$ref": "#/definitions/GenericResource" + } + }, + "202": { + "description": "Accepted" + } + }, + "x-ms-long-running-operation": true + }, + "get": { + "tags": [ + "Resources" + ], + "operationId": "Resources_Get", + "description": "Gets a resource.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group containing the resource to get. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "resourceProviderNamespace", + "in": "path", + "required": true, + "type": "string", + "description": "The namespace of the resource provider." + }, + { + "name": "parentResourcePath", + "in": "path", + "required": true, + "type": "string", + "description": "The parent resource identity.", + "x-ms-skip-url-encoding": true + }, + { + "name": "resourceType", + "in": "path", + "required": true, + "type": "string", + "description": "The resource type of the resource.", + "x-ms-skip-url-encoding": true + }, + { + "name": "resourceName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource to get." + }, + { + "name": "api-version", + "in": "query", + "required": true, + "type": "string", + "description": "The API version to use for the operation." + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns information about the resource.", + "schema": { + "$ref": "#/definitions/GenericResource" + } + } + } + } + }, + "/{resourceId}": { + "head": { + "tags": [ + "Resources" + ], + "operationId": "Resources_CheckExistenceById", + "description": "Checks by ID whether a resource exists.", + "parameters": [ + { + "name": "resourceId", + "in": "path", + "required": true, + "type": "string", + "description": "The fully qualified ID of the resource, including the resource name and resource type. Use the format, /subscriptions/{guid}/resourceGroups/{resource-group-name}/{resource-provider-namespace}/{resource-type}/{resource-name}", + "x-ms-skip-url-encoding": true + }, + { + "name": "api-version", + "in": "query", + "required": true, + "type": "string", + "description": "The API version to use for the operation." + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "tags": [ + "Resources" + ], + "operationId": "Resources_DeleteById", + "description": "Deletes a resource by ID.", + "parameters": [ + { + "name": "resourceId", + "in": "path", + "required": true, + "type": "string", + "description": "The fully qualified ID of the resource, including the resource name and resource type. Use the format, /subscriptions/{guid}/resourceGroups/{resource-group-name}/{resource-provider-namespace}/{resource-type}/{resource-name}", + "x-ms-skip-url-encoding": true + }, + { + "name": "api-version", + "in": "query", + "required": true, + "type": "string", + "description": "The API version to use for the operation." + } + ], + "responses": { + "200": { + "description": "OK" + }, + "204": { + "description": "No Content" + }, + "202": { + "description": "Accepted" + } + }, + "x-ms-long-running-operation": true + }, + "put": { + "tags": [ + "Resources" + ], + "operationId": "Resources_CreateOrUpdateById", + "description": "Create a resource by ID.", + "parameters": [ + { + "name": "resourceId", + "in": "path", + "required": true, + "type": "string", + "description": "The fully qualified ID of the resource, including the resource name and resource type. Use the format, /subscriptions/{guid}/resourceGroups/{resource-group-name}/{resource-provider-namespace}/{resource-type}/{resource-name}", + "x-ms-skip-url-encoding": true + }, + { + "name": "api-version", + "in": "query", + "required": true, + "type": "string", + "description": "The API version to use for the operation." + }, + { + "name": "parameters", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GenericResource" + }, + "description": "Create or update resource parameters." + } + ], + "responses": { + "201": { + "description": "Created - Returns information about the resource.", + "schema": { + "$ref": "#/definitions/GenericResource" + } + }, + "200": { + "description": "OK - Returns information about the resource.", + "schema": { + "$ref": "#/definitions/GenericResource" + } + }, + "202": { + "description": "Accepted" + } + }, + "x-ms-long-running-operation": true + }, + "get": { + "tags": [ + "Resources" + ], + "operationId": "Resources_GetById", + "description": "Gets a resource by ID.", + "parameters": [ + { + "name": "resourceId", + "in": "path", + "required": true, + "type": "string", + "description": "The fully qualified ID of the resource, including the resource name and resource type. Use the format, /subscriptions/{guid}/resourceGroups/{resource-group-name}/{resource-provider-namespace}/{resource-type}/{resource-name}", + "x-ms-skip-url-encoding": true + }, + { + "name": "api-version", + "in": "query", + "required": true, + "type": "string", + "description": "The API version to use for the operation." + } + ], + "responses": { + "200": { + "description": "OK - Returns information about the resource.", + "schema": { + "$ref": "#/definitions/GenericResource" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/tagNames/{tagName}/tagValues/{tagValue}": { + "delete": { + "tags": [ + "Tags" + ], + "operationId": "Tags_DeleteValue", + "description": "Deletes a tag value.", + "parameters": [ + { + "name": "tagName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the tag." + }, + { + "name": "tagValue", + "in": "path", + "required": true, + "type": "string", + "description": "The value of the tag to delete." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK" + }, + "204": { + "description": "No Content" + } + } + }, + "put": { + "tags": [ + "Tags" + ], + "operationId": "Tags_CreateOrUpdateValue", + "description": "Creates a tag value. The name of the tag must already exist.", + "parameters": [ + { + "name": "tagName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the tag." + }, + { + "name": "tagValue", + "in": "path", + "required": true, + "type": "string", + "description": "The value of the tag to create." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns information about the tag value.", + "schema": { + "$ref": "#/definitions/TagValue" + } + }, + "201": { + "description": "Created - Returns information about the tag value.", + "schema": { + "$ref": "#/definitions/TagValue" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/tagNames/{tagName}": { + "put": { + "tags": [ + "Tags" + ], + "operationId": "Tags_CreateOrUpdate", + "summary": "Creates a tag in the subscription.", + "description": "The tag name can have a maximum of 512 characters and is case insensitive. Tag names created by Azure have prefixes of microsoft, azure, or windows. You cannot create tags with one of these prefixes.", + "parameters": [ + { + "name": "tagName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the tag to create." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns information about the tag.", + "schema": { + "$ref": "#/definitions/TagDetails" + } + }, + "201": { + "description": "Created - Returns information about the tag.", + "schema": { + "$ref": "#/definitions/TagDetails" + } + } + } + }, + "delete": { + "tags": [ + "Tags" + ], + "operationId": "Tags_Delete", + "summary": "Deletes a tag from the subscription.", + "description": "You must remove all values from a resource tag before you can delete it.", + "parameters": [ + { + "name": "tagName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the tag." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK" + }, + "204": { + "description": "No Content" + } + } + } + }, + "/subscriptions/{subscriptionId}/tagNames": { + "get": { + "tags": [ + "Tags" + ], + "operationId": "Tags_List", + "description": "Gets the names and values of all resource tags that are defined in a subscription.", + "parameters": [ + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns an array of tag names and values.", + "schema": { + "$ref": "#/definitions/TagsListResult" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/deployments/{deploymentName}/operations/{operationId}": { + "get": { + "tags": [ + "DeploymentOperations" + ], + "operationId": "DeploymentOperations_Get", + "description": "Gets a deployments operation.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "deploymentName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the deployment.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 64 + }, + { + "name": "operationId", + "in": "path", + "required": true, + "type": "string", + "description": "The ID of the operation to get." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Returns information about the deployment operation.", + "schema": { + "$ref": "#/definitions/DeploymentOperation" + } + } + } + } + }, + "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/deployments/{deploymentName}/operations": { + "get": { + "tags": [ + "DeploymentOperations" + ], + "operationId": "DeploymentOperations_List", + "description": "Gets all deployments operations for a deployment.", + "parameters": [ + { + "name": "resourceGroupName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the resource group. The name is case insensitive.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 90 + }, + { + "name": "deploymentName", + "in": "path", + "required": true, + "type": "string", + "description": "The name of the deployment with the operation to get.", + "pattern": "^[-\\w\\._\\(\\)]+$", + "minLength": 1, + "maxLength": 64 + }, + { + "name": "$top", + "in": "query", + "required": false, + "type": "integer", + "format": "int32", + "description": "The number of results to return." + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/SubscriptionIdParameter" + } + ], + "responses": { + "200": { + "description": "OK - Return an array of deployment operations.", + "schema": { + "$ref": "#/definitions/DeploymentOperationsListResult" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + } + }, + "definitions": { + "DeploymentExtendedFilter": { + "properties": { + "provisioningState": { + "type": "string", + "description": "The provisioning state." + } + }, + "description": "Deployment filter." + }, + "GenericResourceFilter": { + "properties": { + "resourceType": { + "type": "string", + "description": "The resource type." + }, + "tagname": { + "type": "string", + "description": "The tag name." + }, + "tagvalue": { + "type": "string", + "description": "The tag value." + } + }, + "description": "Resource filter." + }, + "ResourceGroupFilter": { + "properties": { + "tagName": { + "type": "string", + "description": "The tag name." + }, + "tagValue": { + "type": "string", + "description": "The tag value." + } + }, + "description": "Resource group filter." + }, + "TemplateLink": { + "properties": { + "uri": { + "type": "string", + "description": "The URI of the template to deploy." + }, + "contentVersion": { + "type": "string", + "description": "If included, must match the ContentVersion in the template." + } + }, + "required": [ + "uri" + ], + "description": "Entity representing the reference to the template." + }, + "ParametersLink": { + "properties": { + "uri": { + "type": "string", + "description": "The URI of the parameters file." + }, + "contentVersion": { + "type": "string", + "description": "If included, must match the ContentVersion in the template." + } + }, + "required": [ + "uri" + ], + "description": "Entity representing the reference to the deployment paramaters." + }, + "DeploymentProperties": { + "properties": { + "template": { + "type": "object", + "description": "The template content. You use this element when you want to pass the template syntax directly in the request rather than link to an existing template. It can be a JObject or well-formed JSON string. Use either the templateLink property or the template property, but not both." + }, + "templateLink": { + "$ref": "#/definitions/TemplateLink", + "description": "The URI of the template. Use either the templateLink property or the template property, but not both." + }, + "parameters": { + "type": "object", + "description": "Name and value pairs that define the deployment parameters for the template. You use this element when you want to provide the parameter values directly in the request rather than link to an existing parameter file. Use either the parametersLink property or the parameters property, but not both. It can be a JObject or a well formed JSON string." + }, + "parametersLink": { + "$ref": "#/definitions/ParametersLink", + "description": "The URI of parameters file. You use this element to link to an existing parameters file. Use either the parametersLink property or the parameters property, but not both." + }, + "mode": { + "type": "string", + "description": "The mode that is used to deploy resources. This value can be either Incremental or Complete. In Incremental mode, resources are deployed without deleting existing resources that are not included in the template. In Complete mode, resources are deployed and existing resources in the resource group that are not included in the template are deleted. Be careful when using Complete mode as you may unintentionally delete resources.", + "enum": [ + "Incremental", + "Complete" + ], + "x-ms-enum": { + "name": "DeploymentMode", + "modelAsString": false + } + }, + "debugSetting": { + "$ref": "#/definitions/DebugSetting", + "description": "The debug setting of the deployment." + } + }, + "required": [ + "mode" + ], + "description": "Deployment properties." + }, + "DebugSetting": { + "properties": { + "detailLevel": { + "type": "string", + "description": "Specifies the type of information to log for debugging. The permitted values are none, requestContent, responseContent, or both requestContent and responseContent separated by a comma. The default is none. When setting this value, carefully consider the type of information you are passing in during deployment. By logging information about the request or response, you could potentially expose sensitive data that is retrieved through the deployment operations." + } + } + }, + "Deployment": { + "properties": { + "properties": { + "$ref": "#/definitions/DeploymentProperties", + "description": "The deployment properties." + } + }, + "required": [ + "properties" + ], + "description": "Deployment operation parameters." + }, + "DeploymentExportResult": { + "properties": { + "template": { + "type": "object", + "description": "The template content." + } + }, + "description": "The deployment export result. " + }, + "ResourceManagementErrorWithDetails": { + "properties": { + "code": { + "readOnly": true, + "type": "string", + "description": "The error code returned when exporting the template." + }, + "message": { + "readOnly": true, + "type": "string", + "description": "The error message describing the export error." + }, + "target": { + "readOnly": true, + "type": "string", + "description": "The target of the error." + }, + "details": { + "readOnly": true, + "type": "array", + "items": { + "$ref": "#/definitions/ResourceManagementErrorWithDetails" + }, + "description": "Validation error." + } + } + }, + "AliasPathType": { + "properties": { + "path": { + "type": "string", + "description": "The path of an alias." + }, + "apiVersions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The API versions." + } + }, + "description": "The type of the paths for alias. " + }, + "AliasType": { + "properties": { + "name": { + "type": "string", + "description": "The alias name." + }, + "paths": { + "type": "array", + "items": { + "$ref": "#/definitions/AliasPathType" + }, + "description": "The paths for an alias." + } + }, + "description": "The alias type. " + }, + "ProviderResourceType": { + "properties": { + "resourceType": { + "type": "string", + "description": "The resource type." + }, + "locations": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The collection of locations where this resource type can be created." + }, + "aliases": { + "type": "array", + "items": { + "$ref": "#/definitions/AliasType" + }, + "description": "The aliases that are supported by this resource type." + }, + "apiVersions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The API version." + }, + "properties": { + "type": "object", + "additionalProperties": { + "type": "string", + "description": "The additional properties. " + }, + "description": "The properties." + } + }, + "description": "Resource type managed by the resource provider." + }, + "Provider": { + "properties": { + "id": { + "readOnly": true, + "type": "string", + "description": "The provider ID." + }, + "namespace": { + "type": "string", + "description": "The namespace of the resource provider." + }, + "registrationState": { + "readOnly": true, + "type": "string", + "description": "The registration state of the provider." + }, + "resourceTypes": { + "readOnly": true, + "type": "array", + "items": { + "$ref": "#/definitions/ProviderResourceType" + }, + "description": "The collection of provider resource types." + } + }, + "description": "Resource provider information." + }, + "BasicDependency": { + "properties": { + "id": { + "type": "string", + "description": "The ID of the dependency." + }, + "resourceType": { + "type": "string", + "description": "The dependency resource type." + }, + "resourceName": { + "type": "string", + "description": "The dependency resource name." + } + }, + "description": "Deployment dependency information." + }, + "Dependency": { + "properties": { + "dependsOn": { + "type": "array", + "items": { + "$ref": "#/definitions/BasicDependency" + }, + "description": "The list of dependencies." + }, + "id": { + "type": "string", + "description": "The ID of the dependency." + }, + "resourceType": { + "type": "string", + "description": "The dependency resource type." + }, + "resourceName": { + "type": "string", + "description": "The dependency resource name." + } + }, + "description": "Deployment dependency information." + }, + "DeploymentPropertiesExtended": { + "properties": { + "provisioningState": { + "readOnly": true, + "type": "string", + "description": "The state of the provisioning." + }, + "correlationId": { + "readOnly": true, + "type": "string", + "description": "The correlation ID of the deployment." + }, + "timestamp": { + "readOnly": true, + "type": "string", + "format": "date-time", + "description": "The timestamp of the template deployment." + }, + "outputs": { + "type": "object", + "description": "Key/value pairs that represent deploymentoutput." + }, + "providers": { + "type": "array", + "items": { + "$ref": "#/definitions/Provider" + }, + "description": "The list of resource providers needed for the deployment." + }, + "dependencies": { + "type": "array", + "items": { + "$ref": "#/definitions/Dependency" + }, + "description": "The list of deployment dependencies." + }, + "template": { + "type": "object", + "description": "The template content. Use only one of Template or TemplateLink." + }, + "templateLink": { + "$ref": "#/definitions/TemplateLink", + "description": "The URI referencing the template. Use only one of Template or TemplateLink." + }, + "parameters": { + "type": "object", + "description": "Deployment parameters. Use only one of Parameters or ParametersLink." + }, + "parametersLink": { + "$ref": "#/definitions/ParametersLink", + "description": "The URI referencing the parameters. Use only one of Parameters or ParametersLink." + }, + "mode": { + "type": "string", + "description": "The deployment mode. Possible values are Incremental and Complete.", + "enum": [ + "Incremental", + "Complete" + ], + "x-ms-enum": { + "name": "DeploymentMode", + "modelAsString": false + } + }, + "debugSetting": { + "$ref": "#/definitions/DebugSetting", + "description": "The debug setting of the deployment." + } + }, + "description": "Deployment properties with additional details." + }, + "DeploymentValidateResult": { + "properties": { + "error": { + "$ref": "#/definitions/ResourceManagementErrorWithDetails", + "description": "Validation error." + }, + "properties": { + "$ref": "#/definitions/DeploymentPropertiesExtended", + "description": "The template deployment properties." + } + }, + "description": "Information from validate template deployment response." + }, + "DeploymentExtended": { + "properties": { + "id": { + "type": "string", + "description": "The ID of the deployment." + }, + "name": { + "type": "string", + "description": "The name of the deployment." + }, + "properties": { + "$ref": "#/definitions/DeploymentPropertiesExtended", + "description": "Deployment properties." + } + }, + "required": [ + "name" + ], + "description": "Deployment information." + }, + "DeploymentListResult": { + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/DeploymentExtended" + }, + "description": "An array of deployments." + }, + "nextLink": { + "readOnly": true, + "type": "string", + "description": "The URL to use for getting the next set of results." + } + }, + "description": "List of deployments." + }, + "ProviderListResult": { + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/Provider" + }, + "description": "An array of resource providers." + }, + "nextLink": { + "readOnly": true, + "type": "string", + "description": "The URL to use for getting the next set of results." + } + }, + "description": "List of resource providers." + }, + "GenericResource": { + "properties": { + "plan": { + "$ref": "#/definitions/Plan", + "description": "The plan of the resource." + }, + "properties": { + "type": "object", + "description": "The resource properties." + }, + "kind": { + "type": "string", + "description": "The kind of the resource.", + "pattern": "^[-\\w\\._,\\(\\)]+$" + }, + "managedBy": { + "type": "string", + "description": "ID of the resource that manages this resource." + }, + "sku": { + "$ref": "#/definitions/Sku", + "description": "The SKU of the resource." + }, + "identity": { + "$ref": "#/definitions/Identity", + "description": "The identity of the resource." + } + }, + "allOf": [ + { + "$ref": "#/definitions/Resource" + } + ], + "description": "Resource information." + }, + "Plan": { + "properties": { + "name": { + "type": "string", + "description": "The plan ID." + }, + "publisher": { + "type": "string", + "description": "The publisher ID." + }, + "product": { + "type": "string", + "description": "The offer ID." + }, + "promotionCode": { + "type": "string", + "description": "The promotion code." + } + }, + "description": "Plan for the resource." + }, + "Sku": { + "properties": { + "name": { + "type": "string", + "description": "The SKU name." + }, + "tier": { + "type": "string", + "description": "The SKU tier." + }, + "size": { + "type": "string", + "description": "The SKU size." + }, + "family": { + "type": "string", + "description": "The SKU family." + }, + "model": { + "type": "string", + "description": "The SKU model." + }, + "capacity": { + "type": "integer", + "format": "int32", + "description": "The SKU capacity." + } + }, + "description": "SKU for the resource." + }, + "Identity": { + "properties": { + "principalId": { + "readOnly": true, + "type": "string", + "description": "The principal ID of resource identity." + }, + "tenantId": { + "readOnly": true, + "type": "string", + "description": "The tenant ID of resource." + }, + "type": { + "type": "string", + "description": "The identity type.", + "enum": [ + "SystemAssigned" + ], + "x-ms-enum": { + "name": "ResourceIdentityType", + "modelAsString": false + } + } + }, + "description": "Identity for the resource." + }, + "ResourceListResult": { + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/GenericResource" + }, + "description": "An array of resources." + }, + "nextLink": { + "readOnly": true, + "type": "string", + "description": "The URL to use for getting the next set of results." + } + }, + "description": "List of resource groups." + }, + "ResourceGroup": { + "properties": { + "id": { + "readOnly": true, + "type": "string", + "description": "The ID of the resource group." + }, + "name": { + "type": "string", + "description": "The name of the resource group." + }, + "properties": { + "$ref": "#/definitions/ResourceGroupProperties" + }, + "location": { + "type": "string", + "description": "The location of the resource group. It cannot be changed after the resource group has been created. It muct be one of the supported Azure locations." + }, + "managedBy": { + "type": "string", + "description": "The ID of the resource that manages this resource group." + }, + "tags": { + "type": "object", + "additionalProperties": { + "type": "string", + "description": "The additional properties. " + }, + "description": "The tags attached to the resource group." + } + }, + "required": [ + "location" + ], + "description": "Resource group information." + }, + "ResourceGroupProperties": { + "properties": { + "provisioningState": { + "readOnly": true, + "type": "string", + "description": "The provisioning state. " + } + }, + "description": "The resource group properties." + }, + "ResourceGroupListResult": { + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/ResourceGroup" + }, + "description": "An array of resource groups." + }, + "nextLink": { + "readOnly": true, + "type": "string", + "description": "The URL to use for getting the next set of results." + } + }, + "description": "List of resource groups." + }, + "ResourcesMoveInfo": { + "properties": { + "resources": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The IDs of the resources." + }, + "targetResourceGroup": { + "type": "string", + "description": "The target resource group." + } + }, + "description": "Parameters of move resources." + }, + "ExportTemplateRequest": { + "properties": { + "resources": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The IDs of the resources. The only supported string currently is '*' (all resources). Future updates will support exporting specific resources." + }, + "options": { + "type": "string", + "description": "The export template options. Supported values include 'IncludeParameterDefaultValue', 'IncludeComments' or 'IncludeParameterDefaultValue, IncludeComments" + } + }, + "description": "Export resource group template request parameters." + }, + "TagCount": { + "properties": { + "type": { + "type": "string", + "description": "Type of count." + }, + "value": { + "type": "integer", + "description": "Value of count." + } + }, + "description": "Tag count." + }, + "TagValue": { + "properties": { + "id": { + "type": "string", + "description": "The tag ID." + }, + "tagValue": { + "type": "string", + "description": "The tag value." + }, + "count": { + "$ref": "#/definitions/TagCount", + "description": "The tag value count." + } + }, + "description": "Tag information." + }, + "TagDetails": { + "properties": { + "id": { + "type": "string", + "description": "The tag ID." + }, + "tagName": { + "type": "string", + "description": "The tag name." + }, + "count": { + "$ref": "#/definitions/TagCount", + "description": "The total number of resources that use the resource tag. When a tag is initially created and has no associated resources, the value is 0." + }, + "values": { + "type": "array", + "items": { + "$ref": "#/definitions/TagValue" + }, + "description": "The list of tag values." + } + }, + "description": "Tag details." + }, + "TagsListResult": { + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/TagDetails" + }, + "description": "An array of tags." + }, + "nextLink": { + "readOnly": true, + "type": "string", + "description": "The URL to use for getting the next set of results." + } + }, + "description": "List of subscription tags." + }, + "TargetResource": { + "properties": { + "id": { + "type": "string", + "description": "The ID of the resource." + }, + "resourceName": { + "type": "string", + "description": "The name of the resource." + }, + "resourceType": { + "type": "string", + "description": "The type of the resource." + } + }, + "description": "Target resource." + }, + "HttpMessage": { + "properties": { + "content": { + "type": "object", + "description": "HTTP message content." + } + } + }, + "DeploymentOperationProperties": { + "properties": { + "provisioningState": { + "readOnly": true, + "type": "string", + "description": "The state of the provisioning." + }, + "timestamp": { + "readOnly": true, + "type": "string", + "format": "date-time", + "description": "The date and time of the operation." + }, + "serviceRequestId": { + "readOnly": true, + "type": "string", + "description": "Deployment operation service request id." + }, + "statusCode": { + "readOnly": true, + "type": "string", + "description": "Operation status code." + }, + "statusMessage": { + "readOnly": true, + "type": "object", + "description": "Operation status message." + }, + "targetResource": { + "readOnly": true, + "$ref": "#/definitions/TargetResource", + "description": "The target resource." + }, + "request": { + "readOnly": true, + "$ref": "#/definitions/HttpMessage", + "description": "The HTTP request message." + }, + "response": { + "readOnly": true, + "$ref": "#/definitions/HttpMessage", + "description": "The HTTP response message." + } + }, + "description": "Deployment operation properties." + }, + "DeploymentOperation": { + "properties": { + "id": { + "readOnly": true, + "type": "string", + "description": "Full deployment operation ID." + }, + "operationId": { + "readOnly": true, + "type": "string", + "description": "Deployment operation ID." + }, + "properties": { + "$ref": "#/definitions/DeploymentOperationProperties", + "description": "Deployment properties." + } + }, + "description": "Deployment operation information." + }, + "DeploymentOperationsListResult": { + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/DeploymentOperation" + }, + "description": "An array of deployment operations." + }, + "nextLink": { + "readOnly": true, + "type": "string", + "description": "The URL to use for getting the next set of results." + } + }, + "description": "List of deployment operations." + }, + "ResourceProviderOperationDisplayProperties": { + "properties": { + "publisher": { + "type": "string", + "description": "Operation description." + }, + "provider": { + "type": "string", + "description": "Operation provider." + }, + "resource": { + "type": "string", + "description": "Operation resource." + }, + "operation": { + "type": "string", + "description": "Operation." + }, + "description": { + "type": "string", + "description": "Operation description." + } + }, + "description": "Resource provider operation's display properties." + }, + "Resource": { + "properties": { + "id": { + "readOnly": true, + "type": "string", + "description": "Resource ID" + }, + "name": { + "readOnly": true, + "type": "string", + "description": "Resource name" + }, + "type": { + "readOnly": true, + "type": "string", + "description": "Resource type" + }, + "location": { + "type": "string", + "description": "Resource location" + }, + "tags": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Resource tags" + } + }, + "x-ms-azure-resource": true + }, + "SubResource": { + "properties": { + "id": { + "type": "string", + "description": "Resource ID" + } + }, + "x-ms-azure-resource": true + }, + "ResourceGroupExportResult": { + "properties": { + "template": { + "type": "object", + "description": "The template content." + }, + "error": { + "$ref": "#/definitions/ResourceManagementErrorWithDetails", + "description": "The error." + } + } + } + }, + "parameters": { + "SubscriptionIdParameter": { + "name": "subscriptionId", + "in": "path", + "required": true, + "type": "string", + "description": "The ID of the target subscription." + }, + "ApiVersionParameter": { + "name": "api-version", + "in": "query", + "required": true, + "type": "string", + "description": "The API version to use for this operation." + } + } +} \ No newline at end of file diff --git a/arm-search/2015-02-28/swagger/search.json b/test/swaggers/arm-search/2015-02-28/swagger/search.json similarity index 100% rename from arm-search/2015-02-28/swagger/search.json rename to test/swaggers/arm-search/2015-02-28/swagger/search.json diff --git a/arm-search/2015-08-19/swagger/search.json b/test/swaggers/arm-search/2015-08-19/swagger/search.json similarity index 100% rename from arm-search/2015-08-19/swagger/search.json rename to test/swaggers/arm-search/2015-08-19/swagger/search.json diff --git a/arm-storage/2015-05-01-preview/swagger/storage.json b/test/swaggers/arm-storage/2015-05-01-preview/swagger/storage.json similarity index 100% rename from arm-storage/2015-05-01-preview/swagger/storage.json rename to test/swaggers/arm-storage/2015-05-01-preview/swagger/storage.json diff --git a/arm-storage/2015-06-15/swagger/storage.json b/test/swaggers/arm-storage/2015-06-15/swagger/storage.json similarity index 100% rename from arm-storage/2015-06-15/swagger/storage.json rename to test/swaggers/arm-storage/2015-06-15/swagger/storage.json diff --git a/arm-storage/2016-01-01/examples/storageAccountCheckNameAvailability.json b/test/swaggers/arm-storage/2016-01-01/examples/storageAccountCheckNameAvailability.json similarity index 100% rename from arm-storage/2016-01-01/examples/storageAccountCheckNameAvailability.json rename to test/swaggers/arm-storage/2016-01-01/examples/storageAccountCheckNameAvailability.json diff --git a/arm-storage/2016-01-01/examples/storageAccountCreate.json b/test/swaggers/arm-storage/2016-01-01/examples/storageAccountCreate.json similarity index 100% rename from arm-storage/2016-01-01/examples/storageAccountCreate.json rename to test/swaggers/arm-storage/2016-01-01/examples/storageAccountCreate.json diff --git a/arm-storage/2016-01-01/examples/storageAccountDelete.json b/test/swaggers/arm-storage/2016-01-01/examples/storageAccountDelete.json similarity index 100% rename from arm-storage/2016-01-01/examples/storageAccountDelete.json rename to test/swaggers/arm-storage/2016-01-01/examples/storageAccountDelete.json diff --git a/arm-storage/2016-01-01/examples/storageAccountGetProperties.json b/test/swaggers/arm-storage/2016-01-01/examples/storageAccountGetProperties.json similarity index 100% rename from arm-storage/2016-01-01/examples/storageAccountGetProperties.json rename to test/swaggers/arm-storage/2016-01-01/examples/storageAccountGetProperties.json diff --git a/arm-storage/2016-01-01/examples/storageAccountList.json b/test/swaggers/arm-storage/2016-01-01/examples/storageAccountList.json similarity index 100% rename from arm-storage/2016-01-01/examples/storageAccountList.json rename to test/swaggers/arm-storage/2016-01-01/examples/storageAccountList.json diff --git a/arm-storage/2016-01-01/examples/storageAccountListByRG.json b/test/swaggers/arm-storage/2016-01-01/examples/storageAccountListByRG.json similarity index 100% rename from arm-storage/2016-01-01/examples/storageAccountListByRG.json rename to test/swaggers/arm-storage/2016-01-01/examples/storageAccountListByRG.json diff --git a/arm-storage/2016-01-01/examples/storageAccountListKeys.json b/test/swaggers/arm-storage/2016-01-01/examples/storageAccountListKeys.json similarity index 100% rename from arm-storage/2016-01-01/examples/storageAccountListKeys.json rename to test/swaggers/arm-storage/2016-01-01/examples/storageAccountListKeys.json diff --git a/arm-storage/2016-01-01/examples/storageAccountListUsages.json b/test/swaggers/arm-storage/2016-01-01/examples/storageAccountListUsages.json similarity index 100% rename from arm-storage/2016-01-01/examples/storageAccountListUsages.json rename to test/swaggers/arm-storage/2016-01-01/examples/storageAccountListUsages.json diff --git a/arm-storage/2016-01-01/examples/storageAccountRegenerateKeys.json b/test/swaggers/arm-storage/2016-01-01/examples/storageAccountRegenerateKeys.json similarity index 100% rename from arm-storage/2016-01-01/examples/storageAccountRegenerateKeys.json rename to test/swaggers/arm-storage/2016-01-01/examples/storageAccountRegenerateKeys.json diff --git a/arm-storage/2016-01-01/examples/storageAccountUpdate.json b/test/swaggers/arm-storage/2016-01-01/examples/storageAccountUpdate.json similarity index 100% rename from arm-storage/2016-01-01/examples/storageAccountUpdate.json rename to test/swaggers/arm-storage/2016-01-01/examples/storageAccountUpdate.json diff --git a/arm-storage/2016-01-01/swagger/storage.json b/test/swaggers/arm-storage/2016-01-01/swagger/storage.json similarity index 100% rename from arm-storage/2016-01-01/swagger/storage.json rename to test/swaggers/arm-storage/2016-01-01/swagger/storage.json diff --git a/test/utilsTests.js b/test/utilsTests.js new file mode 100644 index 00000000..5ba67df2 --- /dev/null +++ b/test/utilsTests.js @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +var assert = require('assert'); +var utils = require('../lib/util/utils.js'); + +describe('Utility functions', function () { + describe('Get Provider', function () { + it('should throw on empty', function () { + assert.throws(() => { + utils.getProvider(''); + }) + }); + it('should throw null', function () { + assert.throws(() => { + utils.getProvider(null); + }) + }); + it('should throw undefined', function () { + assert.throws(() => { + utils.getProvider(); + }) + }); + it('should return Microsoft.Resources', function () { + let path = "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/{parentResourcePath}/{resourceType}/{resourceName}" + let provider = utils.getProvider(path); + assert.equal(provider, 'Microsoft.Resources'); + }) + it('should return undefined', function () { + let path = "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/" + let provider = utils.getProvider(path); + assert.equal(provider, undefined); + }) + it('should return Microsoft.Authorization', function () { + let path = "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/{parentResourcePath}/{resourceType}/{resourceName}/providers/Microsoft.Authorization/roleAssignments" + let provider = utils.getProvider(path); + assert.equal(provider, 'Microsoft.Authorization'); + }) + }); +});