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

Commit fbb2375

Browse files
author
Andres
committed
Add support for 'deploy function' command
1 parent 81d34d0 commit fbb2375

File tree

7 files changed

+307
-46
lines changed

7 files changed

+307
-46
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ $ curl http://127.0.0.1:8001/api/v1/namespaces/default/services/hello/proxy/
112112
hello world
113113
```
114114

115+
If you have a change in your function and you want to redeploy it you can run:
116+
```
117+
$ serverless deploy function -f hello
118+
Serverless: Redeploying hello...
119+
Serverless: Function hello succesfully deployed
120+
```
121+
115122
Finally you can remove the function.
116123
```
117124
$ serverless remove

deploy/kubelessDeploy.js

+58-43
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,31 @@ class KubelessDeploy {
8080
);
8181
}
8282

83+
getRuntimeFilenames(runtime, handler) {
84+
let files = null;
85+
if (runtime.match(/python/)) {
86+
files = {
87+
handler: `${handler.toString().split('.')[0]}.py`,
88+
deps: 'requirements.txt',
89+
};
90+
} else if (runtime.match(/node/)) {
91+
files = {
92+
handler: `${handler.toString().split('.')[0]}.js`,
93+
deps: 'package.json',
94+
};
95+
} else if (runtime.match(/ruby/)) {
96+
files = {
97+
handler: `${handler.toString().split('.')[0]}.rb`,
98+
deps: 'Gemfile',
99+
};
100+
} else {
101+
throw new Error(
102+
`The runtime ${runtime} is not supported yet`
103+
);
104+
}
105+
return files;
106+
}
107+
83108
waitForDeployment(funcName, requestMoment) {
84109
const core = new Api.Core(helpers.getConnectionOptions(helpers.loadKubeConfig()));
85110
const loop = setInterval(() => {
@@ -118,38 +143,44 @@ class KubelessDeploy {
118143
}, 2000);
119144
}
120145

146+
deployFunctionAndWait(body, thirdPartyResources) {
147+
const requestMoment = moment().milliseconds(0);
148+
this.serverless.cli.log(
149+
`Deploying function ${body.metadata.name}...`
150+
);
151+
return new BbPromise((resolve, reject) => {
152+
thirdPartyResources.ns.functions.post({ body }, (err) => {
153+
if (err) {
154+
if (err.code === 409) {
155+
this.serverless.cli.log(
156+
`The function ${body.metadata.name} is already deployed. ` +
157+
`If you want to redeploy it execute "sls deploy function -f ${body.metadata.name}".`
158+
);
159+
resolve();
160+
} else {
161+
reject(new Error(
162+
`Unable to deploy the function ${body.metadata.name}. Received:\n` +
163+
` Code: ${err.code}\n` +
164+
` Message: ${err.message}`
165+
));
166+
}
167+
} else {
168+
this.waitForDeployment(body.metadata.name, requestMoment);
169+
resolve();
170+
}
171+
});
172+
});
173+
}
174+
121175
deployFunction() {
122176
const thirdPartyResources = this.getThirdPartyResources();
123177
thirdPartyResources.addResource('functions');
124-
let files = {
125-
handler: null,
126-
deps: null,
127-
};
128178
const errors = [];
129179
let counter = 0;
130180
return new BbPromise((resolve, reject) => {
131181
_.each(this.serverless.service.functions, (description, name) => {
132182
const runtime = this.serverless.service.provider.runtime;
133-
if (runtime.match(/python/)) {
134-
files = {
135-
handler: `${description.handler.toString().split('.')[0]}.py`,
136-
deps: 'requirements.txt',
137-
};
138-
} else if (runtime.match(/node/)) {
139-
files = {
140-
handler: `${description.handler.toString().split('.')[0]}.js`,
141-
deps: 'package.json',
142-
};
143-
} else if (runtime.match(/ruby/)) {
144-
files = {
145-
handler: `${description.handler.toString().split('.')[0]}.rb`,
146-
deps: 'Gemfile',
147-
};
148-
} else {
149-
throw new Error(
150-
`The runtime ${this.serverless.service.provider.runtime} is not supported yet`
151-
);
152-
}
183+
const files = this.getRuntimeFilenames(runtime, description.handler);
153184
this.getFunctionContent(files.handler)
154185
.then(functionContent => {
155186
this.getFunctionContent(files.deps)
@@ -173,25 +204,9 @@ class KubelessDeploy {
173204
type: 'HTTP',
174205
},
175206
};
176-
// Create function
177-
const requestMoment = moment().milliseconds(0);
178-
thirdPartyResources.ns.functions.post({ body: funcs }, (err) => {
179-
if (err) {
180-
if (err.code === 409) {
181-
this.serverless.cli.log(
182-
`The function ${name} is already deployed. ` +
183-
'Remove it if you want to deploy it again.'
184-
);
185-
} else {
186-
errors.push(
187-
`Unable to deploy the function ${name}. Received:\n` +
188-
` Code: ${err.code}\n` +
189-
` Message: ${err.message}`
190-
);
191-
}
192-
} else {
193-
this.waitForDeployment(name, requestMoment);
194-
}
207+
this.deployFunctionAndWait(funcs, thirdPartyResources).catch(err => {
208+
errors.push(err);
209+
}).then(() => {
195210
counter++;
196211
if (counter === _.keys(this.serverless.service.functions).length) {
197212
if (_.isEmpty(errors)) {
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
Copyright 2017 Bitnami.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
'use strict';
18+
19+
const _ = require('lodash');
20+
const BbPromise = require('bluebird');
21+
const KubelessDeploy = require('../deploy/kubelessDeploy');
22+
const moment = require('moment');
23+
24+
class KubelessDeployFunction extends KubelessDeploy {
25+
constructor(serverless, options) {
26+
super(serverless, options);
27+
this.hooks = {
28+
'deploy:function:deploy': () => BbPromise.bind(this)
29+
.then(this.validate)
30+
.then(this.deployFunction),
31+
};
32+
}
33+
34+
deployFunctionAndWait(body, thirdPartyResources) {
35+
const requestMoment = moment().milliseconds(0);
36+
return new BbPromise((resolve, reject) => {
37+
thirdPartyResources.ns.functions(body.metadata.name).put({ body }, (err) => {
38+
if (err) {
39+
reject(new Error(
40+
`Unable to update the function ${body.metadata.name}. Received:\n` +
41+
` Code: ${err.code}\n` +
42+
` Message: ${err.message}`
43+
));
44+
} else {
45+
this.waitForDeployment(body.metadata.name, requestMoment);
46+
resolve();
47+
}
48+
});
49+
});
50+
}
51+
52+
deployFunction() {
53+
// Pick only the funciton that we are interested in
54+
this.serverless.service.functions = _.pick(
55+
this.serverless.service.functions,
56+
this.options.function
57+
);
58+
if (_.isEmpty(this.serverless.service.functions)) {
59+
throw new Error(
60+
`The function ${this.options.function} is not present in the current description`
61+
);
62+
}
63+
this.serverless.cli.log(`Redeploying ${this.options.function}...`);
64+
return super.deployFunction();
65+
}
66+
}
67+
68+
module.exports = KubelessDeployFunction;

index.js

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ whole provider implementation.
2424

2525
const KubelessProvider = require('./provider/kubelessProvider');
2626
const KubelessDeploy = require('./deploy/kubelessDeploy');
27+
const KubelessDeployFunction = require('./deployFunction/kubelessDeployFunction');
2728
const KubelessRemove = require('./remove/kubelessRemove');
2829
const KubelessInvoke = require('./invoke/kubelessInvoke');
2930
const KubelessInfo = require('./info/kubelessInfo');
@@ -36,6 +37,7 @@ class KubelessIndex {
3637

3738
this.serverless.pluginManager.addPlugin(KubelessProvider);
3839
this.serverless.pluginManager.addPlugin(KubelessDeploy);
40+
this.serverless.pluginManager.addPlugin(KubelessDeployFunction);
3941
this.serverless.pluginManager.addPlugin(KubelessRemove);
4042
this.serverless.pluginManager.addPlugin(KubelessInvoke);
4143
this.serverless.pluginManager.addPlugin(KubelessInfo);

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "serverless-kubeless",
3-
"version": "0.1.4",
3+
"version": "0.1.5",
44
"description": "This plugin enables support for Kubeless within the [Serverless Framework](https://github.com/serverless).",
55
"main": "index.js",
66
"directories": {

test/kubelessDeploy.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ describe('KubelessDeploy', () => {
430430
kubelessDeploy.deployFunction()
431431
).to.be.eventually.rejectedWith(
432432
'Found errors while deploying the given functions:\n' +
433-
'Unable to deploy the function myFunction. Received:\n' +
433+
'Error: Unable to deploy the function myFunction. Received:\n' +
434434
' Code: 500\n' +
435435
' Message: Internal server error'
436436
);
@@ -469,7 +469,7 @@ describe('KubelessDeploy', () => {
469469
kubelessDeploy.deployFunction()
470470
).to.be.eventually.rejectedWith(
471471
'Found errors while deploying the given functions:\n' +
472-
'Unable to deploy the function myFunction2. Received:\n' +
472+
'Error: Unable to deploy the function myFunction2. Received:\n' +
473473
' Code: 500\n' +
474474
' Message: Internal server error'
475475
);

0 commit comments

Comments
 (0)