pepr 0.52.3 → 0.53.0-nightly.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/cli/banner.d.ts +1 -1
  2. package/dist/cli/banner.d.ts.map +1 -1
  3. package/dist/cli/build/build.helpers.d.ts +1 -1
  4. package/dist/cli/build/build.helpers.d.ts.map +1 -1
  5. package/dist/cli/build/buildModule.d.ts +1 -2
  6. package/dist/cli/build/buildModule.d.ts.map +1 -1
  7. package/dist/cli/build/index.d.ts.map +1 -1
  8. package/dist/cli/deploy/buildAndDeploy.d.ts +5 -0
  9. package/dist/cli/deploy/buildAndDeploy.d.ts.map +1 -0
  10. package/dist/cli/deploy/imagePullSecret.d.ts +16 -0
  11. package/dist/cli/deploy/imagePullSecret.d.ts.map +1 -0
  12. package/dist/cli/deploy/index.d.ts +3 -0
  13. package/dist/cli/deploy/index.d.ts.map +1 -0
  14. package/dist/cli/deploy/userConfirmation.d.ts +4 -0
  15. package/dist/cli/deploy/userConfirmation.d.ts.map +1 -0
  16. package/dist/cli/dev.d.ts.map +1 -1
  17. package/dist/cli/init/createProjectFiles.d.ts +3 -0
  18. package/dist/cli/init/createProjectFiles.d.ts.map +1 -0
  19. package/dist/cli/init/doPostInitActions.d.ts +2 -0
  20. package/dist/cli/init/doPostInitActions.d.ts.map +1 -0
  21. package/dist/cli/init/index.d.ts +1 -1
  22. package/dist/cli/init/index.d.ts.map +1 -1
  23. package/dist/cli/init/setupProjectStructure.d.ts +2 -0
  24. package/dist/cli/init/setupProjectStructure.d.ts.map +1 -0
  25. package/dist/cli/init/templates.d.ts +9 -9
  26. package/dist/cli/init/templates.d.ts.map +1 -1
  27. package/dist/cli/init/walkthrough.d.ts.map +1 -1
  28. package/dist/cli.js +260 -229
  29. package/dist/controller.js +1 -1
  30. package/dist/lib/assets/assets.d.ts.map +1 -1
  31. package/dist/lib/assets/loader.d.ts.map +1 -1
  32. package/dist/lib/assets/webhooks.d.ts +5 -1
  33. package/dist/lib/assets/webhooks.d.ts.map +1 -1
  34. package/dist/lib/assets/yaml/overridesFile.d.ts +1 -0
  35. package/dist/lib/assets/yaml/overridesFile.d.ts.map +1 -1
  36. package/dist/lib/controller/index.d.ts.map +1 -1
  37. package/dist/lib/types.d.ts +7 -0
  38. package/dist/lib/types.d.ts.map +1 -1
  39. package/dist/lib.js +1 -0
  40. package/dist/lib.js.map +2 -2
  41. package/package.json +16 -16
  42. package/src/cli/banner.ts +25 -59
  43. package/src/cli/build/build.helpers.ts +3 -9
  44. package/src/cli/build/buildModule.ts +1 -1
  45. package/src/cli/build/index.ts +9 -5
  46. package/src/cli/deploy/buildAndDeploy.ts +48 -0
  47. package/src/cli/deploy/imagePullSecret.ts +68 -0
  48. package/src/cli/deploy/index.ts +40 -0
  49. package/src/cli/deploy/userConfirmation.ts +16 -0
  50. package/src/cli/dev.ts +6 -5
  51. package/src/cli/init/createProjectFiles.ts +48 -0
  52. package/src/cli/init/doPostInitActions.ts +26 -0
  53. package/src/cli/init/index.ts +18 -84
  54. package/src/cli/init/setupProjectStructure.ts +8 -0
  55. package/src/cli/init/templates.ts +2 -4
  56. package/src/cli/init/walkthrough.ts +3 -0
  57. package/src/cli/kfc.ts +2 -2
  58. package/src/cli/monitor.ts +6 -6
  59. package/src/cli.ts +5 -5
  60. package/src/lib/assets/assets.ts +5 -1
  61. package/src/lib/assets/k8sObjects.ts +6 -6
  62. package/src/lib/assets/loader.ts +0 -6
  63. package/src/lib/assets/webhooks.ts +58 -9
  64. package/src/lib/assets/yaml/overridesFile.ts +29 -7
  65. package/src/lib/controller/index.ts +1 -0
  66. package/src/lib/types.ts +7 -0
  67. package/dist/cli/deploy.d.ts +0 -21
  68. package/dist/cli/deploy.d.ts.map +0 -1
  69. package/src/cli/deploy.ts +0 -170
