1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const stringify = require("json-stringify-safe");
|
4 | const _ = require("lodash");
|
5 | const ApolloGraphClient_1 = require("../graph/ApolloGraphClient");
|
6 | const HandlerResult_1 = require("../HandlerResult");
|
7 | const NodeConfigSecretResolver_1 = require("../internal/env/NodeConfigSecretResolver");
|
8 | const metadata_1 = require("../internal/metadata/metadata");
|
9 | const metadataReading_1 = require("../internal/metadata/metadataReading");
|
10 | const parameterPopulation_1 = require("../internal/parameterPopulation");
|
11 | const logger_1 = require("../internal/util/logger");
|
12 | const string_1 = require("../internal/util/string");
|
13 | const SmartParameters_1 = require("../SmartParameters");
|
14 | const MetadataProcessor_1 = require("../spi/env/MetadataProcessor");
|
15 | const constructionUtils_1 = require("../util/constructionUtils");
|
16 | const AbstractAutomationServer_1 = require("./AbstractAutomationServer");
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | class BuildableAutomationServer extends AbstractAutomationServer_1.AbstractAutomationServer {
|
22 | constructor(opts) {
|
23 | super();
|
24 | this.opts = opts;
|
25 | this.commandHandlers = [];
|
26 | this.eventHandlers = [];
|
27 | this.ingesters = [];
|
28 | this.secretResolver = new NodeConfigSecretResolver_1.NodeConfigSecretResolver();
|
29 | this.metadataProcessor = new MetadataProcessor_1.PassThroughMetadataProcessor();
|
30 | if (opts.secretResolver) {
|
31 | this.secretResolver = opts.secretResolver;
|
32 | }
|
33 | if (opts.metadataProcessor) {
|
34 | this.metadataProcessor = opts.metadataProcessor;
|
35 | }
|
36 | if (opts.endpoints && opts.endpoints.graphql) {
|
37 | if (opts.workspaceIds || opts.teamIds) {
|
38 | let workspaceIds;
|
39 | if (opts.workspaceIds.length === 1) {
|
40 | workspaceIds = opts.workspaceIds[0];
|
41 | }
|
42 | else if (opts.workspaceIds.length > 1) {
|
43 | workspaceIds = opts.workspaceIds[0];
|
44 | }
|
45 | else if (opts.teamIds.length === 1) {
|
46 | workspaceIds = opts.teamIds[0];
|
47 | }
|
48 | else if (opts.teamIds.length > 1) {
|
49 | workspaceIds = opts.teamIds[0];
|
50 | }
|
51 | if (workspaceIds) {
|
52 | if (opts.token) {
|
53 | this.graphClient = new ApolloGraphClient_1.ApolloGraphClient(`${opts.endpoints.graphql}/${workspaceIds}`, { Authorization: `token ${opts.token}` });
|
54 | }
|
55 | else if (opts.apiKey) {
|
56 | this.graphClient = new ApolloGraphClient_1.ApolloGraphClient(`${opts.endpoints.graphql}/${workspaceIds}`, { Authorization: `Bearer ${opts.apiKey}` });
|
57 | }
|
58 | }
|
59 | }
|
60 | }
|
61 | }
|
62 | registerCommandHandler(chm) {
|
63 | const factory = constructionUtils_1.toFactory(chm);
|
64 | const instanceToInspect = factory();
|
65 | if (instanceToInspect) {
|
66 | const md = metadataReading_1.metadataFromInstance(instanceToInspect);
|
67 | if (!md) {
|
68 | throw new Error(`Cannot get metadata from handler '${stringify(instanceToInspect)}'`);
|
69 | }
|
70 | this.commandHandlers.push({
|
71 | metadata: this.metadataProcessor.process(md, this.opts),
|
72 | invoke: (i, ctx) => {
|
73 | const newHandler = factory();
|
74 | const params = !!newHandler.freshParametersInstance ? newHandler.freshParametersInstance() : newHandler;
|
75 | return this.invokeCommandHandlerWithFreshParametersInstance(newHandler, md, params, i, ctx);
|
76 | },
|
77 | });
|
78 | }
|
79 | return this;
|
80 | }
|
81 | fromCommandHandler(hc) {
|
82 | const md = metadata_1.isCommandHandlerMetadata(hc) ? hc : metadataReading_1.metadataFromInstance(hc);
|
83 | this.commandHandlers.push({
|
84 | metadata: this.metadataProcessor.process(md, this.opts),
|
85 | invoke: (i, ctx) => {
|
86 | const freshParams = !!hc.freshParametersInstance ? hc.freshParametersInstance() : hc;
|
87 | return this.invokeCommandHandlerWithFreshParametersInstance(hc, md, freshParams, i, ctx);
|
88 | },
|
89 | });
|
90 | return this;
|
91 | }
|
92 | registerEventHandler(maker) {
|
93 | const factory = constructionUtils_1.toFactory(maker);
|
94 | const instanceToInspect = factory();
|
95 | if (instanceToInspect) {
|
96 | const md = metadataReading_1.metadataFromInstance(instanceToInspect);
|
97 | if (!md) {
|
98 | throw new Error(`Cannot get metadata from event handler '${stringify(instanceToInspect)}'`);
|
99 | }
|
100 | this.eventHandlers.push({
|
101 | metadata: this.metadataProcessor.process(md, this.opts),
|
102 | invoke: (e, ctx) => this.invokeFreshEventHandlerInstance(factory(), md, e, ctx),
|
103 | });
|
104 | }
|
105 | return this;
|
106 | }
|
107 | registerIngester(ingester) {
|
108 | this.ingesters.push(ingester);
|
109 | return this;
|
110 | }
|
111 | invokeCommandHandler(invocation, metadata, ctx) {
|
112 | const handler = this.commandHandlers.find(a => a.metadata.name === invocation.name);
|
113 | logger_1.logger.info("Invoking command handler '%s'", metadata.name);
|
114 | return handler.invoke(invocation, ctx);
|
115 | }
|
116 | invokeEventHandler(e, metadata, ctx) {
|
117 | const handler = this.eventHandlers.find(a => a.metadata.name === metadata.name);
|
118 | logger_1.logger.info("Invoking event handler '%s'", metadata.name);
|
119 | return handler.invoke(e, ctx);
|
120 | }
|
121 | |
122 |
|
123 |
|
124 | invokeCommandHandlerWithFreshParametersInstance(h, md, params, invocation, ctx) {
|
125 | parameterPopulation_1.populateParameters(params, md, invocation.args);
|
126 | parameterPopulation_1.populateValues(params, md, this.opts);
|
127 | this.populateMappedParameters(params, md, invocation);
|
128 | this.populateSecrets(params, md, invocation.secrets);
|
129 | const bindAndValidate = SmartParameters_1.isSmartParameters(params) ?
|
130 | Promise.resolve(params.bindAndValidate()) :
|
131 | Promise.resolve();
|
132 | return bindAndValidate
|
133 | .then(vr => {
|
134 | if (SmartParameters_1.isValidationError(vr)) {
|
135 | return Promise.reject(`Validation failure invoking command handler '${md.name}': [${vr.message}]`);
|
136 | }
|
137 | const handlerResult = h.handle(this.enrichContext(ctx), params);
|
138 | if (!handlerResult) {
|
139 | return HandlerResult_1.SuccessPromise;
|
140 | }
|
141 | return handlerResult
|
142 | .then(result => {
|
143 | if (result) {
|
144 | return result;
|
145 | }
|
146 | else {
|
147 | return HandlerResult_1.SuccessPromise;
|
148 | }
|
149 | });
|
150 | });
|
151 | }
|
152 | invokeFreshEventHandlerInstance(h, metadata, e, ctx) {
|
153 | this.populateSecrets(h, metadata, e.secrets);
|
154 | parameterPopulation_1.populateValues(h, metadata, this.opts);
|
155 | const handlerResult = h.handle(e, this.enrichContext(ctx), h);
|
156 | if (!handlerResult) {
|
157 | return HandlerResult_1.SuccessPromise;
|
158 | }
|
159 | return handlerResult
|
160 | .then(result => {
|
161 | if (result) {
|
162 | return result;
|
163 | }
|
164 | else {
|
165 | return HandlerResult_1.SuccessPromise;
|
166 | }
|
167 | });
|
168 | }
|
169 | enrichContext(ctx) {
|
170 | ctx.graphClient = ctx.graphClient || this.graphClient;
|
171 | return ctx;
|
172 | }
|
173 | populateMappedParameters(h, metadata, invocation) {
|
174 |
|
175 | class InvocationSecretResolver {
|
176 | constructor(mp) {
|
177 | this.mp = mp;
|
178 | }
|
179 | resolve(key) {
|
180 | const value = this.mp.find(a => a.name === key);
|
181 | if (value) {
|
182 | return String(value.value);
|
183 | }
|
184 | throw new Error(`Cannot resolve mapped parameter '${key}'`);
|
185 | }
|
186 | }
|
187 |
|
188 |
|
189 |
|
190 |
|
191 | const mrResolver = invocation.mappedParameters ?
|
192 | new InvocationSecretResolver(invocation.mappedParameters) :
|
193 | this.secretResolver;
|
194 |
|
195 | const mappedParameters = metadata.mapped_parameters || [];
|
196 | const invMps = invocation.mappedParameters || [];
|
197 | mappedParameters.forEach(mp => {
|
198 | if (invMps.some(im => im.name === mp.name) || mp.required) {
|
199 | _.update(h, mp.name, () => mrResolver.resolve(mp.name));
|
200 | }
|
201 | });
|
202 | }
|
203 | populateSecrets(h, metadata, invocationSecrets) {
|
204 |
|
205 | class InvocationSecretResolver {
|
206 | constructor(sec) {
|
207 | this.sec = sec;
|
208 | }
|
209 | resolve(key) {
|
210 | const value = this.sec.find(a => a.uri === key);
|
211 | if (value) {
|
212 | return String(value.value);
|
213 | }
|
214 | throw new Error(`Cannot resolve secret '${key}'`);
|
215 | }
|
216 | }
|
217 | const secretResolver = invocationSecrets ? new InvocationSecretResolver(invocationSecrets) :
|
218 | this.secretResolver;
|
219 |
|
220 | const secrets = metadata.secrets || [];
|
221 | secrets.forEach(s => {
|
222 | _.update(h, s.name, () => secretResolver.resolve(s.uri));
|
223 | });
|
224 | }
|
225 | get automations() {
|
226 | return {
|
227 | name: this.opts.name,
|
228 | version: this.opts.version,
|
229 | policy: this.opts.policy,
|
230 | team_ids: this.opts.workspaceIds && this.opts.workspaceIds.length > 0 ? this.opts.workspaceIds : this.opts.teamIds,
|
231 | groups: string_1.toStringArray(this.opts.groups),
|
232 | keywords: this.opts.keywords,
|
233 | commands: this.commandHandlers.map(e => e.metadata),
|
234 | events: this.eventHandlers.map(e => e.metadata),
|
235 | ingesters: this.ingesters,
|
236 | };
|
237 | }
|
238 | }
|
239 | exports.BuildableAutomationServer = BuildableAutomationServer;
|
240 |
|
\ | No newline at end of file |