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

Commit

Permalink
Move logic into library files
Browse files Browse the repository at this point in the history
  • Loading branch information
Andres committed Sep 12, 2017
1 parent 1e3eae4 commit 201066d
Show file tree
Hide file tree
Showing 20 changed files with 1,854 additions and 1,679 deletions.
459 changes: 40 additions & 419 deletions deploy/kubelessDeploy.js

Large diffs are not rendered by default.

141 changes: 6 additions & 135 deletions info/kubelessInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,10 @@
'use strict';

const _ = require('lodash');
const Api = require('kubernetes-client');
const BbPromise = require('bluebird');
const chalk = require('chalk');
const getInfo = require('../lib/get-info');
const helpers = require('../lib/helpers');

function toMultipleWords(word) {
return word.replace(/([A-Z])/, ' $1').replace(/^./, (l) => l.toUpperCase());
}

class KubelessInfo {
constructor(serverless, options) {
this.serverless = serverless;
Expand Down Expand Up @@ -62,136 +57,12 @@ class KubelessInfo {
return BbPromise.resolve();
}

formatMessage(service, f, options) {
if (options && !options.color) chalk.enabled = false;
let message = '';
message += `\n${chalk.yellow.underline(`Service Information "${service.name}"`)}\n`;
message += `${chalk.yellow('Cluster IP: ')} ${service.ip}\n`;
message += `${chalk.yellow('Type: ')} ${service.type}\n`;
message += `${chalk.yellow('Ports: ')}\n`;
_.each(service.ports, (port) => {
// Ports can have variable properties
_.each(port, (value, key) => {
message += ` ${chalk.yellow(`${toMultipleWords(key)}: `)} ${value}\n`;
});
});
if (this.options.verbose) {
message += `${chalk.yellow('Metadata')}\n`;
message += ` ${chalk.yellow('Self Link: ')} ${service.selfLink}\n`;
message += ` ${chalk.yellow('UID: ')} ${service.uid}\n`;
message += ` ${chalk.yellow('Timestamp: ')} ${service.timestamp}\n`;
}
message += `${chalk.yellow.underline('Function Info')}\n`;
if (f.url) {
message += `${chalk.yellow('URL: ')} ${f.url}\n`;
}
if (f.annotations && f.annotations['kubeless.serverless.com/description']) {
message += `${chalk.yellow('Description:')} ` +
`${f.annotations['kubeless.serverless.com/description']}\n`;
}
if (f.labels) {
message += `${chalk.yellow('Labels:\n')}`;
_.each(f.labels, (v, k) => {
message += `${chalk.yellow(` ${k}:`)} ${v}\n`;
});
}
message += `${chalk.yellow('Handler: ')} ${f.handler}\n`;
message += `${chalk.yellow('Runtime: ')} ${f.runtime}\n`;
if (f.type === 'PubSub' && !_.isEmpty(f.topic)) {
message += `${chalk.yellow('Topic Trigger:')} ${f.topic}\n`;
} else {
message += `${chalk.yellow('Trigger: ')} ${f.type}\n`;
}
message += `${chalk.yellow('Dependencies: ')} ${f.deps}`;
if (this.options.verbose) {
message += `\n${chalk.yellow('Metadata:')}\n`;
message += ` ${chalk.yellow('Self Link: ')} ${f.selfLink}\n`;
message += ` ${chalk.yellow('UID: ')} ${f.uid}\n`;
message += ` ${chalk.yellow('Timestamp: ')} ${f.timestamp}`;
}
return message;
}

infoFunction(options) {
let counter = 0;
let message = '';
return new BbPromise((resolve) => {
_.each(this.serverless.service.functions, (desc, f) => {
const connectionOptions = helpers.getConnectionOptions(helpers.loadKubeConfig(), {
namespace: desc.namespace || this.serverless.service.provider.namespace,
});
const core = new Api.Core(connectionOptions);
const thirdPartyResources = new Api.ThirdPartyResources(connectionOptions);
const extensions = new Api.Extensions(connectionOptions);
thirdPartyResources.addResource('functions');
core.services.get((err, servicesInfo) => {
if (err) throw new this.serverless.classes.Error(err);
thirdPartyResources.ns.functions.get((ferr, functionsInfo) => {
if (ferr) throw new this.serverless.classes.Error(ferr);
extensions.ns.ingress.get((ierr, ingressInfo) => {
if (ierr) throw this.serverless.classes.Error(ierr);
const fDesc = _.find(functionsInfo.items, item => item.metadata.name === f);
const functionService = _.find(
servicesInfo.items,
(service) => (
service.metadata.labels &&
service.metadata.labels.function === f
)
);
if (_.isEmpty(functionService) || _.isEmpty(fDesc)) {
this.serverless.cli.consoleLog(
`Not found any information about the function "${f}"`
);
} else {
const fIngress = _.find(ingressInfo.items, item => (
item.metadata.labels && item.metadata.labels.function === f
));
let url = null;
if (fIngress) {
url = `${fIngress.spec.rules[0].host || 'API_URL'}` +
`${fIngress.spec.rules[0].http.paths[0].path}`;
}
const service = {
name: functionService.metadata.name,
ip: functionService.spec.clusterIP,
type: functionService.spec.type,
ports: functionService.spec.ports,
selfLink: functionService.metadata.selfLink,
uid: functionService.metadata.uid,
timestamp: functionService.metadata.creationTimestamp,
};
const func = {
name: f,
url,
handler: fDesc.spec.handler,
runtime: fDesc.spec.runtime,
topic: fDesc.spec.topic,
type: fDesc.spec.type,
deps: fDesc.spec.deps,
annotations: fDesc.metadata.annotations,
labels: fDesc.metadata.labels,
selfLink: fDesc.metadata.selfLink,
uid: fDesc.metadata.uid,
timestamp: fDesc.metadata.creationTimestamp,
};
message += this.formatMessage(
service,
func,
_.defaults({}, options, { color: true })
);
}
counter++;
if (counter === _.keys(this.serverless.service.functions).length) {
if (!_.isEmpty(message)) {
this.serverless.cli.consoleLog(message);
}
resolve(message);
}
});
});
});
});
});
return getInfo(this.serverless.service.functions, _.defaults({}, options, {
namespace: this.serverless.service.provider.namespace,
verbose: this.options.verbose,
log: this.serverless.cli.consoleLog,
}));
}
}

Expand Down
102 changes: 12 additions & 90 deletions invoke/kubelessInvoke.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 path = require('path');
const request = require('request');
const helpers = require('../lib/helpers');
const invoke = require('../lib/invoke');

class KubelessInvoke {
constructor(serverless, options) {
Expand All @@ -36,46 +36,7 @@ class KubelessInvoke {
};
}

getData(data) {
let result = null;
const d = data || this.options.data;
try {
if (!_.isEmpty(d)) {
try {
// Try to parse data as JSON
result = {
body: JSON.parse(d),
json: true,
};
} catch (e) {
// Assume data is a string
result = {
body: d,
};
}
} else if (this.options.path) {
const absolutePath = path.isAbsolute(this.options.path) ?
this.options.path :
path.join(this.serverless.config.servicePath, this.options.path);
if (!this.serverless.utils.fileExistsSync(absolutePath)) {
throw new this.serverless.classes.Error('The file you provided does not exist.');
}
result = {
body: this.serverless.utils.readFileSync(absolutePath),
json: true,
};
}
} catch (e) {
throw new this.serverless.classes.Error(
`Unable to parse data given in the arguments: \n${e.message}`
);
}
return result;
}

validate() {
// Parse data to ensure it has a correct format
this.getData();
const unsupportedOptions = ['stage', 'region', 'type'];
helpers.warnUnsupportedOptions(
unsupportedOptions,
Expand All @@ -93,58 +54,19 @@ class KubelessInvoke {
invokeFunction(func, data) {
const f = func || this.options.function;
this.serverless.cli.log(`Calling function: ${f}...`);
const config = helpers.loadKubeConfig();
const APIRootUrl = helpers.getKubernetesAPIURL(config);
const namespace = this.serverless.service.functions[f].namespace ||
this.serverless.service.provider.namespace ||
helpers.getDefaultNamespace(config);
const url = `${APIRootUrl}/api/v1/proxy/namespaces/${namespace}/services/${f}/`;
const connectionOptions = Object.assign(
helpers.getConnectionOptions(helpers.loadKubeConfig()),
{ url }
);
const requestData = this.getData(data);
if (this.serverless.service.functions[f].sequence) {
let promise = null;
_.each(this.serverless.service.functions[f].sequence.slice(), sequenceFunction => {
if (promise) {
promise = promise.then(
result => this.invokeFunction(sequenceFunction, result.body)
);
} else {
promise = this.invokeFunction(sequenceFunction, data);
}
});
return new BbPromise((resolve, reject) => promise.then(
(response) => resolve(response),
err => reject(err)
));
let dataPath = this.options.path;
if (dataPath && !path.isAbsolute(dataPath)) {
dataPath = path.join(this.serverless.config.servicePath, dataPath);
}
return new BbPromise((resolve, reject) => {
const parseReponse = (err, response) => {
if (err) {
reject(new this.serverless.classes.Error(err.message, err.statusCode));
} else {
if (response.statusCode !== 200) {
reject(new this.serverless.classes.Error(response.statusMessage, response.statusCode));
}
resolve(response);
}
};
if (_.isEmpty(requestData)) {
// There is no data to send, sending a GET request
request.get(connectionOptions, parseReponse);
} else {
// Sending request data with a POST
request.post(
Object.assign(
connectionOptions,
requestData
),
parseReponse
);
return invoke(
f,
data || this.options.data,
_.map(this.serverless.service.functions, (desc, ff) => _.assign({}, desc, { id: ff })),
{
namespace: this.serverless.service.provider.namespace,
path: dataPath,
}
});
);
}

log(response) {
Expand Down
Loading

0 comments on commit 201066d

Please sign in to comment.