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

Commit

Permalink
added url+zip deploy method (#187)
Browse files Browse the repository at this point in the history
  • Loading branch information
vognev authored and Andres Martinez Gotor committed Sep 24, 2019
1 parent 220117e commit c220233
Show file tree
Hide file tree
Showing 15 changed files with 902 additions and 422 deletions.
66 changes: 28 additions & 38 deletions deploy/kubelessDeploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
const _ = require('lodash');
const BbPromise = require('bluebird');
const Config = require('../lib/config');
const crypto = require('crypto');
const deploy = require('../lib/deploy');
const Strategy = require('../lib/strategy');
const fs = require('fs');
const helpers = require('../lib/helpers');
const JSZip = require('jszip');
Expand Down Expand Up @@ -90,29 +90,23 @@ class KubelessDeploy {
this.serverless.service.package.artifact ||
description.package.artifact ||
this.serverless.config.serverless.service.artifact;

this.checkSize(pkg);
const s = fs.createReadStream(pkg);
const shasum = crypto.createHash('sha256');
let functionContent = '';
s.on('error', (err) => reject(err));
s.on('data', (data) => {
shasum.update(data);
functionContent += data.toString('base64');
});
s.on('end', () => {
if (description.handler) {
const depFile = helpers.getRuntimeDepfile(description.runtime || runtime,
kubelessConfig);
this.getFileContent(pkg, depFile)
.catch(() => {
// No requirements found
})
.then((requirementsContent) => {
populatedFunctions.push(
_.assign({}, description, {

if (description.handler) {
const depFile = helpers.getRuntimeDepfile(description.runtime || runtime,
kubelessConfig);

(new Strategy(this.serverless)).factory().deploy(description, pkg)
.catch(reject)
.then(deployOptions => {
this.getFileContent(pkg, depFile)
.catch(() => {
// No requirements found
})
.then((requirementsContent) => {
populatedFunctions.push(_.assign({}, description, deployOptions, {
id: name,
content: functionContent,
checksum: `sha256:${shasum.digest('hex')}`,
deps: requirementsContent,
image: description.image || this.serverless.service.provider.image,
events: _.map(description.events, (event) => {
Expand All @@ -124,22 +118,19 @@ class KubelessDeploy {
}
return _.assign({ type }, event[type]);
}),
})
);
if (
populatedFunctions.length ===
_.keys(this.serverless.service.functions).length
) {
resolve();
}
});
} else {
populatedFunctions.push(_.assign({}, description, { id: name }));
if (populatedFunctions.length === _.keys(this.serverless.service.functions).length) {
resolve();
}
}));
if (populatedFunctions.length ===
_.keys(this.serverless.service.functions).length) {
resolve();
}
});
});
} else {
populatedFunctions.push(_.assign({}, description, { id: name }));
if (populatedFunctions.length === _.keys(this.serverless.service.functions).length) {
resolve();
}
});
}
});
});
}).then(() => deploy(
Expand All @@ -159,7 +150,6 @@ class KubelessDeploy {
verbose: this.options.verbose,
log: this.serverless.cli.log.bind(this.serverless.cli),
timeout: this.serverless.service.provider.timeout,
contentType: 'base64+zip',
environment: this.serverless.service.provider.environment,
}
));
Expand Down
13 changes: 13 additions & 0 deletions examples/post-php-s3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Simple Hello World function

This function returns the given data capitalizing the first word.

```console
$ npm install
$ serverless deploy
$ serverless invoke -f php-echo -l --data 'hello!'
Serverless: Calling function: php-echo...
--------------------------------------------------------------------
hello!
$ serverless remove
```
6 changes: 6 additions & 0 deletions examples/post-php-s3/handler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

function foo($event, $context) {
return json_encode($event->data);
}

14 changes: 14 additions & 0 deletions examples/post-php-s3/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "php-echo",
"version": "1.0.0",
"description": "Example function for serverless kubeless",
"dependencies": {
"serverless-kubeless": "^0.7.0"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "Apache-2.0"
}
21 changes: 21 additions & 0 deletions examples/post-php-s3/serverless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
service: php-echo-s3

