pepr 0.1.27 → 0.1.29
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.
- package/cli.ts +3 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +4 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +14 -0
- package/dist/package.json +76 -0
- package/dist/src/cli/banner.d.ts +1 -0
- package/dist/{pepr-cli.js → src/cli/banner.js} +4 -1251
- package/dist/src/cli/build.d.ts +7 -0
- package/dist/src/cli/build.js +102 -0
- package/dist/src/cli/capability.d.ts +2 -0
- package/dist/src/cli/capability.js +15 -0
- package/dist/src/cli/deploy.d.ts +2 -0
- package/dist/src/cli/deploy.js +55 -0
- package/dist/src/cli/dev.d.ts +2 -0
- package/dist/src/cli/dev.js +96 -0
- package/dist/src/cli/index.d.ts +1 -0
- package/dist/src/cli/index.js +33 -0
- package/dist/src/cli/init/index.d.ts +2 -0
- package/dist/src/cli/init/index.js +54 -0
- package/dist/src/cli/init/templates.d.ts +82 -0
- package/dist/src/cli/init/templates.js +229 -0
- package/dist/src/cli/init/utils.d.ts +20 -0
- package/dist/src/cli/init/utils.js +56 -0
- package/dist/src/cli/init/walkthrough.d.ts +7 -0
- package/dist/src/cli/init/walkthrough.js +84 -0
- package/dist/src/cli/root.d.ts +4 -0
- package/dist/src/cli/root.js +21 -0
- package/dist/src/cli/test.d.ts +2 -0
- package/dist/src/cli/test.js +51 -0
- package/dist/src/lib/capability.d.ts +26 -0
- package/dist/src/lib/capability.js +119 -0
- package/dist/src/lib/controller.d.ts +13 -0
- package/dist/src/lib/controller.js +84 -0
- package/dist/src/lib/filter.d.ts +10 -0
- package/dist/src/lib/filter.js +48 -0
- package/dist/src/lib/k8s/index.d.ts +4 -0
- package/dist/src/lib/k8s/index.js +38 -0
- package/dist/src/lib/k8s/kinds.d.ts +3 -0
- package/dist/src/lib/k8s/kinds.js +431 -0
- package/dist/src/lib/k8s/tls.d.ts +17 -0
- package/dist/src/lib/k8s/tls.js +74 -0
- package/dist/src/lib/k8s/types.d.ts +136 -0
- package/dist/src/lib/k8s/types.js +12 -0
- package/dist/src/lib/k8s/upstream.d.ts +1 -0
- package/dist/src/lib/k8s/upstream.js +47 -0
- package/dist/src/lib/k8s/webhook.d.ts +33 -0
- package/dist/src/lib/k8s/webhook.js +497 -0
- package/dist/src/lib/logger.d.ts +54 -0
- package/dist/{types-1709b44f.js → src/lib/logger.js} +6 -39
- package/dist/src/lib/module.d.ts +22 -0
- package/dist/src/lib/module.js +39 -0
- package/dist/src/lib/processor.d.ts +4 -0
- package/dist/src/lib/processor.js +73 -0
- package/dist/src/lib/request.d.ts +77 -0
- package/dist/src/lib/request.js +144 -0
- package/dist/src/lib/types.d.ts +187 -0
- package/dist/src/lib/types.js +34 -0
- package/package.json +8 -11
- package/tsconfig.build.json +4 -0
- package/dist/pepr-core.js +0 -949
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.capabilitySnippet = exports.capabilityHelloPeprTS = exports.readme = exports.prettierRC = exports.gitIgnore = exports.tsConfig = exports.genPkgJSON = exports.genPeprTS = void 0;
|
|
6
|
+
const util_1 = require("util");
|
|
7
|
+
const uuid_1 = require("uuid");
|
|
8
|
+
const package_json_1 = require("../../../package.json");
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
function genPeprTS() {
|
|
11
|
+
return {
|
|
12
|
+
path: "pepr.ts",
|
|
13
|
+
data: `import { PeprModule } from "pepr";
|
|
14
|
+
import cfg from "./package.json";
|
|
15
|
+
import { HelloPepr } from "./capabilities/hello-pepr";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* This is the main entrypoint for the Pepr module. It is the file that is run when the module is started.
|
|
19
|
+
* This is where you register your configurations and capabilities with the module.
|
|
20
|
+
*/
|
|
21
|
+
new PeprModule(cfg, [
|
|
22
|
+
// "HelloPepr" is a demo capability that is included with Pepr. You can remove it if you want.
|
|
23
|
+
HelloPepr,
|
|
24
|
+
|
|
25
|
+
// Your additional capabilities go here
|
|
26
|
+
]);
|
|
27
|
+
`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
exports.genPeprTS = genPeprTS;
|
|
31
|
+
function genPkgJSON(opts) {
|
|
32
|
+
// Generate a random UUID for the module based on the module name
|
|
33
|
+
const uuid = (0, uuid_1.v5)(opts.name, (0, uuid_1.v4)());
|
|
34
|
+
// Generate a name for the module based on the module name
|
|
35
|
+
const name = (0, utils_1.sanitizeName)(opts.name);
|
|
36
|
+
// Make typescript a dev dependency
|
|
37
|
+
const { typescript } = package_json_1.dependencies;
|
|
38
|
+
const data = {
|
|
39
|
+
name,
|
|
40
|
+
version: "0.0.1",
|
|
41
|
+
description: opts.description,
|
|
42
|
+
keywords: ["pepr", "k8s", "policy-engine", "pepr-module", "security"],
|
|
43
|
+
pepr: {
|
|
44
|
+
name: opts.name.trim(),
|
|
45
|
+
version: package_json_1.version,
|
|
46
|
+
uuid,
|
|
47
|
+
onError: opts.errorBehavior,
|
|
48
|
+
alwaysIgnore: {
|
|
49
|
+
namespaces: [],
|
|
50
|
+
labels: [],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
scripts: {
|
|
54
|
+
build: "pepr build",
|
|
55
|
+
start: "pepr dev",
|
|
56
|
+
},
|
|
57
|
+
dependencies: {
|
|
58
|
+
pepr: `^${package_json_1.version}`,
|
|
59
|
+
},
|
|
60
|
+
devDependencies: {
|
|
61
|
+
typescript,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
return {
|
|
65
|
+
data,
|
|
66
|
+
path: "package.json",
|
|
67
|
+
print: (0, util_1.inspect)(data, false, 5, true),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
exports.genPkgJSON = genPkgJSON;
|
|
71
|
+
exports.tsConfig = {
|
|
72
|
+
path: "tsconfig.json",
|
|
73
|
+
data: {
|
|
74
|
+
compilerOptions: {
|
|
75
|
+
esModuleInterop: true,
|
|
76
|
+
lib: ["ES2020"],
|
|
77
|
+
moduleResolution: "node",
|
|
78
|
+
resolveJsonModule: true,
|
|
79
|
+
rootDir: ".",
|
|
80
|
+
strict: false,
|
|
81
|
+
target: "ES2020",
|
|
82
|
+
},
|
|
83
|
+
include: ["**/*.ts"],
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
exports.gitIgnore = {
|
|
87
|
+
path: ".gitignore",
|
|
88
|
+
data: `# Ignore node_modules
|
|
89
|
+
node_modules
|
|
90
|
+
dist
|
|
91
|
+
`,
|
|
92
|
+
};
|
|
93
|
+
exports.prettierRC = {
|
|
94
|
+
path: ".prettierrc",
|
|
95
|
+
data: {
|
|
96
|
+
arrowParens: "avoid",
|
|
97
|
+
bracketSameLine: false,
|
|
98
|
+
bracketSpacing: true,
|
|
99
|
+
embeddedLanguageFormatting: "auto",
|
|
100
|
+
insertPragma: false,
|
|
101
|
+
printWidth: 80,
|
|
102
|
+
quoteProps: "as-needed",
|
|
103
|
+
requirePragma: false,
|
|
104
|
+
semi: true,
|
|
105
|
+
tabWidth: 2,
|
|
106
|
+
useTabs: false,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
exports.readme = {
|
|
110
|
+
path: "README.md",
|
|
111
|
+
data: `# Pepr Module
|
|
112
|
+
|
|
113
|
+
This is a Pepr module. It is a module that can be used with the [Pepr]() framework.
|
|
114
|
+
|
|
115
|
+
The \`capabilities\` directory contains all the capabilities for this module. By default,
|
|
116
|
+
a capability is a single typescript file in the format of \`capability-name.ts\` that is
|
|
117
|
+
imported in the root \`pepr.ts\` file as \`import { HelloPepr } from "./capabilities/hello-pepr";\`.
|
|
118
|
+
Because this is typescript, you can organize this however you choose, e.g. creating a sub-folder
|
|
119
|
+
per-capability or common logic in shared files or folders.
|
|
120
|
+
|
|
121
|
+
Example Structure:
|
|
122
|
+
|
|
123
|
+
\`\`\`
|
|
124
|
+
Module Root
|
|
125
|
+
├── package.json
|
|
126
|
+
├── pepr.ts
|
|
127
|
+
└── capabilities
|
|
128
|
+
├── example-one.ts
|
|
129
|
+
├── example-three.ts
|
|
130
|
+
└── example-two.ts
|
|
131
|
+
\`\`\`
|
|
132
|
+
`,
|
|
133
|
+
};
|
|
134
|
+
exports.capabilityHelloPeprTS = {
|
|
135
|
+
path: "hello-pepr.ts",
|
|
136
|
+
data: `import { Capability, a } from "pepr";
|
|
137
|
+
|
|
138
|
+
export const HelloPepr = new Capability({
|
|
139
|
+
name: "hello-pepr",
|
|
140
|
+
description: "A simple example capability to show how things work.",
|
|
141
|
+
namespaces: ["pepr-demo"],
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Use the 'When' function to create a new Capability Action
|
|
145
|
+
const { When } = HelloPepr;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* This is a single Capability Action. They can be in the same file or put imported from other files.
|
|
149
|
+
* In this exmaple, when a ConfigMap is created with the name \`example-1\`, then add a label and annotation.
|
|
150
|
+
*
|
|
151
|
+
* Equivelant to manually running:
|
|
152
|
+
* \`kubectl label configmap example-1 pepr=was-here\`
|
|
153
|
+
* \`kubectl annotate configmap example-1 pepr.dev=annotations-work-too\`
|
|
154
|
+
*/
|
|
155
|
+
When(a.ConfigMap)
|
|
156
|
+
.IsCreated()
|
|
157
|
+
.WithName("example-1")
|
|
158
|
+
.Then(request =>
|
|
159
|
+
request
|
|
160
|
+
.SetLabel("pepr", "was-here")
|
|
161
|
+
.SetAnnotation("pepr.dev", "annotations-work-too")
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* This Capabiility Action does the exact same changes for example-2, except this time it uses the \`.ThenSet()\` feature.
|
|
166
|
+
* You can stack multiple \`.Then()\` calls, but only a single \`.ThenSet()\`
|
|
167
|
+
*/
|
|
168
|
+
When(a.ConfigMap)
|
|
169
|
+
.IsCreated()
|
|
170
|
+
.WithName("example-2")
|
|
171
|
+
.ThenSet({
|
|
172
|
+
metadata: {
|
|
173
|
+
labels: {
|
|
174
|
+
pepr: "was-here",
|
|
175
|
+
},
|
|
176
|
+
annotations: {
|
|
177
|
+
"pepr.dev": "annotations-work-too",
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* This Capability Action combines different styles. Unlike the previous actions, this one will look for any ConfigMap
|
|
184
|
+
* in the \`pepr-demo\` namespace that has the label \`change=by-label\`. Note that all conditions added such as \`WithName()\`,
|
|
185
|
+
* \`WithLabel()\`, \`InNamespace()\`, are ANDs so all conditions must be true for the request to be procssed.
|
|
186
|
+
*/
|
|
187
|
+
When(a.ConfigMap)
|
|
188
|
+
.IsCreated()
|
|
189
|
+
.WithLabel("change", "by-label")
|
|
190
|
+
.Then(request => {
|
|
191
|
+
// The K8s object e are going to mutate
|
|
192
|
+
const cm = request.Raw;
|
|
193
|
+
|
|
194
|
+
// Get the username and uid of the K8s reuest
|
|
195
|
+
const { username, uid } = request.Request.userInfo;
|
|
196
|
+
|
|
197
|
+
// Store some data about the request in the configmap
|
|
198
|
+
cm.data["username"] = username;
|
|
199
|
+
cm.data["uid"] = uid;
|
|
200
|
+
|
|
201
|
+
// You can still mix other ways of making changes too
|
|
202
|
+
request.SetAnnotation("pepr.dev", "making-waves");
|
|
203
|
+
});
|
|
204
|
+
`,
|
|
205
|
+
};
|
|
206
|
+
exports.capabilitySnippet = {
|
|
207
|
+
path: "pepr.code-snippets",
|
|
208
|
+
data: `{
|
|
209
|
+
"Create a new Pepr capability": {
|
|
210
|
+
"prefix": "create pepr capability",
|
|
211
|
+
"body": [
|
|
212
|
+
"import { Capability, a } from 'pepr';",
|
|
213
|
+
"",
|
|
214
|
+
"export const $\{TM_FILENAME_BASE/(.*)/$\{1:/pascalcase}/} = new Capability({",
|
|
215
|
+
"\\tname: '$\{TM_FILENAME_BASE}',",
|
|
216
|
+
"\\tdescription: '$\{1:A brief description of this capability.}',",
|
|
217
|
+
"\\tnamespaces: [$\{2:}],",
|
|
218
|
+
"});",
|
|
219
|
+
"",
|
|
220
|
+
"// Use the 'When' function to create a new Capability Action",
|
|
221
|
+
"const { When } = $\{TM_FILENAME_BASE/(.*)/$\{1:/pascalcase}/};",
|
|
222
|
+
"",
|
|
223
|
+
"// When(a.<Kind>).Is<Event>().Then(change => change.<changes>",
|
|
224
|
+
"When($\{3:})"
|
|
225
|
+
],
|
|
226
|
+
"description": "Creates a new Pepr capability with a specified description, and optional namespaces, and adds a When statement for the specified value."
|
|
227
|
+
}
|
|
228
|
+
}`,
|
|
229
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitize a user input name to be used as a pepr module directory name
|
|
3
|
+
*
|
|
4
|
+
* @param name the user input name
|
|
5
|
+
* @returns the sanitized name
|
|
6
|
+
*/
|
|
7
|
+
export declare function sanitizeName(name: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Creates a directory and throws an error if it already exists
|
|
10
|
+
*
|
|
11
|
+
* @param dir - The directory to create
|
|
12
|
+
*/
|
|
13
|
+
export declare function createDir(dir: string): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Write data to a file on disk
|
|
16
|
+
* @param path - The path to the file
|
|
17
|
+
* @param data - The data to write
|
|
18
|
+
* @returns A promise that resolves when the file has been written
|
|
19
|
+
*/
|
|
20
|
+
export declare function write(path: string, data: unknown): Promise<void>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.write = exports.createDir = exports.sanitizeName = void 0;
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
/**
|
|
8
|
+
* Sanitize a user input name to be used as a pepr module directory name
|
|
9
|
+
*
|
|
10
|
+
* @param name the user input name
|
|
11
|
+
* @returns the sanitized name
|
|
12
|
+
*/
|
|
13
|
+
function sanitizeName(name) {
|
|
14
|
+
// Replace any characters outside of [^a-z0-9-] with "-"
|
|
15
|
+
let sanitized = name.toLowerCase().replace(/[^a-z0-9-]+/gi, "-");
|
|
16
|
+
// Remove any leading or trailing hyphens
|
|
17
|
+
sanitized = sanitized.replace(/^-+|-+$/g, "");
|
|
18
|
+
// Replace multiple hyphens with a single hyphen
|
|
19
|
+
sanitized = sanitized.replace(/--+/g, "-");
|
|
20
|
+
return sanitized;
|
|
21
|
+
}
|
|
22
|
+
exports.sanitizeName = sanitizeName;
|
|
23
|
+
/**
|
|
24
|
+
* Creates a directory and throws an error if it already exists
|
|
25
|
+
*
|
|
26
|
+
* @param dir - The directory to create
|
|
27
|
+
*/
|
|
28
|
+
async function createDir(dir) {
|
|
29
|
+
try {
|
|
30
|
+
await fs_1.promises.mkdir(dir);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
// The directory already exists
|
|
34
|
+
if (err.code === "EEXIST") {
|
|
35
|
+
throw new Error(`Directory ${dir} already exists`);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.createDir = createDir;
|
|
43
|
+
/**
|
|
44
|
+
* Write data to a file on disk
|
|
45
|
+
* @param path - The path to the file
|
|
46
|
+
* @param data - The data to write
|
|
47
|
+
* @returns A promise that resolves when the file has been written
|
|
48
|
+
*/
|
|
49
|
+
function write(path, data) {
|
|
50
|
+
// If the data is not a string, stringify it
|
|
51
|
+
if (typeof data !== "string") {
|
|
52
|
+
data = JSON.stringify(data, null, 2);
|
|
53
|
+
}
|
|
54
|
+
return fs_1.promises.writeFile(path, data);
|
|
55
|
+
}
|
|
56
|
+
exports.write = write;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Answers } from "prompts";
|
|
2
|
+
export type InitOptions = Answers<"name" | "description" | "errorBehavior">;
|
|
3
|
+
export declare function walkthrough(): Promise<InitOptions>;
|
|
4
|
+
export declare function confirm(dirName: string, packageJSON: {
|
|
5
|
+
path: string;
|
|
6
|
+
print: string;
|
|
7
|
+
}, peprTSPath: string): Promise<any>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
4
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
+
};
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.confirm = exports.walkthrough = void 0;
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
11
|
+
const types_1 = require("../../lib/types");
|
|
12
|
+
const templates_1 = require("./templates");
|
|
13
|
+
const utils_1 = require("./utils");
|
|
14
|
+
function walkthrough() {
|
|
15
|
+
const askName = {
|
|
16
|
+
type: "text",
|
|
17
|
+
name: "name",
|
|
18
|
+
message: "Enter a name for the new Pepr module. This will create a new directory based on the name.\n",
|
|
19
|
+
validate: async (val) => {
|
|
20
|
+
try {
|
|
21
|
+
const name = (0, utils_1.sanitizeName)(val);
|
|
22
|
+
await fs_1.promises.access(name, fs_1.promises.constants.F_OK);
|
|
23
|
+
return "A directory with this name already exists";
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
return val.length > 2 || "The name must be at least 3 characters long";
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
const askDescription = {
|
|
31
|
+
type: "text",
|
|
32
|
+
name: "description",
|
|
33
|
+
message: "(Recommended) Enter a description for the new Pepr module.\n",
|
|
34
|
+
};
|
|
35
|
+
const askErrorBehavior = {
|
|
36
|
+
type: "select",
|
|
37
|
+
name: "errorBehavior",
|
|
38
|
+
validate: val => types_1.ErrorBehavior[val],
|
|
39
|
+
message: "How do you want Pepr to handle errors encountered during K8s operations?",
|
|
40
|
+
choices: [
|
|
41
|
+
{
|
|
42
|
+
title: "Ignore",
|
|
43
|
+
value: types_1.ErrorBehavior.ignore,
|
|
44
|
+
description: "Pepr will continue processing and generate an entry in the Pepr Controller log.",
|
|
45
|
+
selected: true,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
title: "Log an audit event",
|
|
49
|
+
value: types_1.ErrorBehavior.audit,
|
|
50
|
+
description: "Pepr will continue processing and generate an entry in the Pepr Controller log as well as an audit event in the cluster.",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
title: "Reject the operation",
|
|
54
|
+
value: types_1.ErrorBehavior.reject,
|
|
55
|
+
description: "Pepr will reject the operation and return an error to the client.",
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
return (0, prompts_1.default)([askName, askDescription, askErrorBehavior]);
|
|
60
|
+
}
|
|
61
|
+
exports.walkthrough = walkthrough;
|
|
62
|
+
async function confirm(dirName, packageJSON, peprTSPath) {
|
|
63
|
+
console.log(`
|
|
64
|
+
To be generated:
|
|
65
|
+
|
|
66
|
+
\x1b[1m${dirName}\x1b[0m
|
|
67
|
+
├── \x1b[1m${templates_1.gitIgnore.path}\x1b[0m
|
|
68
|
+
├── \x1b[1m${templates_1.prettierRC.path}\x1b[0m
|
|
69
|
+
├── \x1b[1mcapabilties\x1b[0m
|
|
70
|
+
| └── \x1b[1mhello-pepr.ts\x1b[0m
|
|
71
|
+
├── \x1b[1m${packageJSON.path}\x1b[0m
|
|
72
|
+
${packageJSON.print.replace(/^/gm, " │ ")}
|
|
73
|
+
├── \x1b[1m${peprTSPath}\x1b[0m
|
|
74
|
+
├── \x1b[1m${templates_1.readme.path}\x1b[0m
|
|
75
|
+
└── \x1b[1m${templates_1.tsConfig.path}\x1b[0m
|
|
76
|
+
`);
|
|
77
|
+
const confirm = await (0, prompts_1.default)({
|
|
78
|
+
type: "confirm",
|
|
79
|
+
name: "confirm",
|
|
80
|
+
message: "Create the new Pepr module?",
|
|
81
|
+
});
|
|
82
|
+
return confirm.confirm;
|
|
83
|
+
}
|
|
84
|
+
exports.confirm = confirm;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
4
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
+
};
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.RootCmd = void 0;
|
|
9
|
+
const commander_1 = require("commander");
|
|
10
|
+
const logger_1 = __importDefault(require("../lib/logger"));
|
|
11
|
+
class RootCmd extends commander_1.Command {
|
|
12
|
+
createCommand(name) {
|
|
13
|
+
const cmd = new commander_1.Command(name);
|
|
14
|
+
cmd.option("-l, --log-level [level]", "Log level: debug, info, warn, error", "info");
|
|
15
|
+
cmd.hook("preAction", run => {
|
|
16
|
+
logger_1.default.SetLogLevel(run.opts().logLevel);
|
|
17
|
+
});
|
|
18
|
+
return cmd;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.RootCmd = RootCmd;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
4
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
+
};
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const child_process_1 = require("child_process");
|
|
9
|
+
const chokidar_1 = require("chokidar");
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
const util_1 = require("util");
|
|
12
|
+
const logger_1 = __importDefault(require("../lib/logger"));
|
|
13
|
+
const build_1 = require("./build");
|
|
14
|
+
const exec = (0, util_1.promisify)(child_process_1.exec);
|
|
15
|
+
function default_1(program) {
|
|
16
|
+
program
|
|
17
|
+
.command("test")
|
|
18
|
+
.description("Test a Pepr Module locally")
|
|
19
|
+
.option("-d, --dir [directory]", "Pepr module directory", ".")
|
|
20
|
+
.option("-w, --watch", "Watch for changes and re-run the test")
|
|
21
|
+
.action(async (opts) => {
|
|
22
|
+
logger_1.default.info("Test Module");
|
|
23
|
+
await buildAndTest(opts.dir);
|
|
24
|
+
if (opts.watch) {
|
|
25
|
+
const moduleFiles = (0, path_1.resolve)(opts.dir, "**", "*.ts");
|
|
26
|
+
const watcher = (0, chokidar_1.watch)(moduleFiles);
|
|
27
|
+
watcher.on("ready", () => {
|
|
28
|
+
logger_1.default.info(`Watching for changes in ${moduleFiles}`);
|
|
29
|
+
watcher.on("all", async (event, path) => {
|
|
30
|
+
logger_1.default.debug({ event, path }, "File changed");
|
|
31
|
+
await buildAndTest(opts.dir);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
exports.default = default_1;
|
|
38
|
+
async function buildAndTest(dir) {
|
|
39
|
+
const { path } = await (0, build_1.buildModule)(dir);
|
|
40
|
+
logger_1.default.info(`Module built successfully at ${path}`);
|
|
41
|
+
try {
|
|
42
|
+
const { stdout, stderr } = await exec(`node ${path}`);
|
|
43
|
+
console.log(stdout);
|
|
44
|
+
console.log(stderr);
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
logger_1.default.debug(e);
|
|
48
|
+
logger_1.default.error(`Error running module: ${e}`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Binding, CapabilityCfg, GenericClass, HookPhase, WhenSelector } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* A capability is a unit of functionality that can be registered with the Pepr runtime.
|
|
4
|
+
*/
|
|
5
|
+
export declare class Capability implements CapabilityCfg {
|
|
6
|
+
private _name;
|
|
7
|
+
private _description;
|
|
8
|
+
private _namespaces?;
|
|
9
|
+
private _mutateOrValidate;
|
|
10
|
+
private _bindings;
|
|
11
|
+
get bindings(): Binding[];
|
|
12
|
+
get name(): string;
|
|
13
|
+
get description(): string;
|
|
14
|
+
get namespaces(): string[];
|
|
15
|
+
get mutateOrValidate(): HookPhase;
|
|
16
|
+
constructor(cfg: CapabilityCfg);
|
|
17
|
+
/**
|
|
18
|
+
* The When method is used to register a capability action to be executed when a Kubernetes resource is
|
|
19
|
+
* processed by Pepr. The action will be executed if the resource matches the specified kind and any
|
|
20
|
+
* filters that are applied.
|
|
21
|
+
*
|
|
22
|
+
* @param model if using a custom KubernetesObject not available in `a.*`, specify the GroupVersionKind
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
25
|
+
When: <T extends GenericClass>(model: T) => WhenSelector<T>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
4
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
+
};
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.Capability = void 0;
|
|
9
|
+
const k8s_1 = require("./k8s");
|
|
10
|
+
const logger_1 = __importDefault(require("./logger"));
|
|
11
|
+
const types_1 = require("./types");
|
|
12
|
+
/**
|
|
13
|
+
* A capability is a unit of functionality that can be registered with the Pepr runtime.
|
|
14
|
+
*/
|
|
15
|
+
class Capability {
|
|
16
|
+
get bindings() {
|
|
17
|
+
return this._bindings;
|
|
18
|
+
}
|
|
19
|
+
get name() {
|
|
20
|
+
return this._name;
|
|
21
|
+
}
|
|
22
|
+
get description() {
|
|
23
|
+
return this._description;
|
|
24
|
+
}
|
|
25
|
+
get namespaces() {
|
|
26
|
+
return this._namespaces || [];
|
|
27
|
+
}
|
|
28
|
+
get mutateOrValidate() {
|
|
29
|
+
return this._mutateOrValidate;
|
|
30
|
+
}
|
|
31
|
+
constructor(cfg) {
|
|
32
|
+
// Currently everything is considered a mutation
|
|
33
|
+
this._mutateOrValidate = types_1.HookPhase.mutate;
|
|
34
|
+
this._bindings = [];
|
|
35
|
+
/**
|
|
36
|
+
* The When method is used to register a capability action to be executed when a Kubernetes resource is
|
|
37
|
+
* processed by Pepr. The action will be executed if the resource matches the specified kind and any
|
|
38
|
+
* filters that are applied.
|
|
39
|
+
*
|
|
40
|
+
* @param model if using a custom KubernetesObject not available in `a.*`, specify the GroupVersionKind
|
|
41
|
+
* @returns
|
|
42
|
+
*/
|
|
43
|
+
this.When = (model) => {
|
|
44
|
+
const binding = {
|
|
45
|
+
// If the kind is not specified, use the default KubernetesObject
|
|
46
|
+
kind: (0, k8s_1.modelToGroupVersionKind)(model.name),
|
|
47
|
+
filters: {
|
|
48
|
+
name: "",
|
|
49
|
+
namespaces: [],
|
|
50
|
+
labels: {},
|
|
51
|
+
annotations: {},
|
|
52
|
+
},
|
|
53
|
+
callback: () => null,
|
|
54
|
+
};
|
|
55
|
+
const prefix = `${this._name}: ${model.name}`;
|
|
56
|
+
logger_1.default.info(`Binding created`, prefix);
|
|
57
|
+
const Then = (cb) => {
|
|
58
|
+
logger_1.default.info(`Binding action created`, prefix);
|
|
59
|
+
logger_1.default.debug(cb.toString(), prefix);
|
|
60
|
+
// Push the binding to the list of bindings for this capability as a new BindingAction
|
|
61
|
+
// with the callback function to preserve
|
|
62
|
+
this._bindings.push({
|
|
63
|
+
...binding,
|
|
64
|
+
callback: cb,
|
|
65
|
+
});
|
|
66
|
+
// Now only allow adding actions to the same binding
|
|
67
|
+
return { Then };
|
|
68
|
+
};
|
|
69
|
+
const ThenSet = (merge) => {
|
|
70
|
+
// Add the new action to the binding
|
|
71
|
+
Then(req => req.Merge(merge));
|
|
72
|
+
return { Then };
|
|
73
|
+
};
|
|
74
|
+
function InNamespace(...namespaces) {
|
|
75
|
+
logger_1.default.debug(`Add namespaces filter ${namespaces}`, prefix);
|
|
76
|
+
binding.filters.namespaces.push(...namespaces);
|
|
77
|
+
return { WithLabel, WithAnnotation, WithName, Then, ThenSet };
|
|
78
|
+
}
|
|
79
|
+
function WithName(name) {
|
|
80
|
+
logger_1.default.debug(`Add name filter ${name}`, prefix);
|
|
81
|
+
binding.filters.name = name;
|
|
82
|
+
return { WithLabel, WithAnnotation, Then, ThenSet };
|
|
83
|
+
}
|
|
84
|
+
function WithLabel(key, value = "") {
|
|
85
|
+
logger_1.default.debug(`Add label filter ${key}=${value}`, prefix);
|
|
86
|
+
binding.filters.labels[key] = value;
|
|
87
|
+
return { WithLabel, WithAnnotation, Then, ThenSet };
|
|
88
|
+
}
|
|
89
|
+
const WithAnnotation = (key, value = "") => {
|
|
90
|
+
logger_1.default.debug(`Add annotation filter ${key}=${value}`, prefix);
|
|
91
|
+
binding.filters.annotations[key] = value;
|
|
92
|
+
return { WithLabel, WithAnnotation, Then, ThenSet };
|
|
93
|
+
};
|
|
94
|
+
const bindEvent = (event) => {
|
|
95
|
+
binding.event = event;
|
|
96
|
+
return {
|
|
97
|
+
InNamespace,
|
|
98
|
+
Then,
|
|
99
|
+
ThenSet,
|
|
100
|
+
WithAnnotation,
|
|
101
|
+
WithLabel,
|
|
102
|
+
WithName,
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
return {
|
|
106
|
+
IsCreatedOrUpdated: () => bindEvent(types_1.Event.CreateOrUpdate),
|
|
107
|
+
IsCreated: () => bindEvent(types_1.Event.Create),
|
|
108
|
+
IsUpdated: () => bindEvent(types_1.Event.Update),
|
|
109
|
+
IsDeleted: () => bindEvent(types_1.Event.Delete),
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
this._name = cfg.name;
|
|
113
|
+
this._description = cfg.description;
|
|
114
|
+
this._namespaces = cfg.namespaces;
|
|
115
|
+
logger_1.default.info(`Capability ${this._name} registered`);
|
|
116
|
+
logger_1.default.debug(cfg);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.Capability = Capability;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ModuleConfig } from "./types";
|
|
2
|
+
import { Capability } from "./capability";
|
|
3
|
+
export declare class Controller {
|
|
4
|
+
private readonly config;
|
|
5
|
+
private readonly capabilities;
|
|
6
|
+
private readonly app;
|
|
7
|
+
constructor(config: ModuleConfig, capabilities: Capability[]);
|
|
8
|
+
/** Start the webhook server */
|
|
9
|
+
startServer: (port: number) => void;
|
|
10
|
+
private logger;
|
|
11
|
+
private healthz;
|
|
12
|
+
private mutate;
|
|
13
|
+
}
|