diff --git a/package-lock.json b/package-lock.json index 90fb83e3..025338f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3491,13 +3491,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3510,18 +3508,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -3624,8 +3619,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -3635,7 +3629,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3648,7 +3641,6 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3748,8 +3740,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -3864,7 +3855,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7000,24 +6990,6 @@ } } }, - "npm-conf": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", - "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", - "dev": true, - "requires": { - "config-chain": "^1.1.11", - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", diff --git a/src/config.ts b/src/config.ts index ba5cf2c6..2d8a8bf5 100644 --- a/src/config.ts +++ b/src/config.ts @@ -13,7 +13,7 @@ export const constants = { scmCommandApiPath: '/api/command', scmDomain: '.scm.azurewebsites.net', scmVfsPath: '/api/vfs/site/wwwroot/', - scmZipApiPath: '/api/zip/site/wwwroot/' + scmZipDeployApiPath: '/api/zipdeploy' }; export default constants; \ No newline at end of file diff --git a/src/plugins/deploy/azureDeployPlugin.ts b/src/plugins/deploy/azureDeployPlugin.ts index c6acbb10..56d5803a 100644 --- a/src/plugins/deploy/azureDeployPlugin.ts +++ b/src/plugins/deploy/azureDeployPlugin.ts @@ -7,28 +7,17 @@ export class AzureDeployPlugin { constructor(private serverless: Serverless, private options: Serverless.Options) { this.hooks = { - 'before:deploy:deploy': this.beforeDeploy.bind(this), 'deploy:deploy': this.deploy.bind(this) }; } - private async beforeDeploy() { - const functionAppService = new FunctionAppService(this.serverless, this.options); - const functionApp = await functionAppService.get(); - - if (functionApp) { - await functionAppService.cleanUp(functionApp); - } - } - private async deploy() { const resourceService = new ResourceService(this.serverless, this.options); await resourceService.deployResourceGroup(); const functionAppService = new FunctionAppService(this.serverless, this.options); - const functionApp = await functionAppService.deploy(); + const functionApp = await functionAppService.deploy(); await functionAppService.uploadFunctions(functionApp); - await functionAppService.syncTriggers(functionApp); } } diff --git a/src/provider/armTemplates/azuredeploy.json b/src/provider/armTemplates/azuredeploy.json index 023ebf55..32df123f 100644 --- a/src/provider/armTemplates/azuredeploy.json +++ b/src/provider/armTemplates/azuredeploy.json @@ -103,6 +103,10 @@ { "name": "WEBSITE_NODE_DEFAULT_VERSION", "value": "8.11.1" + }, + { + "name": "WEBSITE_RUN_FROM_PACKAGE", + "value": "1" } ] } diff --git a/src/services/functionAppService.ts b/src/services/functionAppService.ts index 84f6eeb8..f40e6204 100644 --- a/src/services/functionAppService.ts +++ b/src/services/functionAppService.ts @@ -7,6 +7,7 @@ import jsonpath from 'jsonpath'; import _ from 'lodash'; import Serverless from 'serverless'; import { BaseService } from './baseService'; +import { constants } from '../config'; export class FunctionAppService extends BaseService { private resourceClient: ResourceManagementClient; @@ -79,27 +80,49 @@ export class FunctionAppService extends BaseService { return response.data.value || []; } - public async uploadFunctions(functionApp): Promise { - this.serverless.cli.log('Creating azure functions'); + public async uploadFunctions(functionApp) { + await this.zipDeploy(functionApp); + } - const scmDomain = functionApp.enabledHostNames[0]; + private async zipDeploy(functionApp) { + const functionAppName = functionApp.name; + this.serverless.cli.log(`Deploying zip file to function app: ${functionAppName}`); + + // Upload function artifact if it exists, otherwise the full service is handled in 'uploadFunctions' method const functionZipFile = this.serverless.service['artifact']; + if (!functionZipFile) { + throw new Error('No zip file found for function app'); + } - this.serverless.cli.log(`-> Deploying service package @ ${functionZipFile}`); + this.serverless.cli.log(`-> Uploading ${functionZipFile}`); + const uploadUrl = `https://${functionAppName}${constants.scmDomain}${constants.scmZipDeployApiPath}`; + this.serverless.cli.log(`-> Upload url: ${uploadUrl}`); + + // https://github.com/projectkudu/kudu/wiki/Deploying-from-a-zip-file-or-url const requestOptions = { method: 'POST', - uri: `https://${scmDomain}/api/zipdeploy/`, + uri: uploadUrl, json: true, headers: { Authorization: `Bearer ${this.credentials.tokenCache._entries[0].accessToken}`, - Accept: '*/*' + Accept: '*/*', + ContentType: 'application/octet-stream', } }; - await this.sendFile(requestOptions, functionZipFile); + try { + await this.sendFile(requestOptions, functionZipFile); + this.serverless.cli.log('-> Function package uploaded successfully'); + } catch (e) { + throw new Error(`Error uploading zip file:\n --> ${e}`); + } } + /** + * create all necessary resources as defined in src/provider/armTemplates + * resource-group, storage account, app service plan, and app service at the minimum + */ public async deploy() { this.serverless.cli.log(`Creating function app: ${this.serviceName}`); let parameters: any = { functionAppName: { value: this.serviceName } };