pepr 0.3.1 → 0.4.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.
- package/README.md +1 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1420 -0
- package/dist/controller.js +157 -0
- package/dist/{src/lib → lib}/capability.d.ts +1 -1
- package/dist/lib/capability.d.ts.map +1 -0
- package/dist/lib/controller.d.ts.map +1 -0
- package/dist/{src/lib → lib}/fetch.d.ts +1 -2
- package/dist/lib/fetch.d.ts.map +1 -0
- package/dist/{src/lib → lib}/filter.d.ts +1 -1
- package/dist/lib/filter.d.ts.map +1 -0
- package/dist/lib/k8s/index.d.ts.map +1 -0
- package/dist/lib/k8s/kinds.d.ts.map +1 -0
- package/dist/lib/k8s/tls.d.ts.map +1 -0
- package/dist/lib/k8s/types.d.ts.map +1 -0
- package/dist/{src/lib → lib}/k8s/upstream.d.ts +2 -2
- package/dist/lib/k8s/upstream.d.ts.map +1 -0
- package/dist/{src/lib → lib}/k8s/webhook.d.ts +1 -1
- package/dist/lib/k8s/webhook.d.ts.map +1 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/module.d.ts.map +1 -0
- package/dist/lib/processor.d.ts.map +1 -0
- package/dist/{src/lib → lib}/request.d.ts +1 -1
- package/dist/lib/request.d.ts.map +1 -0
- package/dist/{src/lib → lib}/types.d.ts +5 -1
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/{src/lib/index.d.ts → lib.d.ts} +8 -8
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +1150 -0
- package/dist/lib.js.map +7 -0
- package/package.json +13 -17
- package/src/cli.ts +37 -0
- package/src/lib/capability.ts +2 -1
- package/src/lib/controller.ts +15 -1
- package/src/lib/fetch.ts +3 -2
- package/src/lib/filter.ts +1 -1
- package/src/lib/k8s/upstream.ts +2 -2
- package/src/lib/k8s/webhook.ts +8 -3
- package/src/lib/module.ts +3 -2
- package/src/lib/processor.ts +2 -2
- package/src/lib/request.ts +4 -4
- package/src/lib/types.ts +6 -1
- package/src/{lib/index.ts → lib.ts} +7 -7
- package/dist/package.json +0 -66
- package/dist/src/cli/banner.js +0 -70
- package/dist/src/cli/build.js +0 -120
- package/dist/src/cli/capability.js +0 -14
- package/dist/src/cli/deploy.js +0 -54
- package/dist/src/cli/dev.js +0 -114
- package/dist/src/cli/index.js +0 -35
- package/dist/src/cli/init/index.js +0 -81
- package/dist/src/cli/init/templates/.prettierrc.json +0 -13
- package/dist/src/cli/init/templates/capabilities/hello-pepr.samples.json +0 -115
- package/dist/src/cli/init/templates/data.json +0 -1
- package/dist/src/cli/init/templates/pepr.code-snippets.json +0 -21
- package/dist/src/cli/init/templates/tsconfig.module.json +0 -12
- package/dist/src/cli/init/templates.js +0 -96
- package/dist/src/cli/init/utils.js +0 -56
- package/dist/src/cli/init/walkthrough.js +0 -84
- package/dist/src/cli/root.js +0 -21
- package/dist/src/cli/run.js +0 -58
- package/dist/src/cli/test.js +0 -50
- package/dist/src/cli/update.js +0 -58
- package/dist/src/lib/capability.d.ts.map +0 -1
- package/dist/src/lib/capability.js +0 -125
- package/dist/src/lib/controller.d.ts.map +0 -1
- package/dist/src/lib/controller.js +0 -108
- package/dist/src/lib/fetch.d.ts.map +0 -1
- package/dist/src/lib/fetch.js +0 -92
- package/dist/src/lib/filter.d.ts.map +0 -1
- package/dist/src/lib/filter.js +0 -77
- package/dist/src/lib/index.d.ts.map +0 -1
- package/dist/src/lib/index.js +0 -26
- package/dist/src/lib/k8s/index.d.ts.map +0 -1
- package/dist/src/lib/k8s/index.js +0 -39
- package/dist/src/lib/k8s/kinds.d.ts.map +0 -1
- package/dist/src/lib/k8s/kinds.js +0 -447
- package/dist/src/lib/k8s/tls.d.ts.map +0 -1
- package/dist/src/lib/k8s/tls.js +0 -74
- package/dist/src/lib/k8s/types.d.ts.map +0 -1
- package/dist/src/lib/k8s/types.js +0 -20
- package/dist/src/lib/k8s/upstream.d.ts.map +0 -1
- package/dist/src/lib/k8s/upstream.js +0 -50
- package/dist/src/lib/k8s/webhook.d.ts.map +0 -1
- package/dist/src/lib/k8s/webhook.js +0 -502
- package/dist/src/lib/logger.d.ts.map +0 -1
- package/dist/src/lib/logger.js +0 -125
- package/dist/src/lib/module.d.ts.map +0 -1
- package/dist/src/lib/module.js +0 -43
- package/dist/src/lib/processor.d.ts.map +0 -1
- package/dist/src/lib/processor.js +0 -85
- package/dist/src/lib/request.d.ts.map +0 -1
- package/dist/src/lib/request.js +0 -124
- package/dist/src/lib/types.d.ts.map +0 -1
- package/dist/src/lib/types.js +0 -34
- /package/dist/{src/lib → lib}/controller.d.ts +0 -0
- /package/dist/{src/lib → lib}/k8s/index.d.ts +0 -0
- /package/dist/{src/lib → lib}/k8s/kinds.d.ts +0 -0
- /package/dist/{src/lib → lib}/k8s/tls.d.ts +0 -0
- /package/dist/{src/lib → lib}/k8s/types.d.ts +0 -0
- /package/dist/{src/lib → lib}/logger.d.ts +0 -0
- /package/dist/{src/lib → lib}/module.d.ts +0 -0
- /package/dist/{src/lib → lib}/processor.d.ts +0 -0
package/dist/lib.js
ADDED
|
@@ -0,0 +1,1150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/lib.ts
|
|
31
|
+
var lib_exports = {};
|
|
32
|
+
__export(lib_exports, {
|
|
33
|
+
Capability: () => Capability,
|
|
34
|
+
Log: () => logger_default,
|
|
35
|
+
PeprModule: () => PeprModule,
|
|
36
|
+
PeprRequest: () => PeprRequest,
|
|
37
|
+
RegisterKind: () => RegisterKind,
|
|
38
|
+
a: () => upstream_exports,
|
|
39
|
+
fetch: () => fetch,
|
|
40
|
+
fetchRaw: () => fetchRaw,
|
|
41
|
+
fetchStatus: () => import_http_status_codes2.StatusCodes,
|
|
42
|
+
k8s: () => import_client_node2.default,
|
|
43
|
+
utils: () => utils
|
|
44
|
+
});
|
|
45
|
+
module.exports = __toCommonJS(lib_exports);
|
|
46
|
+
var import_client_node2 = __toESM(require("@kubernetes/client-node"));
|
|
47
|
+
var import_http_status_codes2 = require("http-status-codes");
|
|
48
|
+
var utils = __toESM(require("ramda"));
|
|
49
|
+
|
|
50
|
+
// src/lib/k8s/upstream.ts
|
|
51
|
+
var upstream_exports = {};
|
|
52
|
+
__export(upstream_exports, {
|
|
53
|
+
APIService: () => import_client_node.V1APIService,
|
|
54
|
+
CSIDriver: () => import_client_node.V1CSIDriver,
|
|
55
|
+
CSIStorageCapacity: () => import_client_node.V1CSIStorageCapacity,
|
|
56
|
+
CertificateSigningRequest: () => import_client_node.V1CertificateSigningRequest,
|
|
57
|
+
ConfigMap: () => import_client_node.V1ConfigMap,
|
|
58
|
+
ControllerRevision: () => import_client_node.V1ControllerRevision,
|
|
59
|
+
CronJob: () => import_client_node.V1CronJob,
|
|
60
|
+
CustomResourceDefinition: () => import_client_node.V1CustomResourceDefinition,
|
|
61
|
+
DaemonSet: () => import_client_node.V1DaemonSet,
|
|
62
|
+
Deployment: () => import_client_node.V1Deployment,
|
|
63
|
+
EndpointSlice: () => import_client_node.V1EndpointSlice,
|
|
64
|
+
GenericKind: () => GenericKind,
|
|
65
|
+
HorizontalPodAutoscaler: () => import_client_node.V1HorizontalPodAutoscaler,
|
|
66
|
+
Ingress: () => import_client_node.V1Ingress,
|
|
67
|
+
IngressClass: () => import_client_node.V1IngressClass,
|
|
68
|
+
Job: () => import_client_node.V1Job,
|
|
69
|
+
LimitRange: () => import_client_node.V1LimitRange,
|
|
70
|
+
LocalSubjectAccessReview: () => import_client_node.V1LocalSubjectAccessReview,
|
|
71
|
+
MutatingWebhookConfiguration: () => import_client_node.V1MutatingWebhookConfiguration,
|
|
72
|
+
Namespace: () => import_client_node.V1Namespace,
|
|
73
|
+
NetworkPolicy: () => import_client_node.V1NetworkPolicy,
|
|
74
|
+
Node: () => import_client_node.V1Node,
|
|
75
|
+
PersistentVolume: () => import_client_node.V1PersistentVolume,
|
|
76
|
+
PersistentVolumeClaim: () => import_client_node.V1PersistentVolumeClaim,
|
|
77
|
+
Pod: () => import_client_node.V1Pod,
|
|
78
|
+
PodDisruptionBudget: () => import_client_node.V1PodDisruptionBudget,
|
|
79
|
+
PodTemplate: () => import_client_node.V1PodTemplate,
|
|
80
|
+
ReplicaSet: () => import_client_node.V1ReplicaSet,
|
|
81
|
+
ReplicationController: () => import_client_node.V1ReplicationController,
|
|
82
|
+
ResourceQuota: () => import_client_node.V1ResourceQuota,
|
|
83
|
+
RuntimeClass: () => import_client_node.V1RuntimeClass,
|
|
84
|
+
Secret: () => import_client_node.V1Secret,
|
|
85
|
+
SelfSubjectAccessReview: () => import_client_node.V1SelfSubjectAccessReview,
|
|
86
|
+
SelfSubjectRulesReview: () => import_client_node.V1SelfSubjectRulesReview,
|
|
87
|
+
Service: () => import_client_node.V1Service,
|
|
88
|
+
ServiceAccount: () => import_client_node.V1ServiceAccount,
|
|
89
|
+
StatefulSet: () => import_client_node.V1StatefulSet,
|
|
90
|
+
StorageClass: () => import_client_node.V1StorageClass,
|
|
91
|
+
SubjectAccessReview: () => import_client_node.V1SubjectAccessReview,
|
|
92
|
+
TokenReview: () => import_client_node.V1TokenReview,
|
|
93
|
+
ValidatingWebhookConfiguration: () => import_client_node.V1ValidatingWebhookConfiguration,
|
|
94
|
+
VolumeAttachment: () => import_client_node.V1VolumeAttachment
|
|
95
|
+
});
|
|
96
|
+
var import_client_node = require("@kubernetes/client-node");
|
|
97
|
+
|
|
98
|
+
// src/lib/k8s/types.ts
|
|
99
|
+
var GenericKind = class {
|
|
100
|
+
apiVersion;
|
|
101
|
+
kind;
|
|
102
|
+
metadata;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// src/lib/k8s/kinds.ts
|
|
106
|
+
var gvkMap = {
|
|
107
|
+
/**
|
|
108
|
+
* Represents a K8s ConfigMap resource.
|
|
109
|
+
* ConfigMap holds configuration data for pods to consume.
|
|
110
|
+
* @see {@link https://kubernetes.io/docs/concepts/configuration/configmap/}
|
|
111
|
+
*/
|
|
112
|
+
V1ConfigMap: {
|
|
113
|
+
kind: "ConfigMap",
|
|
114
|
+
version: "v1",
|
|
115
|
+
group: ""
|
|
116
|
+
},
|
|
117
|
+
/**
|
|
118
|
+
* Represents a K8s Endpoints resource.
|
|
119
|
+
* Endpoints expose a service's IP addresses and ports to other resources.
|
|
120
|
+
* @see {@link https://kubernetes.io/docs/concepts/services-networking/service/#endpoints}
|
|
121
|
+
*/
|
|
122
|
+
V1Endpoint: {
|
|
123
|
+
kind: "Endpoints",
|
|
124
|
+
version: "v1",
|
|
125
|
+
group: ""
|
|
126
|
+
},
|
|
127
|
+
/**
|
|
128
|
+
* Represents a K8s LimitRange resource.
|
|
129
|
+
* LimitRange enforces constraints on the resource consumption of objects in a namespace.
|
|
130
|
+
* @see {@link https://kubernetes.io/docs/concepts/policy/limit-range/}
|
|
131
|
+
*/
|
|
132
|
+
V1LimitRange: {
|
|
133
|
+
kind: "LimitRange",
|
|
134
|
+
version: "v1",
|
|
135
|
+
group: ""
|
|
136
|
+
},
|
|
137
|
+
/**
|
|
138
|
+
* Represents a K8s Namespace resource.
|
|
139
|
+
* Namespace is a way to divide cluster resources between multiple users.
|
|
140
|
+
* @see {@link https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/}
|
|
141
|
+
*/
|
|
142
|
+
V1Namespace: {
|
|
143
|
+
kind: "Namespace",
|
|
144
|
+
version: "v1",
|
|
145
|
+
group: ""
|
|
146
|
+
},
|
|
147
|
+
/**
|
|
148
|
+
* Represents a K8s Node resource.
|
|
149
|
+
* Node is a worker machine in Kubernetes.
|
|
150
|
+
* @see {@link https://kubernetes.io/docs/concepts/architecture/nodes/}
|
|
151
|
+
*/
|
|
152
|
+
V1Node: {
|
|
153
|
+
kind: "Node",
|
|
154
|
+
version: "v1",
|
|
155
|
+
group: ""
|
|
156
|
+
},
|
|
157
|
+
/**
|
|
158
|
+
* Represents a K8s PersistentVolumeClaim resource.
|
|
159
|
+
* PersistentVolumeClaim is a user's request for and claim to a persistent volume.
|
|
160
|
+
* @see {@link https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims}
|
|
161
|
+
*/
|
|
162
|
+
V1PersistentVolumeClaim: {
|
|
163
|
+
kind: "PersistentVolumeClaim",
|
|
164
|
+
version: "v1",
|
|
165
|
+
group: ""
|
|
166
|
+
},
|
|
167
|
+
/**
|
|
168
|
+
* Represents a K8s PersistentVolume resource.
|
|
169
|
+
* PersistentVolume is a piece of storage in the cluster that has been provisioned by an administrator.
|
|
170
|
+
* @see {@link https://kubernetes.io/docs/concepts/storage/persistent-volumes/}
|
|
171
|
+
*/
|
|
172
|
+
V1PersistentVolume: {
|
|
173
|
+
kind: "PersistentVolume",
|
|
174
|
+
version: "v1",
|
|
175
|
+
group: ""
|
|
176
|
+
},
|
|
177
|
+
/**
|
|
178
|
+
* Represents a K8s Pod resource.
|
|
179
|
+
* Pod is the smallest and simplest unit in the Kubernetes object model.
|
|
180
|
+
* @see {@link https://kubernetes.io/docs/concepts/workloads/pods/}
|
|
181
|
+
*/
|
|
182
|
+
V1Pod: {
|
|
183
|
+
kind: "Pod",
|
|
184
|
+
version: "v1",
|
|
185
|
+
group: ""
|
|
186
|
+
},
|
|
187
|
+
/**
|
|
188
|
+
* Represents a K8s PodTemplate resource.
|
|
189
|
+
* PodTemplate is an object that describes the pod that will be created from a higher level abstraction.
|
|
190
|
+
* @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/#pod-template}
|
|
191
|
+
*/
|
|
192
|
+
V1PodTemplate: {
|
|
193
|
+
kind: "PodTemplate",
|
|
194
|
+
version: "v1",
|
|
195
|
+
group: ""
|
|
196
|
+
},
|
|
197
|
+
/**
|
|
198
|
+
* Represents a K8s ReplicationController resource.
|
|
199
|
+
* ReplicationController ensures that a specified number of pod replicas are running at any given time.
|
|
200
|
+
* @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/}
|
|
201
|
+
*/
|
|
202
|
+
V1ReplicationController: {
|
|
203
|
+
kind: "ReplicationController",
|
|
204
|
+
version: "v1",
|
|
205
|
+
group: ""
|
|
206
|
+
},
|
|
207
|
+
/**
|
|
208
|
+
* Represents a K8s ResourceQuota resource.
|
|
209
|
+
* ResourceQuota provides constraints that limit resource consumption per namespace.
|
|
210
|
+
* @see {@link https://kubernetes.io/docs/concepts/policy/resource-quotas/}
|
|
211
|
+
*/
|
|
212
|
+
V1ResourceQuota: {
|
|
213
|
+
kind: "ResourceQuota",
|
|
214
|
+
version: "v1",
|
|
215
|
+
group: ""
|
|
216
|
+
},
|
|
217
|
+
/**
|
|
218
|
+
* Represents a K8s Secret resource.
|
|
219
|
+
* Secret holds secret data of a certain type.
|
|
220
|
+
* @see {@link https://kubernetes.io/docs/concepts/configuration/secret/}
|
|
221
|
+
*/
|
|
222
|
+
V1Secret: {
|
|
223
|
+
kind: "Secret",
|
|
224
|
+
version: "v1",
|
|
225
|
+
group: ""
|
|
226
|
+
},
|
|
227
|
+
/**
|
|
228
|
+
* Represents a K8s ServiceAccount resource.
|
|
229
|
+
* ServiceAccount is an identity that processes in a pod can use to access the Kubernetes API.
|
|
230
|
+
* @see {@link https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/}
|
|
231
|
+
*/
|
|
232
|
+
V1ServiceAccount: {
|
|
233
|
+
kind: "ServiceAccount",
|
|
234
|
+
version: "v1",
|
|
235
|
+
group: ""
|
|
236
|
+
},
|
|
237
|
+
/**
|
|
238
|
+
* Represents a K8s Service resource.
|
|
239
|
+
* Service is an abstraction which defines a logical set of Pods and a policy by which to access them.
|
|
240
|
+
* @see {@link https://kubernetes.io/docs/concepts/services-networking/service/}
|
|
241
|
+
*/
|
|
242
|
+
V1Service: {
|
|
243
|
+
kind: "Service",
|
|
244
|
+
version: "v1",
|
|
245
|
+
group: ""
|
|
246
|
+
},
|
|
247
|
+
/**
|
|
248
|
+
* Represents a K8s MutatingWebhookConfiguration resource.
|
|
249
|
+
* MutatingWebhookConfiguration configures a mutating admission webhook.
|
|
250
|
+
* @see {@link https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#configure-admission-webhooks-on-the-fly}
|
|
251
|
+
*/
|
|
252
|
+
V1MutatingWebhookConfiguration: {
|
|
253
|
+
kind: "MutatingWebhookConfiguration",
|
|
254
|
+
version: "v1",
|
|
255
|
+
group: "admissionregistration.k8s.io"
|
|
256
|
+
},
|
|
257
|
+
/**
|
|
258
|
+
* Represents a K8s ValidatingWebhookConfiguration resource.
|
|
259
|
+
* ValidatingWebhookConfiguration configures a validating admission webhook.
|
|
260
|
+
* @see {@link https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#configure-admission-webhooks-on-the-fly}
|
|
261
|
+
*/
|
|
262
|
+
V1ValidatingWebhookConfiguration: {
|
|
263
|
+
kind: "ValidatingWebhookConfiguration",
|
|
264
|
+
version: "v1",
|
|
265
|
+
group: "admissionregistration.k8s.io"
|
|
266
|
+
},
|
|
267
|
+
/**
|
|
268
|
+
* Represents a K8s CustomResourceDefinition resource.
|
|
269
|
+
* CustomResourceDefinition is a custom resource in a Kubernetes cluster.
|
|
270
|
+
* @see {@link https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/}
|
|
271
|
+
*/
|
|
272
|
+
V1CustomResourceDefinition: {
|
|
273
|
+
kind: "CustomResourceDefinition",
|
|
274
|
+
version: "v1",
|
|
275
|
+
group: "apiextensions.k8s.io"
|
|
276
|
+
},
|
|
277
|
+
/**
|
|
278
|
+
* Represents a K8s APIService resource.
|
|
279
|
+
* APIService represents a server for a particular API version and group.
|
|
280
|
+
* @see {@link https://kubernetes.io/docs/tasks/access-kubernetes-api/setup-extension-api-server/}
|
|
281
|
+
*/
|
|
282
|
+
V1APIService: {
|
|
283
|
+
kind: "APIService",
|
|
284
|
+
version: "v1",
|
|
285
|
+
group: "apiregistration.k8s.io"
|
|
286
|
+
},
|
|
287
|
+
/**
|
|
288
|
+
* Represents a K8s ControllerRevision resource.
|
|
289
|
+
* ControllerRevision is used to manage the history of a StatefulSet or DaemonSet.
|
|
290
|
+
* @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#revision-history}
|
|
291
|
+
*/
|
|
292
|
+
V1ControllerRevision: {
|
|
293
|
+
kind: "ControllerRevision",
|
|
294
|
+
version: "v1",
|
|
295
|
+
group: "apps"
|
|
296
|
+
},
|
|
297
|
+
/**
|
|
298
|
+
* Represents a K8s DaemonSet resource.
|
|
299
|
+
* DaemonSet ensures that all (or some) nodes run a copy of a Pod.
|
|
300
|
+
* @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/}
|
|
301
|
+
*/
|
|
302
|
+
V1DaemonSet: {
|
|
303
|
+
kind: "DaemonSet",
|
|
304
|
+
version: "v1",
|
|
305
|
+
group: "apps"
|
|
306
|
+
},
|
|
307
|
+
/**
|
|
308
|
+
* Represents a K8s Deployment resource.
|
|
309
|
+
* Deployment provides declarative updates for Pods and ReplicaSets.
|
|
310
|
+
* @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/deployment/}
|
|
311
|
+
*/
|
|
312
|
+
V1Deployment: {
|
|
313
|
+
kind: "Deployment",
|
|
314
|
+
version: "v1",
|
|
315
|
+
group: "apps"
|
|
316
|
+
},
|
|
317
|
+
/**
|
|
318
|
+
* Represents a K8s ReplicaSet resource.
|
|
319
|
+
* ReplicaSet ensures that a specified number of pod replicas are running at any given time.
|
|
320
|
+
* @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/}
|
|
321
|
+
*/
|
|
322
|
+
V1ReplicaSet: {
|
|
323
|
+
kind: "ReplicaSet",
|
|
324
|
+
version: "v1",
|
|
325
|
+
group: "apps"
|
|
326
|
+
},
|
|
327
|
+
/**
|
|
328
|
+
* Represents a K8s StatefulSet resource.
|
|
329
|
+
* StatefulSet is used to manage stateful applications.
|
|
330
|
+
* @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/}
|
|
331
|
+
*/
|
|
332
|
+
V1StatefulSet: {
|
|
333
|
+
kind: "StatefulSet",
|
|
334
|
+
version: "v1",
|
|
335
|
+
group: "apps"
|
|
336
|
+
},
|
|
337
|
+
/**
|
|
338
|
+
* Represents a K8s TokenReview resource.
|
|
339
|
+
* TokenReview attempts to authenticate a token to a known user.
|
|
340
|
+
* @see {@link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#tokenreview-v1-authentication-k8s-io}
|
|
341
|
+
*/
|
|
342
|
+
V1TokenReview: {
|
|
343
|
+
kind: "TokenReview",
|
|
344
|
+
version: "v1",
|
|
345
|
+
group: "authentication.k8s.io"
|
|
346
|
+
},
|
|
347
|
+
/**
|
|
348
|
+
* Represents a K8s LocalSubjectAccessReview resource.
|
|
349
|
+
* LocalSubjectAccessReview checks whether a specific user can perform a specific action in a specific namespace.
|
|
350
|
+
* @see {@link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#localsubjectaccessreview-v1-authorization-k8s-io}
|
|
351
|
+
*/
|
|
352
|
+
V1LocalSubjectAccessReview: {
|
|
353
|
+
kind: "LocalSubjectAccessReview",
|
|
354
|
+
version: "v1",
|
|
355
|
+
group: "authorization.k8s.io"
|
|
356
|
+
},
|
|
357
|
+
/**
|
|
358
|
+
* Represents a K8s SelfSubjectAccessReview resource.
|
|
359
|
+
* SelfSubjectAccessReview checks whether the current user can perform a specific action.
|
|
360
|
+
* @see {@link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#selfsubjectaccessreview-v1-authorization-k8s-io}
|
|
361
|
+
*/
|
|
362
|
+
V1SelfSubjectAccessReview: {
|
|
363
|
+
kind: "SelfSubjectAccessReview",
|
|
364
|
+
version: "v1",
|
|
365
|
+
group: "authorization.k8s.io"
|
|
366
|
+
},
|
|
367
|
+
/**
|
|
368
|
+
* Represents a K8s SelfSubjectRulesReview resource.
|
|
369
|
+
* SelfSubjectRulesReview lists the permissions a specific user has within a namespace.
|
|
370
|
+
* @see {@link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#selfsubjectrulesreview-v1-authorization-k8s-io}
|
|
371
|
+
*/
|
|
372
|
+
V1SelfSubjectRulesReview: {
|
|
373
|
+
kind: "SelfSubjectRulesReview",
|
|
374
|
+
version: "v1",
|
|
375
|
+
group: "authorization.k8s.io"
|
|
376
|
+
},
|
|
377
|
+
/**
|
|
378
|
+
* Represents a K8s SubjectAccessReview resource.
|
|
379
|
+
* SubjectAccessReview checks whether a specific user can perform a specific action.
|
|
380
|
+
* @see {@link https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#subjectaccessreview-v1-authorization-k8s-io}
|
|
381
|
+
*/
|
|
382
|
+
V1SubjectAccessReview: {
|
|
383
|
+
kind: "SubjectAccessReview",
|
|
384
|
+
version: "v1",
|
|
385
|
+
group: "authorization.k8s.io"
|
|
386
|
+
},
|
|
387
|
+
/**
|
|
388
|
+
* Represents a K8s HorizontalPodAutoscaler resource.
|
|
389
|
+
* HorizontalPodAutoscaler automatically scales the number of Pods in a replication controller, deployment, or replica set.
|
|
390
|
+
* @see {@link https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/}
|
|
391
|
+
*/
|
|
392
|
+
V1HorizontalPodAutoscaler: {
|
|
393
|
+
kind: "HorizontalPodAutoscaler",
|
|
394
|
+
version: "v2",
|
|
395
|
+
group: "autoscaling"
|
|
396
|
+
},
|
|
397
|
+
/**
|
|
398
|
+
* Represents a K8s CronJob resource.
|
|
399
|
+
* CronJob manages time-based jobs, specifically those that run periodically and complete after a successful execution.
|
|
400
|
+
* @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/}
|
|
401
|
+
*/
|
|
402
|
+
V1CronJob: {
|
|
403
|
+
kind: "CronJob",
|
|
404
|
+
version: "v1",
|
|
405
|
+
group: "batch"
|
|
406
|
+
},
|
|
407
|
+
/**
|
|
408
|
+
* Represents a K8s Job resource.
|
|
409
|
+
* Job represents the configuration of a single job.
|
|
410
|
+
* @see {@link https://kubernetes.io/docs/concepts/workloads/controllers/job/}
|
|
411
|
+
*/
|
|
412
|
+
V1Job: {
|
|
413
|
+
kind: "Job",
|
|
414
|
+
version: "v1",
|
|
415
|
+
group: "batch"
|
|
416
|
+
},
|
|
417
|
+
/**
|
|
418
|
+
* Represents a K8s CertificateSigningRequest resource.
|
|
419
|
+
* CertificateSigningRequest represents a certificate signing request.
|
|
420
|
+
* @see {@link https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/}
|
|
421
|
+
*/
|
|
422
|
+
V1CertificateSigningRequest: {
|
|
423
|
+
kind: "CertificateSigningRequest",
|
|
424
|
+
version: "v1",
|
|
425
|
+
group: "certificates.k8s.io"
|
|
426
|
+
},
|
|
427
|
+
/**
|
|
428
|
+
* Represents a K8s EndpointSlice resource.
|
|
429
|
+
* EndpointSlice represents a scalable set of network endpoints for a Kubernetes Service.
|
|
430
|
+
* @see {@link https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/}
|
|
431
|
+
*/
|
|
432
|
+
V1EndpointSlice: {
|
|
433
|
+
kind: "EndpointSlice",
|
|
434
|
+
version: "v1",
|
|
435
|
+
group: "discovery.k8s.io"
|
|
436
|
+
},
|
|
437
|
+
/**
|
|
438
|
+
* Represents a K8s IngressClass resource.
|
|
439
|
+
* IngressClass represents the class of the Ingress, referenced by the Ingress spec.
|
|
440
|
+
* @see {@link https://kubernetes.io/docs/concepts/services-networking/ingress/}
|
|
441
|
+
*/
|
|
442
|
+
V1IngressClass: {
|
|
443
|
+
kind: "IngressClass",
|
|
444
|
+
version: "v1",
|
|
445
|
+
group: "networking.k8s.io"
|
|
446
|
+
},
|
|
447
|
+
/**
|
|
448
|
+
* Represents a K8s Ingress resource.
|
|
449
|
+
* Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster.
|
|
450
|
+
* @see {@link https://kubernetes.io/docs/concepts/services-networking/ingress/}
|
|
451
|
+
*/
|
|
452
|
+
V1Ingress: {
|
|
453
|
+
kind: "Ingress",
|
|
454
|
+
version: "v1",
|
|
455
|
+
group: "networking.k8s.io"
|
|
456
|
+
},
|
|
457
|
+
/**
|
|
458
|
+
* Represents a K8s NetworkPolicy resource.
|
|
459
|
+
* NetworkPolicy defines a set of rules for how pods communicate with each other.
|
|
460
|
+
* @see {@link https://kubernetes.io/docs/concepts/services-networking/network-policies/}
|
|
461
|
+
*/
|
|
462
|
+
V1NetworkPolicy: {
|
|
463
|
+
kind: "NetworkPolicy",
|
|
464
|
+
version: "v1",
|
|
465
|
+
group: "networking.k8s.io"
|
|
466
|
+
},
|
|
467
|
+
/**
|
|
468
|
+
* Represents a K8s RuntimeClass resource.
|
|
469
|
+
* RuntimeClass is a cluster-scoped resource that surfaces container runtime properties to the control plane.
|
|
470
|
+
* @see {@link https://kubernetes.io/docs/concepts/containers/runtime-class/}
|
|
471
|
+
*/
|
|
472
|
+
V1RuntimeClass: {
|
|
473
|
+
kind: "RuntimeClass",
|
|
474
|
+
version: "v1",
|
|
475
|
+
group: "node.k8s.io"
|
|
476
|
+
},
|
|
477
|
+
/**
|
|
478
|
+
* Represents a K8s PodDisruptionBudget resource.
|
|
479
|
+
* PodDisruptionBudget is an API object that limits the number of pods of a replicated application that are down simultaneously.
|
|
480
|
+
* @see {@link https://kubernetes.io/docs/concepts/workloads/pods/disruptions/}
|
|
481
|
+
*/
|
|
482
|
+
V1PodDisruptionBudget: {
|
|
483
|
+
kind: "PodDisruptionBudget",
|
|
484
|
+
version: "v1",
|
|
485
|
+
group: "policy"
|
|
486
|
+
},
|
|
487
|
+
/**
|
|
488
|
+
* Represents a K8s VolumeAttachment resource.
|
|
489
|
+
* VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node.
|
|
490
|
+
* @see {@link https://kubernetes.io/docs/concepts/storage/storage-classes/}
|
|
491
|
+
*/
|
|
492
|
+
V1VolumeAttachment: {
|
|
493
|
+
kind: "VolumeAttachment",
|
|
494
|
+
version: "v1",
|
|
495
|
+
group: "storage.k8s.io"
|
|
496
|
+
},
|
|
497
|
+
/**
|
|
498
|
+
* Represents a K8s CSIDriver resource.
|
|
499
|
+
* CSIDriver captures information about a Container Storage Interface (CSI) volume driver.
|
|
500
|
+
* @see {@link https://kubernetes.io/docs/concepts/storage/volumes/}
|
|
501
|
+
*/
|
|
502
|
+
V1CSIDriver: {
|
|
503
|
+
kind: "CSIDriver",
|
|
504
|
+
version: "v1",
|
|
505
|
+
group: "storage.k8s.io"
|
|
506
|
+
},
|
|
507
|
+
/**
|
|
508
|
+
* Represents a K8s CSIStorageCapacity resource.
|
|
509
|
+
* CSIStorageCapacity stores the reported storage capacity of a CSI node or storage class.
|
|
510
|
+
* @see {@link https://kubernetes.io/docs/concepts/storage/csi/}
|
|
511
|
+
*/
|
|
512
|
+
V1CSIStorageCapacity: {
|
|
513
|
+
kind: "CSIStorageCapacity",
|
|
514
|
+
version: "v1",
|
|
515
|
+
group: "storage.k8s.io"
|
|
516
|
+
},
|
|
517
|
+
/**
|
|
518
|
+
* Represents a K8s StorageClass resource.
|
|
519
|
+
* StorageClass is a cluster-scoped resource that provides a way for administrators to describe the classes of storage they offer.
|
|
520
|
+
* @see {@link https://kubernetes.io/docs/concepts/storage/storage-classes/}
|
|
521
|
+
*/
|
|
522
|
+
V1StorageClass: {
|
|
523
|
+
kind: "StorageClass",
|
|
524
|
+
version: "v1",
|
|
525
|
+
group: "storage.k8s.io"
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
function modelToGroupVersionKind(key) {
|
|
529
|
+
return gvkMap[key];
|
|
530
|
+
}
|
|
531
|
+
var RegisterKind = (model, groupVersionKind) => {
|
|
532
|
+
const name = model.name;
|
|
533
|
+
if (gvkMap[name]) {
|
|
534
|
+
throw new Error(`GVK ${name} already registered`);
|
|
535
|
+
}
|
|
536
|
+
gvkMap[name] = groupVersionKind;
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
// src/lib/logger.ts
|
|
540
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
541
|
+
LogLevel2[LogLevel2["debug"] = 0] = "debug";
|
|
542
|
+
LogLevel2[LogLevel2["info"] = 1] = "info";
|
|
543
|
+
LogLevel2[LogLevel2["warn"] = 2] = "warn";
|
|
544
|
+
LogLevel2[LogLevel2["error"] = 3] = "error";
|
|
545
|
+
return LogLevel2;
|
|
546
|
+
})(LogLevel || {});
|
|
547
|
+
var Logger = class {
|
|
548
|
+
_logLevel;
|
|
549
|
+
/**
|
|
550
|
+
* Create a new logger instance.
|
|
551
|
+
* @param logLevel - The minimum log level to log messages for.
|
|
552
|
+
*/
|
|
553
|
+
constructor(logLevel) {
|
|
554
|
+
this._logLevel = logLevel;
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Change the log level of the logger.
|
|
558
|
+
* @param logLevel - The log level to log the message at.
|
|
559
|
+
*/
|
|
560
|
+
SetLogLevel(logLevel) {
|
|
561
|
+
this._logLevel = LogLevel[logLevel];
|
|
562
|
+
this.debug(`Log level set to ${logLevel}`);
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Log a debug message.
|
|
566
|
+
* @param message - The message to log.
|
|
567
|
+
*/
|
|
568
|
+
debug(message, prefix) {
|
|
569
|
+
this.log(0 /* debug */, message, prefix);
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Log an info message.
|
|
573
|
+
* @param message - The message to log.
|
|
574
|
+
*/
|
|
575
|
+
info(message, prefix) {
|
|
576
|
+
this.log(1 /* info */, message, prefix);
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Log a warning message.
|
|
580
|
+
* @param message - The message to log.
|
|
581
|
+
*/
|
|
582
|
+
warn(message, prefix) {
|
|
583
|
+
this.log(2 /* warn */, message, prefix);
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Log an error message.
|
|
587
|
+
* @param message - The message to log.
|
|
588
|
+
*/
|
|
589
|
+
error(message, prefix) {
|
|
590
|
+
this.log(3 /* error */, message, prefix);
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Log a message at the specified log level.
|
|
594
|
+
* @param logLevel - The log level of the message.
|
|
595
|
+
* @param message - The message to log.
|
|
596
|
+
*/
|
|
597
|
+
log(logLevel, message, callerPrefix = "") {
|
|
598
|
+
const color = {
|
|
599
|
+
[0 /* debug */]: "\x1B[30m" /* FgBlack */,
|
|
600
|
+
[1 /* info */]: "\x1B[36m" /* FgCyan */,
|
|
601
|
+
[2 /* warn */]: "\x1B[33m" /* FgYellow */,
|
|
602
|
+
[3 /* error */]: "\x1B[31m" /* FgRed */
|
|
603
|
+
};
|
|
604
|
+
if (logLevel >= this._logLevel) {
|
|
605
|
+
let prefix = "[" + LogLevel[logLevel] + "] " + callerPrefix;
|
|
606
|
+
prefix = this.colorize(prefix, color[logLevel]);
|
|
607
|
+
if (typeof message !== "string") {
|
|
608
|
+
console.log(prefix);
|
|
609
|
+
console.debug("%o", message);
|
|
610
|
+
} else {
|
|
611
|
+
console.log(prefix + " " + message);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
colorize(text, color) {
|
|
616
|
+
return color + text + "\x1B[0m" /* Reset */;
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
var Log = new Logger(1 /* info */);
|
|
620
|
+
if (process.env.LOG_LEVEL) {
|
|
621
|
+
Log.SetLogLevel(process.env.LOG_LEVEL);
|
|
622
|
+
}
|
|
623
|
+
var logger_default = Log;
|
|
624
|
+
|
|
625
|
+
// src/lib/capability.ts
|
|
626
|
+
var Capability = class {
|
|
627
|
+
_name;
|
|
628
|
+
_description;
|
|
629
|
+
_namespaces;
|
|
630
|
+
// Currently everything is considered a mutation
|
|
631
|
+
_mutateOrValidate = "mutate" /* mutate */;
|
|
632
|
+
_bindings = [];
|
|
633
|
+
get bindings() {
|
|
634
|
+
return this._bindings;
|
|
635
|
+
}
|
|
636
|
+
get name() {
|
|
637
|
+
return this._name;
|
|
638
|
+
}
|
|
639
|
+
get description() {
|
|
640
|
+
return this._description;
|
|
641
|
+
}
|
|
642
|
+
get namespaces() {
|
|
643
|
+
return this._namespaces || [];
|
|
644
|
+
}
|
|
645
|
+
get mutateOrValidate() {
|
|
646
|
+
return this._mutateOrValidate;
|
|
647
|
+
}
|
|
648
|
+
constructor(cfg) {
|
|
649
|
+
this._name = cfg.name;
|
|
650
|
+
this._description = cfg.description;
|
|
651
|
+
this._namespaces = cfg.namespaces;
|
|
652
|
+
logger_default.info(`Capability ${this._name} registered`);
|
|
653
|
+
logger_default.debug(cfg);
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* The When method is used to register a capability action to be executed when a Kubernetes resource is
|
|
657
|
+
* processed by Pepr. The action will be executed if the resource matches the specified kind and any
|
|
658
|
+
* filters that are applied.
|
|
659
|
+
*
|
|
660
|
+
* @param model the KubernetesObject model to match
|
|
661
|
+
* @param kind if using a custom KubernetesObject not available in `a.*`, specify the GroupVersionKind
|
|
662
|
+
* @returns
|
|
663
|
+
*/
|
|
664
|
+
When = (model, kind) => {
|
|
665
|
+
const matchedKind = modelToGroupVersionKind(model.name);
|
|
666
|
+
if (!matchedKind && !kind) {
|
|
667
|
+
throw new Error(`Kind not specified for ${model.name}`);
|
|
668
|
+
}
|
|
669
|
+
const binding = {
|
|
670
|
+
// If the kind is not specified, use the matched kind from the model
|
|
671
|
+
kind: kind || matchedKind,
|
|
672
|
+
filters: {
|
|
673
|
+
name: "",
|
|
674
|
+
namespaces: [],
|
|
675
|
+
labels: {},
|
|
676
|
+
annotations: {}
|
|
677
|
+
},
|
|
678
|
+
callback: () => void 0
|
|
679
|
+
};
|
|
680
|
+
const prefix = `${this._name}: ${model.name}`;
|
|
681
|
+
logger_default.info(`Binding created`, prefix);
|
|
682
|
+
const Then = (cb) => {
|
|
683
|
+
logger_default.info(`Binding action created`, prefix);
|
|
684
|
+
logger_default.debug(cb.toString(), prefix);
|
|
685
|
+
this._bindings.push({
|
|
686
|
+
...binding,
|
|
687
|
+
callback: cb
|
|
688
|
+
});
|
|
689
|
+
return { Then };
|
|
690
|
+
};
|
|
691
|
+
const ThenSet = (merge) => {
|
|
692
|
+
Then((req) => req.Merge(merge));
|
|
693
|
+
return { Then };
|
|
694
|
+
};
|
|
695
|
+
function InNamespace(...namespaces) {
|
|
696
|
+
logger_default.debug(`Add namespaces filter ${namespaces}`, prefix);
|
|
697
|
+
binding.filters.namespaces.push(...namespaces);
|
|
698
|
+
return { WithLabel, WithAnnotation, WithName, Then, ThenSet };
|
|
699
|
+
}
|
|
700
|
+
function WithName(name) {
|
|
701
|
+
logger_default.debug(`Add name filter ${name}`, prefix);
|
|
702
|
+
binding.filters.name = name;
|
|
703
|
+
return { WithLabel, WithAnnotation, Then, ThenSet };
|
|
704
|
+
}
|
|
705
|
+
function WithLabel(key, value = "") {
|
|
706
|
+
logger_default.debug(`Add label filter ${key}=${value}`, prefix);
|
|
707
|
+
binding.filters.labels[key] = value;
|
|
708
|
+
return { WithLabel, WithAnnotation, Then, ThenSet };
|
|
709
|
+
}
|
|
710
|
+
const WithAnnotation = (key, value = "") => {
|
|
711
|
+
logger_default.debug(`Add annotation filter ${key}=${value}`, prefix);
|
|
712
|
+
binding.filters.annotations[key] = value;
|
|
713
|
+
return { WithLabel, WithAnnotation, Then, ThenSet };
|
|
714
|
+
};
|
|
715
|
+
const bindEvent = (event) => {
|
|
716
|
+
binding.event = event;
|
|
717
|
+
return {
|
|
718
|
+
InNamespace,
|
|
719
|
+
Then,
|
|
720
|
+
ThenSet,
|
|
721
|
+
WithAnnotation,
|
|
722
|
+
WithLabel,
|
|
723
|
+
WithName
|
|
724
|
+
};
|
|
725
|
+
};
|
|
726
|
+
return {
|
|
727
|
+
IsCreatedOrUpdated: () => bindEvent("CREATEORUPDATE" /* CreateOrUpdate */),
|
|
728
|
+
IsCreated: () => bindEvent("CREATE" /* Create */),
|
|
729
|
+
IsUpdated: () => bindEvent("UPDATE" /* Update */),
|
|
730
|
+
IsDeleted: () => bindEvent("DELETE" /* Delete */)
|
|
731
|
+
};
|
|
732
|
+
};
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
// src/lib/fetch.ts
|
|
736
|
+
var import_http_status_codes = require("http-status-codes");
|
|
737
|
+
var import_node_fetch = __toESM(require("node-fetch"));
|
|
738
|
+
var fetchRaw = import_node_fetch.default;
|
|
739
|
+
async function fetch(url, init) {
|
|
740
|
+
let data = void 0;
|
|
741
|
+
try {
|
|
742
|
+
logger_default.debug(`Fetching ${url}`);
|
|
743
|
+
const resp = await fetchRaw(url, init);
|
|
744
|
+
const contentType = resp.headers.get("content-type") || "";
|
|
745
|
+
if (resp.ok) {
|
|
746
|
+
if (contentType.includes("application/json")) {
|
|
747
|
+
data = await resp.json();
|
|
748
|
+
} else {
|
|
749
|
+
data = await resp.text();
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
return {
|
|
753
|
+
data,
|
|
754
|
+
ok: resp.ok,
|
|
755
|
+
status: resp.status,
|
|
756
|
+
statusText: resp.statusText
|
|
757
|
+
};
|
|
758
|
+
} catch (e) {
|
|
759
|
+
if (e instanceof import_node_fetch.FetchError) {
|
|
760
|
+
logger_default.debug(`Fetch failed: ${e instanceof Error ? e.message : e}`);
|
|
761
|
+
const status = parseInt(e.code || "400");
|
|
762
|
+
return {
|
|
763
|
+
data,
|
|
764
|
+
ok: false,
|
|
765
|
+
status,
|
|
766
|
+
statusText: e.message
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
return {
|
|
770
|
+
data,
|
|
771
|
+
ok: false,
|
|
772
|
+
status: import_http_status_codes.StatusCodes.BAD_REQUEST,
|
|
773
|
+
statusText: "Unknown error"
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// src/lib/module.ts
|
|
779
|
+
var import_ramda2 = require("ramda");
|
|
780
|
+
|
|
781
|
+
// src/lib/controller.ts
|
|
782
|
+
var import_express = __toESM(require("express"));
|
|
783
|
+
var import_fs = __toESM(require("fs"));
|
|
784
|
+
var import_https = __toESM(require("https"));
|
|
785
|
+
|
|
786
|
+
// src/lib/processor.ts
|
|
787
|
+
var import_fast_json_patch = __toESM(require("fast-json-patch"));
|
|
788
|
+
|
|
789
|
+
// src/lib/filter.ts
|
|
790
|
+
function shouldSkipRequest(binding, req) {
|
|
791
|
+
const { group, kind, version } = binding.kind || {};
|
|
792
|
+
const { namespaces, labels, annotations, name } = binding.filters || {};
|
|
793
|
+
const { metadata } = req.object || {};
|
|
794
|
+
if (binding.event && !binding.event.includes(req.operation)) {
|
|
795
|
+
return true;
|
|
796
|
+
}
|
|
797
|
+
if (name && name !== req.name) {
|
|
798
|
+
return true;
|
|
799
|
+
}
|
|
800
|
+
if (kind !== req.kind.kind) {
|
|
801
|
+
return true;
|
|
802
|
+
}
|
|
803
|
+
if (group && group !== req.kind.group) {
|
|
804
|
+
return true;
|
|
805
|
+
}
|
|
806
|
+
if (version && version !== req.kind.version) {
|
|
807
|
+
return true;
|
|
808
|
+
}
|
|
809
|
+
if (namespaces.length && !namespaces.includes(req.namespace || "")) {
|
|
810
|
+
logger_default.debug("Namespace does not match");
|
|
811
|
+
return true;
|
|
812
|
+
}
|
|
813
|
+
for (const [key, value] of Object.entries(labels)) {
|
|
814
|
+
const testKey = metadata?.labels?.[key];
|
|
815
|
+
if (!testKey) {
|
|
816
|
+
logger_default.debug(`Label ${key} does not exist`);
|
|
817
|
+
return true;
|
|
818
|
+
}
|
|
819
|
+
if (value && testKey !== value) {
|
|
820
|
+
logger_default.debug(`${testKey} does not match ${value}`);
|
|
821
|
+
return true;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
for (const [key, value] of Object.entries(annotations)) {
|
|
825
|
+
const testKey = metadata?.annotations?.[key];
|
|
826
|
+
if (!testKey) {
|
|
827
|
+
logger_default.debug(`Annotation ${key} does not exist`);
|
|
828
|
+
return true;
|
|
829
|
+
}
|
|
830
|
+
if (value && testKey !== value) {
|
|
831
|
+
logger_default.debug(`${testKey} does not match ${value}`);
|
|
832
|
+
return true;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
return false;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// src/lib/request.ts
|
|
839
|
+
var import_ramda = require("ramda");
|
|
840
|
+
var PeprRequest = class {
|
|
841
|
+
_input;
|
|
842
|
+
Raw;
|
|
843
|
+
get PermitSideEffects() {
|
|
844
|
+
return !this._input.dryRun;
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Indicates whether the request is a dry run.
|
|
848
|
+
* @returns true if the request is a dry run, false otherwise.
|
|
849
|
+
*/
|
|
850
|
+
get IsDryRun() {
|
|
851
|
+
return this._input.dryRun;
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Provides access to the old resource in the request if available.
|
|
855
|
+
* @returns The old Kubernetes resource object or null if not available.
|
|
856
|
+
*/
|
|
857
|
+
get OldResource() {
|
|
858
|
+
return this._input.oldObject;
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Provides access to the request object.
|
|
862
|
+
* @returns The request object containing the Kubernetes resource.
|
|
863
|
+
*/
|
|
864
|
+
get Request() {
|
|
865
|
+
return this._input;
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Creates a new instance of the Action class.
|
|
869
|
+
* @param input - The request object containing the Kubernetes resource to modify.
|
|
870
|
+
*/
|
|
871
|
+
constructor(input) {
|
|
872
|
+
this.Raw = (0, import_ramda.clone)(input.object);
|
|
873
|
+
this._input = input;
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Deep merges the provided object with the current resource.
|
|
877
|
+
*
|
|
878
|
+
* @param obj - The object to merge with the current resource.
|
|
879
|
+
*/
|
|
880
|
+
Merge(obj) {
|
|
881
|
+
this.Raw = (0, import_ramda.mergeDeepRight)(this.Raw, obj);
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Updates a label on the Kubernetes resource.
|
|
885
|
+
* @param key - The key of the label to update.
|
|
886
|
+
* @param value - The value of the label.
|
|
887
|
+
* @returns The current Action instance for method chaining.
|
|
888
|
+
*/
|
|
889
|
+
SetLabel(key, value) {
|
|
890
|
+
const ref = this.Raw;
|
|
891
|
+
ref.metadata = ref.metadata ?? {};
|
|
892
|
+
ref.metadata.labels = ref.metadata.labels ?? {};
|
|
893
|
+
ref.metadata.labels[key] = value;
|
|
894
|
+
return this;
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* Updates an annotation on the Kubernetes resource.
|
|
898
|
+
* @param key - The key of the annotation to update.
|
|
899
|
+
* @param value - The value of the annotation.
|
|
900
|
+
* @returns The current Action instance for method chaining.
|
|
901
|
+
*/
|
|
902
|
+
SetAnnotation(key, value) {
|
|
903
|
+
const ref = this.Raw;
|
|
904
|
+
ref.metadata = ref.metadata ?? {};
|
|
905
|
+
ref.metadata.annotations = ref.metadata.annotations ?? {};
|
|
906
|
+
ref.metadata.annotations[key] = value;
|
|
907
|
+
return this;
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Removes a label from the Kubernetes resource.
|
|
911
|
+
* @param key - The key of the label to remove.
|
|
912
|
+
* @returns The current Action instance for method chaining.
|
|
913
|
+
*/
|
|
914
|
+
RemoveLabel(key) {
|
|
915
|
+
if (this.Raw.metadata?.labels?.[key]) {
|
|
916
|
+
delete this.Raw.metadata.labels[key];
|
|
917
|
+
}
|
|
918
|
+
return this;
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Removes an annotation from the Kubernetes resource.
|
|
922
|
+
* @param key - The key of the annotation to remove.
|
|
923
|
+
* @returns The current Action instance for method chaining.
|
|
924
|
+
*/
|
|
925
|
+
RemoveAnnotation(key) {
|
|
926
|
+
if (this.Raw.metadata?.annotations?.[key]) {
|
|
927
|
+
delete this.Raw.metadata.annotations[key];
|
|
928
|
+
}
|
|
929
|
+
return this;
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Check if a label exists on the Kubernetes resource.
|
|
933
|
+
*
|
|
934
|
+
* @param key the label key to check
|
|
935
|
+
* @returns
|
|
936
|
+
*/
|
|
937
|
+
HasLabel(key) {
|
|
938
|
+
return this.Raw?.metadata?.labels?.[key] !== void 0;
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Check if an annotation exists on the Kubernetes resource.
|
|
942
|
+
*
|
|
943
|
+
* @param key the annotation key to check
|
|
944
|
+
* @returns
|
|
945
|
+
*/
|
|
946
|
+
HasAnnotation(key) {
|
|
947
|
+
return this.Raw?.metadata?.annotations?.[key] !== void 0;
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
|
|
951
|
+
// src/lib/processor.ts
|
|
952
|
+
async function processor(config, capabilities, req) {
|
|
953
|
+
const wrapped = new PeprRequest(req);
|
|
954
|
+
const response = {
|
|
955
|
+
uid: req.uid,
|
|
956
|
+
warnings: [],
|
|
957
|
+
allowed: false
|
|
958
|
+
};
|
|
959
|
+
logger_default.info(`Processing '${req.uid}' for '${req.kind.kind}' '${req.name}'`);
|
|
960
|
+
for (const { name, bindings } of capabilities) {
|
|
961
|
+
const prefix = `${req.uid} ${req.name}: ${name}`;
|
|
962
|
+
logger_default.info(`Processing capability ${name}`, prefix);
|
|
963
|
+
for (const action of bindings) {
|
|
964
|
+
if (shouldSkipRequest(action, req)) {
|
|
965
|
+
continue;
|
|
966
|
+
}
|
|
967
|
+
logger_default.info(`Processing matched action ${action.kind.kind}`, prefix);
|
|
968
|
+
const updateStatus = (status) => {
|
|
969
|
+
if (req.operation == "DELETE") {
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
const identifier = `${config.uuid}.pepr.dev/${name}`;
|
|
973
|
+
wrapped.Raw.metadata = wrapped.Raw.metadata || {};
|
|
974
|
+
wrapped.Raw.metadata.annotations = wrapped.Raw.metadata.annotations || {};
|
|
975
|
+
wrapped.Raw.metadata.annotations[identifier] = status;
|
|
976
|
+
};
|
|
977
|
+
updateStatus("started");
|
|
978
|
+
try {
|
|
979
|
+
await action.callback(wrapped);
|
|
980
|
+
logger_default.info(`Action succeeded`, prefix);
|
|
981
|
+
updateStatus("succeeded");
|
|
982
|
+
} catch (e) {
|
|
983
|
+
response.warnings = response.warnings || [];
|
|
984
|
+
response.warnings.push(`Action failed: ${e}`);
|
|
985
|
+
if (config.onError) {
|
|
986
|
+
logger_default.error(`Action failed: ${e}`, prefix);
|
|
987
|
+
response.result = "Pepr module configured to reject on error";
|
|
988
|
+
return response;
|
|
989
|
+
} else {
|
|
990
|
+
logger_default.warn(`Action failed: ${e}`, prefix);
|
|
991
|
+
updateStatus("warning");
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
response.allowed = true;
|
|
997
|
+
const patches = import_fast_json_patch.default.compare(req.object, wrapped.Raw);
|
|
998
|
+
if (patches.length > 0) {
|
|
999
|
+
response.patchType = "JSONPatch";
|
|
1000
|
+
response.patch = Buffer.from(JSON.stringify(patches)).toString("base64");
|
|
1001
|
+
}
|
|
1002
|
+
if (response.warnings && response.warnings.length < 1) {
|
|
1003
|
+
delete response.warnings;
|
|
1004
|
+
}
|
|
1005
|
+
logger_default.debug(patches);
|
|
1006
|
+
return response;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// src/lib/controller.ts
|
|
1010
|
+
var options = {
|
|
1011
|
+
key: import_fs.default.readFileSync(process.env.SSL_KEY_PATH || "/etc/certs/tls.key"),
|
|
1012
|
+
cert: import_fs.default.readFileSync(process.env.SSL_CERT_PATH || "/etc/certs/tls.crt")
|
|
1013
|
+
};
|
|
1014
|
+
var Controller = class {
|
|
1015
|
+
constructor(config, capabilities, beforeHook, afterHook) {
|
|
1016
|
+
this.config = config;
|
|
1017
|
+
this.capabilities = capabilities;
|
|
1018
|
+
this.beforeHook = beforeHook;
|
|
1019
|
+
this.afterHook = afterHook;
|
|
1020
|
+
this.app.use(this.logger);
|
|
1021
|
+
this.app.use(import_express.default.json());
|
|
1022
|
+
this.app.get("/healthz", this.healthz);
|
|
1023
|
+
this.app.post("/mutate", this.mutate);
|
|
1024
|
+
if (beforeHook) {
|
|
1025
|
+
console.info(`Using beforeHook: ${beforeHook}`);
|
|
1026
|
+
}
|
|
1027
|
+
if (afterHook) {
|
|
1028
|
+
console.info(`Using afterHook: ${afterHook}`);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
app = (0, import_express.default)();
|
|
1032
|
+
running = false;
|
|
1033
|
+
/** Start the webhook server */
|
|
1034
|
+
startServer = (port) => {
|
|
1035
|
+
if (this.running) {
|
|
1036
|
+
throw new Error("Cannot start Pepr module: Pepr module was not instantiated with deferStart=true");
|
|
1037
|
+
}
|
|
1038
|
+
const server = import_https.default.createServer(options, this.app).listen(port);
|
|
1039
|
+
server.on("listening", () => {
|
|
1040
|
+
console.log(`Server listening on port ${port}`);
|
|
1041
|
+
this.running = true;
|
|
1042
|
+
});
|
|
1043
|
+
server.on("error", (e) => {
|
|
1044
|
+
if (e.code === "EADDRINUSE") {
|
|
1045
|
+
console.log("Address in use, retrying...");
|
|
1046
|
+
setTimeout(() => {
|
|
1047
|
+
server.close();
|
|
1048
|
+
server.listen(port);
|
|
1049
|
+
}, 2e3);
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
process.on("SIGTERM", () => {
|
|
1053
|
+
console.log("Received SIGTERM, closing server");
|
|
1054
|
+
server.close(() => {
|
|
1055
|
+
console.log("Server closed");
|
|
1056
|
+
process.exit(0);
|
|
1057
|
+
});
|
|
1058
|
+
});
|
|
1059
|
+
};
|
|
1060
|
+
logger = (req, res, next) => {
|
|
1061
|
+
const startTime = Date.now();
|
|
1062
|
+
res.on("finish", () => {
|
|
1063
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1064
|
+
const elapsedTime = Date.now() - startTime;
|
|
1065
|
+
const message = `[${now}] ${req.method} ${req.originalUrl} - ${res.statusCode} - ${elapsedTime} ms
|
|
1066
|
+
`;
|
|
1067
|
+
res.statusCode >= 400 ? console.error(message) : console.info(message);
|
|
1068
|
+
});
|
|
1069
|
+
next();
|
|
1070
|
+
};
|
|
1071
|
+
healthz = (req, res) => {
|
|
1072
|
+
try {
|
|
1073
|
+
res.send("OK");
|
|
1074
|
+
} catch (err) {
|
|
1075
|
+
console.error(err);
|
|
1076
|
+
res.status(500).send("Internal Server Error");
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
mutate = async (req, res) => {
|
|
1080
|
+
try {
|
|
1081
|
+
this.beforeHook && this.beforeHook(req.body?.request || {});
|
|
1082
|
+
const name = req.body?.request?.name || "";
|
|
1083
|
+
const namespace = req.body?.request?.namespace || "";
|
|
1084
|
+
const gvk = req.body?.request?.kind || { group: "", version: "", kind: "" };
|
|
1085
|
+
console.log(`Mutate request: ${gvk.group}/${gvk.version}/${gvk.kind}`);
|
|
1086
|
+
name && console.log(` ${namespace}/${name}
|
|
1087
|
+
`);
|
|
1088
|
+
const response = await processor(this.config, this.capabilities, req.body.request);
|
|
1089
|
+
this.afterHook && this.afterHook(response);
|
|
1090
|
+
console.debug(response);
|
|
1091
|
+
res.send({
|
|
1092
|
+
apiVersion: "admission.k8s.io/v1",
|
|
1093
|
+
kind: "AdmissionReview",
|
|
1094
|
+
response
|
|
1095
|
+
});
|
|
1096
|
+
} catch (err) {
|
|
1097
|
+
console.error(err);
|
|
1098
|
+
res.status(500).send("Internal Server Error");
|
|
1099
|
+
}
|
|
1100
|
+
};
|
|
1101
|
+
};
|
|
1102
|
+
|
|
1103
|
+
// src/lib/module.ts
|
|
1104
|
+
var alwaysIgnore = {
|
|
1105
|
+
namespaces: ["kube-system", "pepr-system"],
|
|
1106
|
+
labels: [{ "pepr.dev": "ignore" }]
|
|
1107
|
+
};
|
|
1108
|
+
var PeprModule = class {
|
|
1109
|
+
_controller;
|
|
1110
|
+
/**
|
|
1111
|
+
* Create a new Pepr runtime
|
|
1112
|
+
*
|
|
1113
|
+
* @param config The configuration for the Pepr runtime
|
|
1114
|
+
* @param capabilities The capabilities to be loaded into the Pepr runtime
|
|
1115
|
+
* @param _deferStart (optional) If set to `true`, the Pepr runtime will not be started automatically. This can be used to start the Pepr runtime manually with `start()`.
|
|
1116
|
+
*/
|
|
1117
|
+
constructor({ description, pepr }, capabilities = [], opts = {}) {
|
|
1118
|
+
const config = (0, import_ramda2.mergeDeepWith)(import_ramda2.concat, pepr, alwaysIgnore);
|
|
1119
|
+
config.description = description;
|
|
1120
|
+
this._controller = new Controller(config, capabilities, opts.beforeHook, opts.afterHook);
|
|
1121
|
+
if (opts.deferStart) {
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
this.start();
|
|
1125
|
+
}
|
|
1126
|
+
/**
|
|
1127
|
+
* Start the Pepr runtime manually.
|
|
1128
|
+
* Normally this is called automatically when the Pepr module is instantiated, but can be called manually if `deferStart` is set to `true` in the constructor.
|
|
1129
|
+
*
|
|
1130
|
+
* @param port
|
|
1131
|
+
*/
|
|
1132
|
+
start(port = 3e3) {
|
|
1133
|
+
this._controller.startServer(port);
|
|
1134
|
+
}
|
|
1135
|
+
};
|
|
1136
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1137
|
+
0 && (module.exports = {
|
|
1138
|
+
Capability,
|
|
1139
|
+
Log,
|
|
1140
|
+
PeprModule,
|
|
1141
|
+
PeprRequest,
|
|
1142
|
+
RegisterKind,
|
|
1143
|
+
a,
|
|
1144
|
+
fetch,
|
|
1145
|
+
fetchRaw,
|
|
1146
|
+
fetchStatus,
|
|
1147
|
+
k8s,
|
|
1148
|
+
utils
|
|
1149
|
+
});
|
|
1150
|
+
//# sourceMappingURL=lib.js.map
|