UNPKG

4.55 kBJavaScriptView Raw
1'use strict';
2
3const BbPromise = require('bluebird');
4const chalk = require('chalk');
5const path = require('path');
6
7const CmdLineParamsOptions = {
8 type: ['blocking', 'nonblocking'],
9 log: ['result', 'response'],
10};
11
12class OpenWhiskInvoke {
13 constructor(serverless, options) {
14 this.serverless = serverless;
15 this.options = options || {};
16 this.provider = this.serverless.getProvider('openwhisk');
17
18 this.hooks = {
19 'invoke:invoke': () => BbPromise.bind(this)
20 .then(this.validate)
21 .then(this.invoke)
22 .then(this.log),
23 };
24 }
25
26 validate() {
27 if (!this.serverless.config.servicePath) {
28 throw new this.serverless.classes.Error('This command can only be run inside a service.');
29 }
30
31 this.serverless.service.getFunction(this.options.function);
32
33 if (this.options.path) {
34 if (!this.serverless.utils
35 .fileExistsSync(path.join(this.serverless.config.servicePath, this.options.path))) {
36 throw new this.serverless.classes.Error('The file path you provided does not exist.');
37 }
38
39 this.options.data = this.serverless.utils
40 .readFileSync(path.join(this.serverless.config.servicePath, this.options.path));
41
42 if (this.options.data == null || typeof this.options.data !== 'object') {
43 throw new this.serverless.classes.Error(
44 'The file path provided must point to a JSON file with a top-level JSON object definition.'
45 );
46 }
47 } else if (this.options.data) {
48 try {
49 this.options.data = JSON.parse(this.options.data)
50 } catch (e) {
51 throw new this.serverless.classes.Error(
52 'Error parsing data parameter as JSON.'
53 );
54 }
55 if (this.options.data == null || typeof this.options.data !== 'object') throw new this.serverless.classes.Error('Data parameter must be a JSON object')
56 }
57
58 this.validateParamOptions();
59
60 return this.provider.client().then(client => {
61 this.client = client;
62 });
63 }
64
65 // ensure command-line parameter values is a valid option.
66 validateParamOptions() {
67 Object.keys(CmdLineParamsOptions).forEach(key => {
68 if (!this.options[key]) {
69 this.options[key] = CmdLineParamsOptions[key][0];
70 } else if (!CmdLineParamsOptions[key].find(i => i === this.options[key])) {
71 const options = CmdLineParamsOptions[key].join(' or ');
72 throw new this.serverless.classes.Error(
73 `Invalid ${key} parameter value, must be either ${options}.`
74 );
75 }
76 });
77 }
78
79 invoke() {
80 const functionObject = this.serverless.service.getFunction(this.options.function);
81
82 const options = {
83 blocking: this.isBlocking(),
84 actionName: functionObject.name
85 || `${this.serverless.service.service}_${this.options.function}`,
86 };
87
88 if (functionObject.namespace) {
89 options.namespace = functionObject.namespace;
90 }
91
92 if (this.options.data) {
93 options.params = this.options.data;
94 }
95
96 return this.client.actions.invoke(options)
97 .catch(err => this.formatErrMsg(err));
98 }
99
100 formatErrMsg (err) {
101 let err_msg = `Failed to invoke function service (${this.options.function}) due to error:`
102 const base_err = err.error
103 if (base_err.response && base_err.response.result && typeof base_err.response.result.error === 'string') {
104 err.message = base_err.response.result.error
105 err_msg = `Failed to invoke function service (${this.options.function}) due to application error:`
106 const logs_msg = ` Check logs for activation: ${base_err.activationId}`
107 throw new this.serverless.classes.Error(`${err_msg}\n\n ${err.message}\n\n ${logs_msg}`)
108 }
109
110 throw new this.serverless.classes.Error(`${err_msg}\n\n ${err.message}`)
111 }
112
113 isBlocking() {
114 return this.options.type === 'blocking';
115 }
116
117 isLogResult() {
118 return this.options.log === 'result';
119 }
120
121 log(invocationReply) {
122 let color = 'white';
123
124 // error response indicated in-blocking call boolean parameter, success.
125 if (this.isBlocking() && !invocationReply.response.success) {
126 color = 'red';
127 }
128
129 let result = invocationReply;
130
131 // blocking invocation result available as 'response.result' parameter
132 if (this.isBlocking() && this.isLogResult()) {
133 result = invocationReply.response.result;
134 }
135
136 this.consoleLog(chalk[color](JSON.stringify(result, null, 4)));
137 return BbPromise.resolve();
138 }
139
140 consoleLog(msg) {
141 console.log(msg); // eslint-disable-line no-console
142 }
143}
144
145module.exports = OpenWhiskInvoke;