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

Commit d8ccca5

Browse files
authored
Merge pull request #107 from andresmgot/kubeless0.4.0
Adapt to Kubeless 0.4
2 parents 22c31fd + 4cf2d79 commit d8ccca5

12 files changed

+282
-136
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ services:
1111
- docker
1212
env:
1313
global:
14-
- KUBELESS_VERSION: 0.3.4
14+
- KUBELESS_VERSION: 0.4.0
1515
- REPO_DOMAIN: serverless
1616
- REPO_NAME: serverless-kubeless
1717
- secure: "s+L8ndj0uMNwqbLvbHePHeMJw2LI8DdEdcq1vJ98hNwHOWQc2mHVB4utG9EZFkaL+RAZYduldSJqr443d2BugxrkmzhLUlM5vDks+zHeKecwTah2uuaMUXVT/y/cWDDTVp3phqSqWbHBMG6u0ImvTVWHpnkux55S3QJTHevvhdodpO6VDTsJCEB3e1d2hHxi0L9tJrFXzQRpooV8IUuODwKBJyhK4CD7rvu0D1gBgHaUNnNLrCy4YTaFl19q5NdZUtrQDC7rpSPOhFI9CBFX8GiFq6nY3XzFASwq/JtKc3K7OLIC7Wqb6JpuvFhG6S1yhBzp73pnoE9U0Bi+YMa3L+nPoh58dCB2ldNCCCMbx7R6PWq/TwYzLvgZZ7queC2kbvCTrtU6JJfmb0CxmX1fnUIpCsNeyXaPuo4Ly6WJeAID32z79CwMo9NH0uOVTLy3LTrLcEfELhBRL5+WkMvKmXUt8yN/jEIa/H38pQN5Y/AnJ0KznO8RZ2nLhi1cR+xUkxfPVZ22Wr2XkbzJDZih/mZR+5GQBfUHWgpUChK+e8dOhplk+4PZJEO6Myja7ykXBPYtL9CV/Xi+1nQqLmfhyChiES201KusJr1IrFklslzCzgrSH8Dv2yaYUTe/Ub/I3gWIhKOXY66gkpmB6MSBJUfMK3uR4/wYfCvbtBTugsY="

