Skip to content
This repository was archived by the owner on Dec 9, 2024. It is now read-only.

Commit 2ca732a

Browse files
committed
Azure Serverless plugin
1 parent 38fbc52 commit 2ca732a

26 files changed

+3256
-2
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules/
2+
*.dll
3+
.eslintrc.js
4+
.eslintrc.json

.npmignore

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Logs
2+
*.log
3+
npm-debug.log*
4+
5+
# Runtime data
6+
pids
7+
*.pid
8+
*.seed
9+
10+
# Directory for instrumented libs generated by jscoverage/JSCover
11+
lib-cov
12+
13+
# Coverage directory used by tools like istanbul
14+
coverage
15+
16+
# nyc test coverage
17+
.nyc_output
18+
19+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
20+
.grunt
21+
22+
# node-waf configuration
23+
.lock-wscript
24+
25+
# Compiled binary addons (http://nodejs.org/api/addons.html)
26+
build/Release
27+
28+
# Dependency directories
29+
node_modules
30+
jspm_packages
31+
32+
# Optional npm cache directory
33+
.npm
34+
35+
# Optional REPL history
36+
.node_repl_history

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2016 Serverless
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+75-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,75 @@
1-
# serverless-azure-functions
2-
WIP – Coming soon...
1+
# Azure Functions Plugin
2+
3+
This plugin enables Azure Functions support within the Serverless Framework.
4+
5+
## Getting started
6+
7+
8+
### Get a Serverless Service with Azure as the Provider
9+
10+
1. Clone gitrepo: `git clone -b dev https://github.com/pragnagopa/boilerplate-azurefunctions.git`.
11+
2. npm install
12+
13+
### Get an Azure Subscription
14+
- <a href="https://azure.microsoft.com/en-us/free/?b=17.01" target="_blank">Create your free Azure account today</a>
15+
16+
### Create Service Principal User for your Azure subscription
17+
1. Create a Service Principal User with <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal" target="_blank">portal</a> or <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authenticate-service-principal-cli" target="_blank">Azure CLI</a>
18+
2. <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal#get-tenant-id" target="_blank">Get tenant ID</a>
19+
3. <a href="https://blogs.msdn.microsoft.com/mschray/2015/05/13/getting-your-azure-guid-subscription-id/" target="_blank">Get Azure subscription ID</a>
20+
4. <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal#get-application-id-and-authentication-key" target="_blank">Get application ID</a>. Note this is also referred to as the client id.
21+
22+
23+
### Set the following environment variables:
24+
25+
- azureSubId: YourAzureSubscriptionID
26+
- azureServicePrincipalTenantId: servicePrincipalTenantId
27+
- azureservicePrincipalClientId: servicePrincipalClientId
28+
- azureServicePrincipalPassword: servicePrincipalPassword
29+
30+
**Note:** If you created Service Principal User from Portal, servicePrincipalPassword is the authentication key
31+
32+
### Update the config in `serverless.yml`
33+
34+
Open up your `serverless.yml` file and update the following information:
35+
36+
#### `service` property
37+
38+
```yml
39+
service: my-azure-functions-app # Name of the Azure function App you want to create
40+
```
41+
### Quick Start
42+
43+
1. **Deploy a Service:**
44+
45+
Use this when you have made changes to your Functions or you simply want to deploy all changes within your Service at the same time.
46+
```bash
47+
serverless deploy
48+
```
49+
50+
2. **Deploy the Function:**
51+
52+
Use this to quickly upload and overwrite your Azure function, allowing you to develop faster.
53+
```bash
54+
serverless deploy function -f httpjs
55+
```
56+
57+
3. **Invoke the Function:**
58+
59+
Invokes an Azure Function on Azure
60+
```bash
61+
serverless invoke --path httpQueryString.json -f httpjs
62+
```
63+
64+
4. **Stream the Function Logs:**
65+
66+
Open up a separate tab in your console and stream all logs for a specific Function using this command.
67+
```bash
68+
serverless logs -f httpjs -t
69+
```
70+
71+
5. **Remove the Service:**
72+
73+
Removes all Functions and Resources from your Azure subscription.
74+
```bash
75+
serverless remove

deploy/azureDeploy.js

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
'use strict';
2+
3+
const BbPromise = require('bluebird');
4+
const CreateResourceGroupAndFunctionApp = require('./lib/CreateResourceGroupAndFunctionApp');
5+
const createFunctions = require('./lib/createFunctions');
6+
const cleanUpFunctions = require('./lib/cleanUpFunctions');
7+
const loginToAzure = require('../shared/loginToAzure');
8+
9+
class AzureDeploy {
10+
constructor (serverless, options) {
11+
this.serverless = serverless;
12+
this.options = options;
13+
this.provider = this.serverless.getProvider('azure');
14+
15+
Object.assign(
16+
this,
17+
loginToAzure,
18+
cleanUpFunctions,
19+
CreateResourceGroupAndFunctionApp,
20+
createFunctions
21+
);
22+
23+
this.hooks = {
24+
'before:deploy:deploy': () => BbPromise.bind(this)
25+
.then(this.loginToAzure)
26+
.then(this.cleanUpFunctions),
27+
28+
'deploy:deploy': () => BbPromise.bind(this)
29+
.then(this.CreateResourceGroupAndFunctionApp)
30+
.then(this.createFunctions)
31+
.then(() => this.serverless.cli.log('Successfully created Function App'))
32+
};
33+
}
34+
}
35+
36+
module.exports = AzureDeploy;

deploy/azureDeployFunction.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict';
2+
3+
const BbPromise = require('bluebird');
4+
const createFunction = require('./lib/createFunction');
5+
const loginToAzure = require('../shared/loginToAzure');
6+
7+
class AzureDeployFunction {
8+
constructor (serverless, options) {
9+
this.serverless = serverless;
10+
this.options = options;
11+
this.provider = this.serverless.getProvider('azure');
12+
13+
Object.assign(
14+
this,
15+
loginToAzure,
16+
createFunction
17+
);
18+
19+
this.hooks = {
20+
'deploy:function:deploy': () => BbPromise.bind(this)
21+
.then(this.loginToAzure)
22+
.then(this.createFunction)
23+
.then(() => this.serverless.cli.log('Successfully uploaded Function'))
24+
};
25+
}
26+
}
27+
28+
module.exports = AzureDeployFunction;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
'use strict';
2+
3+
module.exports = {
4+
CreateResourceGroupAndFunctionApp () {
5+
6+
return this.provider.CreateResourceGroup()
7+
.then(() => this.provider.CreateFunctionApp());
8+
}
9+
};
10+

deploy/lib/cleanUpFunctions.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
'use strict';
2+
3+
module.exports = {
4+
cleanUpFunctions () {
5+
return this.provider.isExistingFunctionApp()
6+
.then(() => this.provider.getDeployedFunctionsNames())
7+
.then(() => this.provider.cleanUpFunctionsBeforeDeploy(this.serverless.service.getAllFunctions()));
8+
}
9+
};

deploy/lib/createFunction.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
'use strict';
2+
3+
const utils = require('../../shared/utils');
4+
5+
module.exports = {
6+
createFunction () {
7+
const functionName = this.options.function;
8+
const metaData = utils.getFunctionMetaData(functionName, this.provider.getParsedBindings(), this.serverless);
9+
10+
return this.provider.createZipObject(functionName, metaData.entryPoint, metaData.handlerPath, metaData.params)
11+
.then(() => this.provider.createAndUploadZipFunctions());
12+
}
13+
};

deploy/lib/createFunctions.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict';
2+
3+
const BbPromise = require('bluebird');
4+
const utils = require('../../shared/utils');
5+
6+
module.exports = {
7+
createFunctions () {
8+
const createFunctionPromises = [];
9+
10+
this.serverless.service.getAllFunctions().forEach((functionName) => {
11+
const metaData = utils.getFunctionMetaData(functionName, this.provider.getParsedBindings(), this.serverless);
12+
13+
createFunctionPromises.push(this.provider.createZipObject(functionName, metaData.entryPoint, metaData.handlerPath, metaData.params));
14+
});
15+
16+
return BbPromise.all(createFunctionPromises)
17+
.then(() => this.provider.createAndUploadZipFunctions());
18+
}
19+
};

index.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use strict';
2+
3+
/*
4+
NOTE: this plugin is used to add all the differnet provider related plugins at once.
5+
This way only one plugin needs to be added to the service in order to get access to the
6+
whole provider implementation.
7+
*/
8+
9+
const AzureDeploy = require('./deploy/azureDeploy');
10+
const AzureDeployFunction = require('./deploy/azureDeployFunction');
11+
const AzureProvider = require('./provider/azureProvider');
12+
const AzureInvoke = require('./invoke/azureInvoke');
13+
const AzureLogs = require('./logs/azureLogs');
14+
const AzureRemove = require('./remove/azureRemove');
15+
16+
17+
class AzureIndex {
18+
constructor(serverless, options) {
19+
this.serverless = serverless;
20+
this.options = options;
21+
22+
this.serverless.pluginManager.addPlugin(AzureProvider);
23+
this.serverless.pluginManager.addPlugin(AzureDeploy);
24+
this.serverless.pluginManager.addPlugin(AzureDeployFunction);
25+
this.serverless.pluginManager.addPlugin(AzureInvoke);
26+
this.serverless.pluginManager.addPlugin(AzureLogs);
27+
this.serverless.pluginManager.addPlugin(AzureRemove);
28+
}
29+
}
30+
31+
module.exports = AzureIndex;

invoke/azureInvoke.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
3+
const BbPromise = require('bluebird');
4+
const invokeFunction = require('./lib/invokeFunction');
5+
const getAdminKey = require('../shared/getAdminKey');
6+
const loginToAzure = require('../shared/loginToAzure');
7+
const path = require('path');
8+
9+
class AzureInvoke {
10+
constructor (serverless, options) {
11+
this.serverless = serverless;
12+
this.options = options;
13+
this.provider = this.serverless.getProvider('azure');
14+
15+
Object.assign(
16+
this,
17+
loginToAzure,
18+
getAdminKey,
19+
invokeFunction
20+
);
21+
22+
if (this.options.path) {
23+
const absolutePath = path.isAbsolute(this.options.path)
24+
? this.options.path
25+
: path.join(this.serverless.config.servicePath, this.options.path);
26+
27+
if (!this.serverless.utils.fileExistsSync(absolutePath)) {
28+
throw new this.serverless.classes.Error('The file you provided does not exist.');
29+
}
30+
this.options.data = this.serverless.utils.readFileSync(absolutePath);
31+
}
32+
33+
this.hooks = {
34+
35+
'before:invoke:invoke': () => BbPromise.bind(this)
36+
.then(this.loginToAzure)
37+
.then(this.getAdminKey),
38+
39+
'invoke:invoke': () => BbPromise.bind(this)
40+
.then(this.invokeFunction)
41+
};
42+
}
43+
}
44+
45+
module.exports = AzureInvoke;

invoke/lib/invokeFunction.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
'use strict';
2+
3+
module.exports = {
4+
invokeFunction () {
5+
const func = this.options.function;
6+
const functionObject = this.serverless.service.getFunction(func);
7+
const eventType = Object.keys(functionObject.events[0])[0];
8+
9+
return this.provider.invoke(func, eventType, this.options.data);
10+
// TODO: Github issue: https://github.com/Azure/azure-webjobs-sdk-script/issues/1122
11+
// .then(() => this.provider.getInvocationId(func))
12+
// .then(() => this.provider.getLogsForInvocationId());
13+
}
14+
};

logs/azureLogs.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use strict';
2+
3+
const BbPromise = require('bluebird');
4+
const retrieveLogs = require('./lib/retrieveLogs');
5+
const loginToAzure = require('../shared/loginToAzure');
6+
7+
class AzureLogs {
8+
constructor (serverless, options) {
9+
this.serverless = serverless;
10+
this.options = options;
11+
this.provider = this.serverless.getProvider('azure');
12+
13+
Object.assign(
14+
this,
15+
loginToAzure,
16+
retrieveLogs
17+
);
18+
19+
this.hooks = {
20+
'before:logs:logs': () => BbPromise.bind(this)
21+
.then(this.loginToAzure),
22+
23+
'logs:logs': () => BbPromise.bind(this)
24+
.then(this.retrieveLogs)
25+
};
26+
}
27+
}
28+
29+
module.exports = AzureLogs;

logs/lib/retrieveLogs.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use strict';
2+
3+
module.exports = {
4+
retrieveLogs () {
5+
const functionName = this.options.function;
6+
7+
return this.provider.getAdminKey()
8+
.then(() => this.provider.pingHostStatus(functionName))
9+
.then(() => this.provider.getLogsStream(functionName));
10+
}
11+
};

0 commit comments

Comments
 (0)