@@ -27,7 +27,7 @@ import { storeRole, storeRoleBinding, clusterRoleBinding, serviceAccount } from
27
27
  import { tlsSecret, apiPathSecret } from "./networking";
28
28
  import { WebhookType } from "../enums";
29
29
  import { kind } from "kubernetes-fluent-client";
30
-
30
+ import Log from "../telemetry/logger";
31
31
  export function norWatchOrAdmission(capabilities: CapabilityExport[]): boolean {
32
32
  return !isAdmission(capabilities) && !isWatcher(capabilities);
33
33
  }
@@ -134,6 +134,10 @@ export class Assets {
134
134
  imagePullSecret?: string,
135
135
  ): Promise<string> => {
136
136
  this.capabilities = await loadCapabilities(this.path);
137
+ this.capabilities.flatMap(capability => {
138
+ Log.info(`Module ${this.config.uuid} has capability: ${capability.name}`);
139
+ Log.info(`Registered Pepr Capability "${capability.name}"`);
140
+ });
137
141
  // give error if namespaces are not respected
138
142
  for (const capability of this.capabilities) {
139
143
  // until deployment, Pepr does not distinguish between watch and admission
@@ -85,9 +85,9 @@ export function getWatcher(
85
85
  serviceAccountName: name,
86
86
  securityContext: {
87
87
  runAsUser: image.includes("private") ? 1000 : 65532,
88
- runAsGroup: 65532,
88
+ runAsGroup: image.includes("private") ? 1000 : 65532,
89
89
  runAsNonRoot: true,
90
- fsGroup: 65532,
90
+ fsGroup: image.includes("private") ? 1000 : 65532,
91
91
  },
92
92
  containers: [
93
93
  {
@@ -128,7 +128,7 @@ export function getWatcher(
128
128
  },
129
129
  securityContext: {
130
130
  runAsUser: image.includes("private") ? 1000 : 65532,
131
- runAsGroup: 65532,
131
+ runAsGroup: image.includes("private") ? 1000 : 65532,
132
132
  runAsNonRoot: true,
133
133
  allowPrivilegeEscalation: false,
134
134
  capabilities: {
@@ -228,9 +228,9 @@ export function getDeployment(
228
228
  serviceAccountName: name,
229
229
  securityContext: {
230
230
  runAsUser: image.includes("private") ? 1000 : 65532,
231
- runAsGroup: 65532,
231
+ runAsGroup: image.includes("private") ? 1000 : 65532,
232
232
  runAsNonRoot: true,
233
- fsGroup: 65532,
233
+ fsGroup: image.includes("private") ? 1000 : 65532,
234
234
  },
235
235
  containers: [
236
236
  {
@@ -272,7 +272,7 @@ export function getDeployment(
272
272
  env: genEnv(config),
273
273
  securityContext: {
274
274
  runAsUser: image.includes("private") ? 1000 : 65532,
275
- runAsGroup: 65532,
275
+ runAsGroup: image.includes("private") ? 1000 : 65532,
276
276
  runAsNonRoot: true,
277
277
  allowPrivilegeEscalation: false,
278
278
  capabilities: {
@@ -26,12 +26,6 @@ export function loadCapabilities(path: string): Promise<CapabilityExport[]> {
26
26
  program.on("message", message => {
27
27
  // Cast the message to the ModuleCapabilities type
28
28
  const capabilities = message.valueOf() as CapabilityExport[];
29
-
30
- // Iterate through the capabilities and generate the rules
31
- for (const capability of capabilities) {
32
- console.debug(`Registered Pepr Capability "${capability.name}"`);
33
- }
34
-
35
29
  resolve(capabilities);
36
30
  });
37
31
 
@@ -5,6 +5,8 @@ import {
5
5
  AdmissionregistrationV1WebhookClientConfig as AdmissionRegnV1WebhookClientCfg,
6
6
  V1LabelSelectorRequirement,
7
7
  V1RuleWithOperations,
8
+ V1MutatingWebhookConfiguration,
9
+ V1ValidatingWebhookConfiguration,
8
10
  } from "@kubernetes/client-node";
9
11
  import { kind } from "kubernetes-fluent-client";
10
12
  import { concat, equals, uniqWith } from "ramda";
@@ -12,7 +14,6 @@ import { resolveIgnoreNamespaces } from "./ignoredNamespaces";
12
14
  import { Assets } from "./assets";
13
15
  import { Event, WebhookType } from "../enums";
14
16
  import { Binding } from "../types";
15
- import Log from "../telemetry/logger";
16
17
 
17
18
  export const peprIgnoreNamespaces: string[] = ["kube-system", "pepr-system"];
18
19
 
@@ -47,15 +48,13 @@ export async function generateWebhookRules(
47
48
  assets: Assets,
48
49
  isMutateWebhook: boolean,
49
50
  ): Promise<V1RuleWithOperations[]> {
50
- const { config, capabilities } = assets;
51
+ const { capabilities } = assets;
51
52
 
52
- const rules = capabilities.flatMap(capability => {
53
- Log.info(`Module ${config.uuid} has capability: ${capability.name}`);
54
-
55
- return capability.bindings
53
+ const rules = capabilities.flatMap(capability =>
54
+ capability.bindings
56
55
  .map(binding => validateRule(binding, isMutateWebhook))
57
- .filter((rule): rule is V1RuleWithOperations => !!rule);
58
- });
56
+ .filter((rule): rule is V1RuleWithOperations => !!rule),
57
+ );
59
58
 
60
59
  return uniqWith(equals, rules);
61
60
  }
@@ -113,7 +112,7 @@ export async function webhookConfigGenerator(
113
112
  return null;
114
113
  }
115
114
 
116
- return {
115
+ const webhookConfig = {
117
116
  apiVersion: "admissionregistration.k8s.io/v1",
118
117
  kind: isMutate ? "MutatingWebhookConfiguration" : "ValidatingWebhookConfiguration",
119
118
  metadata: { name },
@@ -134,4 +133,54 @@ export async function webhookConfigGenerator(
134
133
  },
135
134
  ],
136
135
  };
136
+
137
+ // If additional webhooks are specified, add them to the config
138
+ if (config.additionalWebhooks) {
139
+ return configureAdditionalWebhooks(webhookConfig, config.additionalWebhooks);
140
+ }
141
+
142
+ return webhookConfig;
143
+ }
144
+
145
+ export function configureAdditionalWebhooks(
146
+ webhookConfig: V1MutatingWebhookConfiguration | V1ValidatingWebhookConfiguration,
147
+ additionalWebhooks: {
148
+ failurePolicy: "Fail" | "Ignore";
149
+ namespace: string;
150
+ }[],
151
+ ): V1MutatingWebhookConfiguration | V1ValidatingWebhookConfiguration {
152
+ if (!additionalWebhooks || additionalWebhooks.length === 0) {
153
+ return webhookConfig;
154
+ }
155
+ // set the ignored namespace to the additional webhook namespaces
156
+ const webhooks = webhookConfig.webhooks ?? [];
157
+ if (webhooks.length === 0) {
158
+ return webhookConfig;
159
+ }
160
+ const expr = webhooks[0]!.namespaceSelector!.matchExpressions![0]!;
161
+ expr.values!.push(...additionalWebhooks.map(w => w.namespace));
162
+
163
+ additionalWebhooks.forEach(additionalWebhook => {
164
+ webhooks.push({
165
+ name: `${webhookConfig.metadata!.name}-${additionalWebhook.namespace}.pepr.dev`,
166
+ admissionReviewVersions: ["v1", "v1beta1"],
167
+ clientConfig: webhooks[0]!.clientConfig,
168
+ failurePolicy: additionalWebhook.failurePolicy,
169
+ matchPolicy: "Equivalent",
170
+ timeoutSeconds: webhooks[0]!.timeoutSeconds,
171
+ namespaceSelector: {
172
+ matchExpressions: [
173
+ {
174
+ key: "kubernetes.io/metadata.name",
175
+ operator: "In",
176
+ values: [additionalWebhook.namespace],
177
+ },
178
+ ],
179
+ },
180
+ rules: webhooks[0].rules,
181
+ sideEffects: "None",
182
+ });
183
+ });
184
+
185
+ return webhookConfig;
137
186
  }
@@ -4,6 +4,8 @@ import { dumpYaml } from "@kubernetes/client-node";
4
4
  import { clusterRole } from "../rbac";
5
5
  import { promises as fs } from "fs";
6
6
  import { resolveIgnoreNamespaces } from "../ignoredNamespaces";
7
+ import { quicktype, InputData, jsonInputForTargetLanguage } from "quicktype-core";
8
+
7
9
  export type ChartOverrides = {
8
10
  apiPath: string;
9
11
  capabilities: CapabilityExport[];
@@ -60,9 +62,9 @@ export async function overridesFile(
60
62
  },
61
63
  securityContext: {
62
64
  runAsUser: image.includes("private") ? 1000 : 65532,
63
- runAsGroup: 65532,
65
+ runAsGroup: image.includes("private") ? 1000 : 65532,
64
66
  runAsNonRoot: true,
65
- fsGroup: 65532,
67
+ fsGroup: image.includes("private") ? 1000 : 65532,
66
68
  },
67
69
  readinessProbe: {
68
70
  httpGet: {
@@ -92,7 +94,7 @@ export async function overridesFile(
92
94
  },
93
95
  containerSecurityContext: {
94
96
  runAsUser: image.includes("private") ? 1000 : 65532,
95
- runAsGroup: 65532,
97
+ runAsGroup: image.includes("private") ? 1000 : 65532,
96
98
  runAsNonRoot: true,
97
99
  allowPrivilegeEscalation: false,
98
100
  capabilities: {
@@ -128,9 +130,9 @@ export async function overridesFile(
128
130
  },
129
131
  securityContext: {
130
132
  runAsUser: image.includes("private") ? 1000 : 65532,
131
- runAsGroup: 65532,
133
+ runAsGroup: image.includes("private") ? 1000 : 65532,
132
134
  runAsNonRoot: true,
133
- fsGroup: 65532,
135
+ fsGroup: image.includes("private") ? 1000 : 65532,
134
136
  },
135
137
  readinessProbe: {
136
138
  httpGet: {
@@ -160,7 +162,7 @@ export async function overridesFile(
160
162
  },
161
163
  containerSecurityContext: {
162
164
  runAsUser: image.includes("private") ? 1000 : 65532,
163
- runAsGroup: 65532,
165
+ runAsGroup: image.includes("private") ? 1000 : 65532,
164
166
  runAsNonRoot: true,
165
167
  allowPrivilegeEscalation: false,
166
168
  capabilities: {
@@ -181,6 +183,26 @@ export async function overridesFile(
181
183
  },
182
184
  },
183
185
  };
184
-
186
+ /** write values.schema.yaml */
187
+ await writeSchemaYamlFromObject(JSON.stringify(overrides, null, 2), path);
185
188
  await fs.writeFile(path, dumpYaml(overrides, { noRefs: true, forceQuotes: true }));
186
189
  }
190
+
191
+ export async function writeSchemaYamlFromObject(
192
+ valuesString: string,
193
+ valuesFilePath: string,
194
+ ): Promise<void> {
195
+ const schemaPath = valuesFilePath.replace(/\.yaml$/, ".schema.json");
196
+ const jsonInput = jsonInputForTargetLanguage("schema");
197
+ await jsonInput.addSource({ name: "Values", samples: [valuesString] });
198
+
199
+ const inputData = new InputData();
200
+ inputData.addInput(jsonInput);
201
+
202
+ const { lines } = await quicktype({ inputData, lang: "schema" });
203
+
204
+ const schemaJson = lines.join("\n");
205
+ const schemaObj = JSON.parse(schemaJson);
206
+
207
+ await fs.writeFile(schemaPath, JSON.stringify(schemaObj, null, 2), "utf8");
208
+ }
@@ -50,6 +50,7 @@ export class Controller {
50
50
  const { beforeHook, afterHook, onReady } = hooks;
51
51
  this.#config = config;
52
52
  this.#capabilities = capabilities;
53
+ Log.info({ config }, "Controller configuration");
53
54
 
54
55
  // Initialize the Pepr store for each capability
55
56
  new StoreController(capabilities, `pepr-${config.uuid}-store`, () => {
package/src/lib/types.ts CHANGED
@@ -296,6 +296,13 @@ export type ModuleConfig = {
296
296
  watch?: {
297
297
  alwaysIgnore: WebhookIgnore;
298
298
  };
299
+ /** Additional webhooks config to be used by the module */
300
+ additionalWebhooks?: [
301
+ {
302
+ failurePolicy: "Fail" | "Ignore";
303
+ namespace: string;
304
+ },
305
+ ];
299
306
  } & Partial<ModuleConfigOptions>;
300
307
 
301
308
  export type PackageJSON = {
@@ -1,21 +0,0 @@
1
- import { CapabilityExport } from "../lib/types";
2
- import { Assets } from "../lib/assets/assets";
3
- import { Command } from "commander";
4
- interface ImagePullSecretDetails {
5
- pullSecret?: string;
6
- dockerServer?: string;
7
- dockerUsername?: string;
8
- dockerEmail?: string;
9
- dockerPassword?: string;
10
- }
11
- export declare function validateImagePullSecretDetails(details: ImagePullSecretDetails): {
12
- valid: boolean;
13
- error?: string;
14
- };
15
- export declare function getUserConfirmation(opts: {
16
- yes: boolean;
17
- }): Promise<boolean>;
18
- export default function (program: Command): void;
19
- export declare function validateNamespaces(capability: CapabilityExport, webhook: Assets): void;
20
- export {};
21
- //# sourceMappingURL=deploy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/cli/deploy.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,UAAU,sBAAsB;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,sBAAsB,GAAG;IAC/E,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAmCA;AAoBD,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAalF;AAkCD,MAAM,CAAC,OAAO,WAAW,OAAO,EAAE,OAAO,GAAG,IAAI,CA8B/C;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAQtF"}
package/src/cli/deploy.ts DELETED
@@ -1,170 +0,0 @@
1
- // SPDX-License-Identifier: Apache-2.0
2
- // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
-
4
- import prompt from "prompts";
5
- import { CapabilityExport } from "../lib/types";
6
- import { Assets } from "../lib/assets/assets";
7
- import { ImagePullSecret } from "../lib/types";
8
- import { Command } from "commander";
9
- import { buildModule } from "./build/buildModule";
10
- import { deployImagePullSecret, deployWebhook } from "../lib/assets/deploy";
11
- import { namespaceDeploymentsReady } from "../lib/deploymentChecks";
12
- import { sanitizeName } from "./init/utils";
13
- import { validateCapabilityNames } from "../lib/helpers";
14
- import { namespaceComplianceValidator } from "../lib/helpers";
15
- import { loadCapabilities } from "../lib/assets/loader";
16
-
17
- interface ImagePullSecretDetails {
18
- pullSecret?: string;
19
- dockerServer?: string;
20
- dockerUsername?: string;
21
- dockerEmail?: string;
22
- dockerPassword?: string;
23
- }
24
-
25
- export function validateImagePullSecretDetails(details: ImagePullSecretDetails): {
26
- valid: boolean;
27
- error?: string;
28
- } {
29
- if (!details.pullSecret) {
30
- return { valid: true };
31
- }
32
-
33
- // https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names
34
- if (details.pullSecret !== sanitizeName(details.pullSecret)) {
35
- return {
36
- valid: false,
37
- error: `Invalid --pullSecret. Must be valid name as defined in RFC 1123.`,
38
- };
39
- }
40
-
41
- const missing: string[] = [];
42
- if (!details.dockerEmail) {
43
- missing.push("--docker-email");
44
- }
45
- if (!details.dockerServer) {
46
- missing.push("--docker-server");
47
- }
48
- if (!details.dockerUsername) {
49
- missing.push("--docker-username");
50
- }
51
- if (!details.dockerPassword) {
52
- missing.push("--docker-password");
53
- }
54
-
55
- if (missing.length > 0) {
56
- return {
57
- valid: false,
58
- error: `Error: Must provide ${missing.join(", ")} when providing --pull-secret`,
59
- };
60
- }
61
-
62
- return { valid: true };
63
- }
64
-
65
- type ValidatedImagePullSecretDetails = Required<ImagePullSecretDetails>;
66
-
67
- function generateImagePullSecret(details: ValidatedImagePullSecretDetails): ImagePullSecret {
68
- const auth = Buffer.from(`${details.dockerUsername}:${details.dockerPassword}`).toString(
69
- "base64",
70
- );
71
- return {
72
- auths: {
73
- [details.dockerServer]: {
74
- username: details.dockerUsername,
75
- password: details.dockerPassword,
76
- email: details.dockerEmail,
77
- auth,
78
- },
79
- },
80
- };
81
- }
82
-
83
- export async function getUserConfirmation(opts: { yes: boolean }): Promise<boolean> {
84
- if (opts.yes) {
85
- return true;
86
- }
87
-
88
- // Prompt the user to confirm
89
- const confirmation = await prompt({
90
- type: "confirm",
91
- name: "yes",
92
- message: "This will remove and redeploy the module. Continue?",
93
- });
94
-
95
- return confirmation.yes ? true : false;
96
- }
97
-
98
- async function buildAndDeployModule(image: string, force: boolean): Promise<void> {
99
- const builtModule = await buildModule("dist");
100
- if (!builtModule) {
101
- return;
102
- }
103
-
104
- // Generate a secret for the module
105
- const webhook = new Assets(
106
- { ...builtModule.cfg.pepr, description: builtModule.cfg.description },
107
- builtModule.path,
108
- [],
109
- );
110
- webhook.image = image ?? webhook.image;
111
- const capabilities = await loadCapabilities(webhook.path);
112
- for (const capability of capabilities) {
113
- validateNamespaces(capability, webhook);
114
- }
115
- try {
116
- await webhook.deploy(deployWebhook, force, builtModule.cfg.pepr.webhookTimeout ?? 10);
117
-
118
- // wait for capabilities to be loaded and test names
119
- validateCapabilityNames(webhook.capabilities);
120
-
121
- // Wait for the pepr-system resources to be fully up
122
- await namespaceDeploymentsReady();
123
- console.info(`✅ Module deployed successfully`);
124
- } catch (e) {
125
- console.error(`Error deploying module:`, e);
126
- process.exit(1);
127
- }
128
- }
129
-
130
- export default function (program: Command): void {
131
- program
132
- .command("deploy")
133
- .description("Deploy a Pepr Module")
134
- .option("-E, --docker-email <email>", "Email for Docker registry.")
135
- .option("-P, --docker-password <password>", "Password for Docker registry.")
136
- .option("-S, --docker-server <server>", "Docker server address.")
137
- .option("-U, --docker-username <username>", "Docker registry username.")
138
- .option("-f, --force", "Force deploy the module, override manager field.")
139
- .option("-i, --image <image>", "Override the image tag.")
140
- .option("-p, --pull-secret <name>", "Deploy imagePullSecret for Controller private registry.")
141
- .option("-y, --yes", "Skip confirmation prompts.")
142
- .action(async opts => {
143
- const valResp = validateImagePullSecretDetails(opts);
144
- if (!valResp.valid) {
145
- console.error(valResp.error);
146
- process.exit(1);
147
- }
148
-
149
- if (opts.pullSecret) {
150
- await deployImagePullSecret(generateImagePullSecret(opts), opts.pullSecret);
151
- return;
152
- }
153
-
154
- if (!(await getUserConfirmation(opts))) {
155
- process.exit(0);
156
- }
157
-
158
- await buildAndDeployModule(opts.image, opts.force);
159
- });
160
- }
161
-
162
- export function validateNamespaces(capability: CapabilityExport, webhook: Assets): void {
163
- namespaceComplianceValidator(capability, webhook.alwaysIgnore?.namespaces);
164
- namespaceComplianceValidator(
165
- capability,
166
- webhook.config.admission?.alwaysIgnore?.namespaces,
167
- false,
168
- );
169
- namespaceComplianceValidator(capability, webhook.config.watch?.alwaysIgnore?.namespaces, true);
170
- }