deploy/kubelessDeploy.js

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
const _ = require('lodash');
2020
const BbPromise = require('bluebird');
21+
const Config = require('../lib/config');
22+
const crypto = require('crypto');
2123
const deploy = require('../lib/deploy');
2224
const fs = require('fs');
2325
const helpers = require('../lib/helpers');
@@ -86,19 +88,27 @@ class KubelessDeploy {
8688
deployFunction() {
8789
const runtime = this.serverless.service.provider.runtime;
8890
const populatedFunctions = [];
91+
const kubelessConfig = new Config();
8992
return new BbPromise((resolve, reject) => {
90-
_.each(this.serverless.service.functions, (description, name) => {
91-
const pkg = this.options.package ||
92-
this.serverless.service.package.path ||
93-
description.package.artifact ||
94-
this.serverless.config.serverless.service.artifact;
95-
this.checkSize(pkg);
96-
fs.readFile(pkg, { encoding: 'base64' }, (err, functionContent) => {
97-
if (err) {
98-
reject(err);
99-
} else if (description.handler) {
100-
const files = helpers.getRuntimeFilenames(runtime, description.handler);
101-
this.getFileContent(pkg, files.deps)
93+
kubelessConfig.init().then(() => {
94+
_.each(this.serverless.service.functions, (description, name) => {
95+
const pkg = this.options.package ||
96+
this.serverless.service.package.path ||
97+
description.package.artifact ||
98+
this.serverless.config.serverless.service.artifact;
99+
this.checkSize(pkg);
100+
const s = fs.createReadStream(pkg);
101+
const shasum = crypto.createHash('sha256');
102+
let functionContent = '';
103+
s.on('error', (err) => reject(err));
104+
s.on('data', (data) => {
105+
shasum.update(data);
106+
functionContent += data.toString('base64');
107+
});
108+
s.on('end', () => {
109+
if (description.handler) {
110+
const depFile = helpers.getRuntimeDepfile(runtime, kubelessConfig);
111+
this.getFileContent(pkg, depFile)
102112
.catch(() => {
103113
// No requirements found
104114
})
@@ -107,6 +117,7 @@ class KubelessDeploy {
107117
_.assign({}, description, {
108118
id: name,
109119
content: functionContent,
120+
checksum: `sha256:${shasum.digest('hex')}`,
110121
deps: requirementsContent,
111122
image: description.image || this.serverless.service.provider.image,
112123
events: _.map(description.events, (event) => {
@@ -127,12 +138,13 @@ class KubelessDeploy {
127138
resolve();
128139
}
129140
});
130-
} else {
131-
populatedFunctions.push(_.assign({}, description, { id: name }));
132-
if (populatedFunctions.length === _.keys(this.serverless.service.functions).length) {
133-
resolve();
141+
} else {
142+
populatedFunctions.push(_.assign({}, description, { id: name }));
143+
if (populatedFunctions.length === _.keys(this.serverless.service.functions).length) {
144+
resolve();
145+
}
134146
}
135-
}
147+
});
136148
});
137149
});
138150
}).then(() => deploy(

lib/config.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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 helpers = require('./helpers');
21+
const request = require('request');
22+
23+
class Config {
24+
constructor(options) {
25+
const opts = _.defaults({}, options, {
26+
namespace: 'kubeless',
27+
});
28+
this.namespace = opts.namespace;
29+
const APIRootUrl = helpers.getKubernetesAPIURL(helpers.loadKubeConfig());
30+
const url = `${APIRootUrl}/api/v1/namespaces/${opts.namespace}/configmaps/kubeless-config`;
31+
this.connectionOptions = Object.assign(
32+
helpers.getConnectionOptions(helpers.loadKubeConfig()),
33+
{ url, json: true }
34+
);
35+
this.configMag = {};
36+
}
37+
init() {
38+
const data = [];
39+
return new Promise((resolve, reject) => {
40+
request.get(this.connectionOptions)
41+
.on('error', err => {
42+
reject(err);
43+
})
44+
.on('data', (d) => {
45+
data.push(d);
46+
})
47+
.on('end', () => {
48+
const res = Buffer.concat(data).toString();
49+
this.configMag = JSON.parse(res);
50+
resolve();
51+
});
52+
});
53+
}
54+
get(key, opt) {
55+
if (opt && opt.parse) {
56+
return JSON.parse(this.configMag.data[key]);
57+
}
58+
return this.configMag.data[key];
59+
}
60+
}
61+
62+
module.exports = Config;

lib/deploy.js

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ function getFunctionDescription(
3232
deps,
3333
funcContent,
3434
contentType,
35+
checksum,
3536
handler,
3637
desc,
3738
labels,
@@ -45,22 +46,27 @@ function getFunctionDescription(
4546
secrets
4647
) {
4748
const funcs = {
48-
apiVersion: 'k8s.io/v1',
49+
apiVersion: 'kubeless.io/v1beta1',
4950
kind: 'Function',
5051
metadata: {
5152
name: funcName,
5253
namespace,
54+
labels: _.assign({}, labels, {
55+
'created-by': 'kubeless',
56+
function: funcName,
57+
}),
5358
},
5459
spec: {
5560
deps: deps || '',
5661
function: funcContent,
62+
checksum,
5763
'function-content-type': contentType,
5864
handler,
5965
runtime,
6066
timeout: String(timeout || '180'),
6167
service: {
6268
ports: [{
63-
name: 'function-port',
69+
name: 'http-function-port',
6470
port: Number(port || 8080),
6571
protocol: 'TCP',
6672
targetPort: Number(port || 8080),
@@ -77,9 +83,6 @@ function getFunctionDescription(
7783
'kubeless.serverless.com/description': desc,
7884
};
7985
}
80-
if (labels) {
81-
funcs.metadata.labels = labels;
82-
}
8386
if (image || env || memory || secrets) {
8487
const container = {
8588
name: funcName,
@@ -111,19 +114,25 @@ function getFunctionDescription(
111114
requests: { memory: memoryWithSuffix },
112115
};
113116
}
114-
funcs.spec.template = {
115-
spec: { containers: [container] },
117+
funcs.spec.deployment = {
118+
spec: {
119+
template: {
120+
spec: {
121+
containers: [container],
122+
},
123+
},
124+
},
116125
};
117126
if (secrets !== undefined && secrets.length > 0) {
118127
if (container.volumeMounts === undefined) {
119128
container.volumeMounts = [];
120129
}
121-
if (funcs.spec.template.spec.volumes === undefined) {
122-
funcs.spec.template.spec.volumes = [];
130+
if (funcs.spec.deployment.spec.template.spec.volumes === undefined) {
131+
funcs.spec.deployment.spec.template.spec.volumes = [];
123132
}
124133
secrets.forEach(secret => {
125134
container.volumeMounts.push({ name: `${secret}-vol`, mountPath: `/${secret}` });
126-
funcs.spec.template.spec.volumes
135+
funcs.spec.deployment.spec.template.spec.volumes
127136
.push({ name: `${secret}-vol`, secret: { secretName: secret } });
128137
});
129138
}
@@ -342,6 +351,7 @@ function deploy(functions, runtime, options) {
342351
description.deps,
343352
description.content,
344353
options.contentType,
354+
description.checksum,
345355
description.handler,
346356
description.description,
347357
description.labels,

lib/functions.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class Functions {
2727
});
2828
this.namespace = opts.namespace;
2929
const APIRootUrl = helpers.getKubernetesAPIURL(helpers.loadKubeConfig());
30-
const url = `${APIRootUrl}/apis/k8s.io/v1/namespaces/${opts.namespace}/functions/`;
30+
const url = `${APIRootUrl}/apis/kubeless.io/v1beta1/namespaces/${opts.namespace}/functions/`;
3131
this.connectionOptions = Object.assign(
3232
helpers.getConnectionOptions(helpers.loadKubeConfig()),
3333
{ url, json: true }

lib/helpers.js

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -177,29 +177,20 @@ function warnUnsupportedOptions(unsupportedOptions, definedOptions, logFunction)
177177
});
178178
}
179179

180-
function getRuntimeFilenames(runtime, handler) {
181-
let files = null;
182-
if (runtime.match(/python/)) {
183-
files = {
184-
handler: `${handler.toString().split('.')[0]}.py`,
185-
deps: 'requirements.txt',
186-
};
187-
} else if (runtime.match(/node/)) {
188-
files = {
189-
handler: `${handler.toString().split('.')[0]}.js`,
190-
deps: 'package.json',
191-
};
192-
} else if (runtime.match(/ruby/)) {
193-
files = {
194-
handler: `${handler.toString().split('.')[0]}.rb`,
195-
deps: 'Gemfile',
196-
};
197-
} else {
180+
function getRuntimeDepfile(runtime, configMap) {
181+
const runtimesInfo = configMap.get('runtime-images', { parse: true });
182+
let depFile = null;
183+
_.each(runtimesInfo, r => {
184+
if (runtime.match(r.ID)) {
185+
depFile = r.depName;
186+
}
187+
});
188+
if (!depFile) {
198189
throw new Error(
199190
`The runtime ${runtime} is not supported yet`
200191
);
201192
}
202-
return files;
193+
return depFile;
203194
}
204195

205196
module.exports = {
@@ -208,5 +199,5 @@ module.exports = {
208199
getKubernetesAPIURL,
209200
getDefaultNamespace,
210201
getConnectionOptions,
211-
getRuntimeFilenames,
202+
getRuntimeDepfile,
212203
};

package.json

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

0 commit comments

Comments
 (0)