provider:
name: kubeless
runtime: php7.2
deploy:
strategy: S3ZipContent
options:
accessKeyId: minio
secretAccessKey: minio123
endpoint: http://10.98.211.80:9000
bucket: kubeless
region: eu-central-1
s3ForcePathStyle: True

plugins:
- serverless-kubeless

functions:
php-echo-s3:
handler: handler.foo
19 changes: 10 additions & 9 deletions lib/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -536,22 +536,23 @@ function deployTrigger(event, funcName, namespace, service, options) {
}

function deploy(functions, runtime, service, options) {
const opts = _.defaults({}, options, {
hostname: null,
namespace: 'default',
memorySize: null,
force: false,
verbose: false,
log: console.log,
contentType: 'text',
});
const errors = [];
let counter = 0;

// Total number of elements to deploy
const elements = helpers.getDeployableItemsNumber(functions);
return new BbPromise((resolve, reject) => {
_.each(functions, (description) => {
const opts = _.defaults({}, options, {
hostname: null,
namespace: 'default',
memorySize: null,
force: false,
verbose: false,
log: console.log,
contentType: ('contentType' in description) ? description.contentType : 'text',
});

const ns = description.namespace || opts.namespace;
if (description.handler) {
deployFunction(description, ns, runtime, opts.contentType, opts)
Expand Down
48 changes: 48 additions & 0 deletions lib/strategy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Copyright 2017 Bitnami.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

const _ = require('lodash');

const Base64ZipContent = require('./strategy/base64_zip_content');
const S3ZipContent = require('./strategy/s3_zip_content');

const strategies = {
Base64ZipContent,
S3ZipContent,
};

class KubelessDeployStrategy {
constructor(serverless) {
this.serverless = serverless;
}

factory() {
const deploy = _.defaults({}, this.serverless.service.provider.deploy, {
strategy: 'Base64ZipContent',
options: {},
});

if (deploy.strategy in strategies) {
return new strategies[deploy.strategy](this, deploy.options);
}

throw new Error(`Unknown deploy strategy "${deploy.strategy}"`);
}
}

module.exports = KubelessDeployStrategy;
45 changes: 45 additions & 0 deletions lib/strategy/base64_zip_content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
Copyright 2017 Bitnami.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

const crypto = require('crypto');
const fs = require('fs');
const BbPromise = require('bluebird');

class Base64ZipContent {
constructor(strategy, options) {
this.strategy = strategy;
this.options = options;
}

deploy(description, artifact) {
return new BbPromise((resolve) => {
const shasum = crypto.createHash('sha256');
const content = fs.readFileSync(artifact);

shasum.update(content);

resolve({
content: content.toString('base64'),
checksum: `sha256:${shasum.digest('hex')}`,
contentType: 'base64+zip',
});
});
}
}

module.exports = Base64ZipContent;
70 changes: 70 additions & 0 deletions lib/strategy/s3_zip_content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
Copyright 2017 Bitnami.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

const _ = require('lodash');
const crypto = require('crypto');
const fs = require('fs');
const AWS = require('aws-sdk');
const BbPromise = require('bluebird');
const shellescape = require('shell-escape');

class S3ZipContent {
constructor(strategy, options) {
this.strategy = strategy;
this.options = options;
}

deploy(description, artifact) {
const options = _.defaults({}, this.options, {
expires: 60 * 60 * 24 * 365,
});
return new BbPromise((resolve, reject) => {
const shasum = crypto.createHash('sha256');
const content = fs.readFileSync(artifact);
shasum.update(content);

AWS.config.update(options, true);
const s3 = new AWS.S3();
const Key = `${description.name}-${+(new Date())}.zip`;

this.strategy.serverless.cli.log(`Uploading function ${description.name} as ${Key}`);

return s3.putObject({
Key,
Bucket: options.bucket,
Body: fs.readFileSync(artifact),
}).promise()
.then(() => {
const url = s3.getSignedUrl('getObject', {
Key,
Bucket: options.bucket,
Expires: options.expires,
});

// fixme: unescaped url in pkg/utils/kubelessutil.go:82
resolve({
content: shellescape([url]),
checksum: `sha256:${shasum.digest('hex')}`,
contentType: 'url+zip',
});
}, reject);
});
}
}

module.exports = S3ZipContent;
Loading

0 comments on commit c220233

Please sign in to comment.