1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | import {
|
18 | Configuration,
|
19 | ConfigurationPostProcessor,
|
20 | guid,
|
21 | logger,
|
22 | } from "@atomist/automation-client";
|
23 | import {
|
24 | ConfigurationValues,
|
25 | SoftwareDeliveryMachine,
|
26 | SoftwareDeliveryMachineConfiguration,
|
27 | validateConfigurationValues,
|
28 | } from "@atomist/sdm";
|
29 | import * as _ from "lodash";
|
30 | import { FulfillGoalOnRequested } from "../../handlers/events/delivery/goals/FulfillGoalOnRequested";
|
31 | import {
|
32 | GoalExecutionAutomationEventListener,
|
33 | GoalExecutionRequestProcessor,
|
34 | } from "../../handlers/events/delivery/goals/goalExecution";
|
35 | import { CacheCleanupAutomationEventListener } from "../../handlers/events/delivery/goals/k8s/CacheCleanupAutomationEventListener";
|
36 | import { defaultSoftwareDeliveryMachineConfiguration } from "../../machine/defaultSoftwareDeliveryMachineConfiguration";
|
37 | import { toArray } from "../../util/misc/array";
|
38 | import { GoalSigningAutomationEventListener } from "../signing/goalSigning";
|
39 | import { SdmGoalMetricReportingAutomationEventListener } from "../util/SdmGoalMetricReportingAutomationEventListener";
|
40 | import {
|
41 | sdmExtensionPackStartupMessage,
|
42 | sdmStartupMessage,
|
43 | } from "../util/startupMessage";
|
44 | import { InvokeSdmStartupListenersAutomationEventListener } from "./InvokeSdmStartupListenersAutomationEventListener";
|
45 | import { LocalSoftwareDeliveryMachineConfiguration } from "./LocalSoftwareDeliveryMachineOptions";
|
46 | import {
|
47 | isGitHubAction,
|
48 | isInLocalMode,
|
49 | } from "./modes";
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 | export interface ConfigureOptions extends ConfigurationValues {
|
56 |
|
57 | }
|
58 |
|
59 |
|
60 |
|
61 |
|
62 | export type SoftwareDeliveryMachineMaker =
|
63 | (configuration: LocalSoftwareDeliveryMachineConfiguration) => SoftwareDeliveryMachine | Promise<SoftwareDeliveryMachine>;
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 | export function configureSdm(machineMaker: SoftwareDeliveryMachineMaker,
|
73 | options: ConfigureOptions = {}): ConfigurationPostProcessor<LocalSoftwareDeliveryMachineConfiguration> {
|
74 |
|
75 | return async (config: Configuration) => {
|
76 | let mergedConfig = config as LocalSoftwareDeliveryMachineConfiguration;
|
77 |
|
78 |
|
79 | mergedConfig = await doWithSdmLocal<LocalSoftwareDeliveryMachineConfiguration>(local => {
|
80 | return local.configureLocal()(mergedConfig);
|
81 | }) || mergedConfig;
|
82 |
|
83 | const defaultSdmConfiguration = defaultSoftwareDeliveryMachineConfiguration(config);
|
84 | mergedConfig = _.merge(defaultSdmConfiguration, mergedConfig);
|
85 |
|
86 | validateConfigurationValues(mergedConfig, options);
|
87 | const sdm = await machineMaker(mergedConfig);
|
88 |
|
89 | await doWithSdmLocal<void>(local =>
|
90 | sdm.addExtensionPacks(local.LocalLifecycle, local.LocalSdmConfig),
|
91 | );
|
92 |
|
93 |
|
94 | await configureJobLaunching(mergedConfig, sdm);
|
95 | configureGoalSigning(mergedConfig);
|
96 |
|
97 | await registerMetadata(mergedConfig, sdm);
|
98 |
|
99 |
|
100 | _.update(mergedConfig, "logging.banner.contributors",
|
101 | old => !!old ? old : []);
|
102 | mergedConfig.logging.banner.contributors.push(
|
103 | sdmStartupMessage(sdm),
|
104 | sdmExtensionPackStartupMessage(sdm));
|
105 |
|
106 | _.update(mergedConfig, "listeners",
|
107 | old => !!old ? old : []);
|
108 | mergedConfig.listeners.push(
|
109 | new InvokeSdmStartupListenersAutomationEventListener(sdm),
|
110 | new SdmGoalMetricReportingAutomationEventListener());
|
111 |
|
112 | return mergedConfig;
|
113 | };
|
114 | }
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 | async function configureJobLaunching(mergedConfig: SoftwareDeliveryMachineConfiguration,
|
122 | machine: SoftwareDeliveryMachine): Promise<void> {
|
123 | const forked = process.env.ATOMIST_ISOLATED_GOAL === "true";
|
124 | if (forked) {
|
125 | configureSdmToRunExactlyOneGoal(mergedConfig, machine);
|
126 | } else {
|
127 |
|
128 | for (const goalScheduler of toArray(mergedConfig.sdm.goalScheduler || [])) {
|
129 | if (!!goalScheduler.initialize) {
|
130 | await goalScheduler.initialize(mergedConfig);
|
131 | }
|
132 | }
|
133 |
|
134 | _.update(mergedConfig, "commands",
|
135 | old => !!old ? old : []);
|
136 | mergedConfig.commands.push(...machine.commandHandlers);
|
137 |
|
138 | _.update(mergedConfig, "events",
|
139 | old => !!old ? old : []);
|
140 | mergedConfig.events.push(...machine.eventHandlers);
|
141 |
|
142 | _.update(mergedConfig, "ingesters",
|
143 | old => !!old ? old : []);
|
144 | mergedConfig.ingesters.push(...machine.ingesters);
|
145 | }
|
146 | }
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 | function configureSdmToRunExactlyOneGoal(mergedConfig: SoftwareDeliveryMachineConfiguration,
|
154 | sdm: SoftwareDeliveryMachine): void {
|
155 | if (process.env.ATOMIST_JOB_NAME) {
|
156 | mergedConfig.name = process.env.ATOMIST_REGISTRATION_NAME;
|
157 | } else {
|
158 | mergedConfig.name = `${mergedConfig.name}-${process.env.ATOMIST_GOAL_ID || guid()}`;
|
159 | }
|
160 |
|
161 |
|
162 | mergedConfig.policy = "ephemeral";
|
163 | mergedConfig.commands = [];
|
164 | mergedConfig.events = [
|
165 | () => new FulfillGoalOnRequested(
|
166 | sdm.goalFulfillmentMapper,
|
167 | [...sdm.goalExecutionListeners])];
|
168 | mergedConfig.ingesters = [];
|
169 | mergedConfig.ws.enabled = false;
|
170 | mergedConfig.cluster.enabled = false;
|
171 |
|
172 | mergedConfig.listeners.push(
|
173 | new GoalExecutionAutomationEventListener(sdm),
|
174 | new CacheCleanupAutomationEventListener(sdm));
|
175 | mergedConfig.requestProcessorFactory =
|
176 | (automations, cfg, listeners) => new GoalExecutionRequestProcessor(automations, cfg, listeners);
|
177 |
|
178 |
|
179 | mergedConfig.applicationEvents.enabled = false;
|
180 | }
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 | function configureGoalSigning(mergedConfig: SoftwareDeliveryMachineConfiguration): void {
|
187 | if (!!mergedConfig.sdm.goalSigning && mergedConfig.sdm.goalSigning.enabled === true) {
|
188 | _.update(mergedConfig, "graphql.listeners",
|
189 | old => !!old ? old : []);
|
190 | mergedConfig.graphql.listeners.push(
|
191 | new GoalSigningAutomationEventListener(mergedConfig.sdm.goalSigning));
|
192 | }
|
193 | }
|
194 |
|
195 | async function registerMetadata(config: Configuration,
|
196 | machine: SoftwareDeliveryMachine): Promise<void> {
|
197 |
|
198 | const sdmPj = require("@atomist/sdm/package.json");
|
199 |
|
200 | const sdmCorePj = require("@atomist/sdm-core/package.json");
|
201 |
|
202 | config.metadata = {
|
203 | ...config.metadata,
|
204 | "atomist.sdm": `${sdmPj.name}:${sdmPj.version}`,
|
205 | "atomist.sdm-core": `${sdmCorePj.name}:${sdmCorePj.version}`,
|
206 | "atomist.sdm.name": machine.name,
|
207 | "atomist.sdm.extension-packs": machine.extensionPacks.map(ex => `${ex.name}:${ex.version}`).join(", "),
|
208 | };
|
209 |
|
210 | config.sdm.name = machine.name;
|
211 |
|
212 | await doWithSdmLocal(() => {
|
213 |
|
214 | const sdmLocalPj = require("@atomist/sdm-local/package.json");
|
215 | config.metadata["atomist.sdm-local"] = `${sdmLocalPj.name}:${sdmLocalPj.version}`;
|
216 | });
|
217 | }
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 | async function doWithSdmLocal<R>(callback: (sdmLocal: any) => any): Promise<R | undefined> {
|
226 | if (isInLocalMode() || isGitHubAction()) {
|
227 |
|
228 | const local = attemptToRequire("@atomist/sdm-local", !process.env.ATOMIST_NPM_LOCAL_LINK);
|
229 | if (local) {
|
230 | return callback(local) as R;
|
231 | } else {
|
232 | logger.warn("Skipping local mode configuration because 'ATOMIST_NPM_LOCAL_LINK' was defined, " +
|
233 | "but '@atomist/sdm-local' could not be loaded");
|
234 | return undefined;
|
235 | }
|
236 | }
|
237 | return undefined;
|
238 | }
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 | function attemptToRequire<T = any>(module: string, failOnError: boolean): T | null {
|
246 | try {
|
247 | return require(module) as T;
|
248 | } catch (err) {
|
249 | if (failOnError) {
|
250 | throw new Error(`Unable to load '${module}'. Please install with 'npm install ${module}'.`);
|
251 | } else {
|
252 | return undefined;
|
253 | }
|
254 | }
|
255 |
|
256 | }
|