diff --git a/adr/0006-onschedule-implementation.md b/adr/0006-onschedule-implementation.md new file mode 100644 index 000000000..dfd7244dc --- /dev/null +++ b/adr/0006-onschedule-implementation.md @@ -0,0 +1,56 @@ +# 6: OnSchedule Implementation + +Date: 2023-10-16 + +## Status + +Accepted + +## Context + +Zarf wrote a Pepr module to facilitate the development in [using ECR as an external registry during 'Zarf Init'](https://github.com/defenseunicorns/zarf/issues/1594). They are running into a challenge where the ECR Registry token is expiring every ~12 hours. Currently, they are having to maintain two completely different codebases, one being the Pepr module that communicates with AWS, and another being a Go app that they run as a `CronJob` to refresh the token. They are interested in rewriting the Go and scheduling logic in Pepr. + +We considered a few options: +- setTimeout - Pepr is created with devex being a first class citizen and using a setTimeout doesn't cover persistence and stylistically different than the fluent api. +- setInterval - " " +- using a `CronJob` - Forces the user to create a separate container image and maintain two codebases while they already have Pepr which should be able to handle this. +- Use the crontab api - Provide a crontab string to run at the given time. Too big, didn't want to implement at this point. +- Use the `OnSchedule` api - Provide a fluent api to run at the given time, with a completions argument. + +## Decision + +```typescript +OnSchedule({ + every: 5, + unit: "minutes", + startTime: "2023-10-16T00:00:00Z", // all dates times must be in GMT + run: () => { + // run some code + }, + completions: 5, +}); +``` + +We decided to: + +Use `OnSchedule` to provide a fluent api to run at the given time, with a completions argument in the event that it needs to `RunAt` some given time and stop. This allows us to cover the functionality that something needs to be run on startup only once, like an IIFE. + +### Missed Jobs + +On missed (cluster restart, power outage) jobs we will run the code at the next scheduled interval and not count the failure against completions. + +### Why watch controller? + +The watch controller runs a single instance, this means we can avoid multiple controllers competing to run the same code. + +### Why `OnSchedule`? + +1. **Covers CronJob usecase**: We can cover the repeatability of a kubernetes native `CronJob` using `OnSchedule` to allow Zarf team to consoludate this functionlity into Pepr. +2. **Backed by etcd**: We can mitigate the risk of Pepr being down by using etcd as the backing store for the `OnSchedule` API and warn the user that these `jobs` should be idempotent. + + +## Consequences + +1. **Developer Experience**: Improved developer experience by extending the functionality provided in Pepr. Reduce the need to maintain a separate codebase to accomplish scheduled `job` type operations. +2. **Test Stability**: Need to extend the internal tests to cover `OnSchedule`. +3. **Documentation**: Existing documentation will need to be updated to reflect these changes. diff --git a/docs/webassembly.md b/docs/webassembly.md index ab8798dca..cbe29aa6b 100644 --- a/docs/webassembly.md +++ b/docs/webassembly.md @@ -1,10 +1,13 @@ -# WASM Support: Introducing WebAssembly to Pepr Guide +# WASM Support: Running WebAssembly in Pepr Guide + +Pepr fully supports WebAssembly. Depending on the language used to generate the WASM, certain files can be too large to fit into a `Secret` or `ConfigMap`. Due to this limitation, users have the ability to incorporate `*.wasm` and any other essential files during the build phase, which are then embedded into the Pepr Controller container. This is achieved through adding an array of files to the `includedFiles` section under `pepr` in the `package.json`. + +> **NOTE -** In order to instantiate the WebAsembly module in TypeScript, you need the WebAssembly type. This is accomplished through add the "DOM" to the `lib` array in the `compilerOptions` section of the `tsconfig.json`. Ex: `"lib": ["ES2022", "DOM"]`. Be aware that adding the DOM will add a lot of extra types to your project and your developer experience will be impacted in terms of the intellisense. -Pepr now supports embedding `*.wasm` files into your Pepr modules during the build process. This is achieved through adding an array of files to the `includedFiles` section under `pepr` in the `package.json`. ## High-Level Overview -At its core, WASM support is achieved through adding layers on top of the Pepr controller image accesible by the module. The key components of WASM support are: +WASM support is achieved through adding files as layers atop the Pepr controller image, these files are then able to be read by the individual capabilities. The key components of WASM support are: - Add files to the **base** of the Pepr module. - Reference the files in the `includedFiles` section of the `pepr` block of the `package.json` @@ -68,7 +71,73 @@ if (typeof globalThis.crypto === 'undefined') { } ``` -### Calling WASM from the Capability + +### Configure Pepr to use WASM + +After adding the files to the root of the Pepr module, reference those files in the `package.json`: + +```json +{ + "name": "pepr-test-module", + "version": "0.0.1", + "description": "A test module for Pepr", + "keywords": [ + "pepr", + "k8s", + "policy-engine", + "pepr-module", + "security" + ], + "engines": { + "node": ">=18.0.0" + }, + "pepr": { + "name": "pepr-test-module", + "uuid": "static-test", + "onError": "ignore", + "alwaysIgnore": { + "namespaces": [], + "labels": [] + }, + "includedFiles":[ + "main.wasm", + "wasm_exec.js" + ] + }, + ... +} +``` + +Update the `tsconfig.json` to add "DOM" to the `compilerOptions` lib: + +```json +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "esModuleInterop": true, + "lib": [ + "ES2022", + "DOM" // <- Add this + ], + "module": "CommonJS", + "moduleResolution": "node", + "outDir": "dist", + "resolveJsonModule": true, + "rootDir": ".", + "strict": false, + "target": "ES2022", + "useUnknownInCatchVariables": false + }, + "include": [ + "**/*.ts" + ] +} +``` + +### Call WASM functions from TypeScript Import the `wasm_exec.js` in the `pepr.ts` @@ -88,7 +157,7 @@ async function callWASM(a,b) { await WebAssembly.instantiate(wasmData, go.importObject).then(wasmModule => { go.run(wasmModule.instance); - concated = global.peprWasm(a,b); + concated = global.concats(a,b); }); return concated; } @@ -106,47 +175,10 @@ When(a.Pod) }); ``` -### Updating the package.json - -After adding the files to the root (adjacent to `pepr.ts`) of the Pepr module, reference those files in the package.json: - -```json -{ - "name": "pepr-test-module", - "version": "0.0.1", - "description": "A test module for Pepr", - "keywords": [ - "pepr", - "k8s", - "policy-engine", - "pepr-module", - "security" - ], - "engines": { - "node": ">=18.0.0" - }, - "pepr": { - "name": "pepr-test-module", - "uuid": "static-test", - "onError": "ignore", - "alwaysIgnore": { - "namespaces": [], - "labels": [] - }, - "includedFiles":[ - "main.wasm", - "wasm_exec.js" - ] - }, - ... -} -``` - ### Run Pepr Build -Build your Pepr module with registry into specified. +Build your Pepr module with the registry specified. ```bash npx pepr build -r docker.io/defenseunicorns ``` - diff --git a/package-lock.json b/package-lock.json index 937ca76a6..aefa33a76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "express": "4.18.2", "fast-json-patch": "3.1.1", - "kubernetes-fluent-client": "1.6.1", + "kubernetes-fluent-client": "1.7.0", "pino": "8.16.0", "pino-pretty": "10.2.3", "prom-client": "15.0.0", @@ -25,13 +25,13 @@ "@commitlint/cli": "17.8.0", "@commitlint/config-conventional": "17.8.0", "@jest/globals": "29.7.0", - "@types/eslint": "8.44.4", - "@types/express": "4.17.19", + "@types/eslint": "8.44.6", + "@types/express": "4.17.20", "@types/node": "18.x.x", - "@types/node-forge": "1.3.7", - "@types/prompts": "2.4.6", - "@types/ramda": "0.29.6", - "@types/uuid": "9.0.5", + "@types/node-forge": "1.3.8", + "@types/prompts": "2.4.7", + "@types/ramda": "0.29.7", + "@types/uuid": "9.0.6", "jest": "29.7.0", "nock": "13.3.4", "ts-jest": "29.1.1" @@ -2112,9 +2112,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.44.4", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.4.tgz", - "integrity": "sha512-lOzjyfY/D9QR4hY9oblZ76B90MYTB3RrQ4z2vBIJKj9ROCRqdkYl2gSUx1x1a4IWPjKJZLL4Aw1Zfay7eMnmnA==", + "version": "8.44.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.6.tgz", + "integrity": "sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw==", "dev": true, "dependencies": { "@types/estree": "*", @@ -2128,9 +2128,9 @@ "dev": true }, "node_modules/@types/express": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.19.tgz", - "integrity": "sha512-UtOfBtzN9OvpZPPbnnYunfjM7XCI4jyk1NvnFhTVz5krYAnW4o5DCoIekvms+8ApqhB4+9wSge1kBijdfTSmfg==", + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.20.tgz", + "integrity": "sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw==", "dev": true, "dependencies": { "@types/body-parser": "*", @@ -2213,9 +2213,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.18.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.5.tgz", - "integrity": "sha512-4slmbtwV59ZxitY4ixUZdy1uRLf9eSIvBWPQxNjhHYWEtn0FryfKpyS2cvADYXTayWdKEIsJengncrVvkI4I6A==" + "version": "18.18.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.6.tgz", + "integrity": "sha512-wf3Vz+jCmOQ2HV1YUJuCWdL64adYxumkrxtc+H1VUQlnQI04+5HtH+qZCOE21lBE7gIrt+CwX2Wv8Acrw5Ak6w==" }, "node_modules/@types/node-fetch": { "version": "2.6.6", @@ -2227,9 +2227,9 @@ } }, "node_modules/@types/node-forge": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.7.tgz", - "integrity": "sha512-uWvTDObXqNQPVprvvm7FCS/B0qexgRMmNCJCRETywf7cBm3C7uGRtGfaSqCoUlksrmY5Yn3++fvA7awBE5lAzw==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.8.tgz", + "integrity": "sha512-vGXshY9vim9CJjrpcS5raqSjEfKlJcWy2HNdgUasR66fAnVEYarrf1ULV4nfvpC1nZq/moA9qyqBcu83x+Jlrg==", "dev": true, "dependencies": { "@types/node": "*" @@ -2242,9 +2242,9 @@ "dev": true }, "node_modules/@types/prompts": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.4.6.tgz", - "integrity": "sha512-hIwnDhvsTV6XwAPo1zNy2MTelR0JmCxklIRsVxwROHLGaf6LfB+sGDkB9n+aqV4gXDz8z5MnlAz4CEC9wQDRsw==", + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.4.7.tgz", + "integrity": "sha512-5zTamE+QQM4nR6Ab3yHK+ovWuhLJXaa2ZLt3mT1en8U3ubWtjVT1vXDaVFC2+cL89uVn7Y+gIq5B3IcVvBl5xQ==", "dev": true, "dependencies": { "@types/node": "*", @@ -2258,9 +2258,9 @@ "dev": true }, "node_modules/@types/ramda": { - "version": "0.29.6", - "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.29.6.tgz", - "integrity": "sha512-4XQ9hYQhCwOxfkoTsIPvDVXc75fY5+MLQHUpExX6ByvU1q+0vOYRLSjWAt1IydkE1hOuhwMH6KvV/9rhzgrvRw==", + "version": "0.29.7", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.29.7.tgz", + "integrity": "sha512-IUl6U95qwlQtVvZkSX4ODj08oJVtPyWMFRtPVNqhxc2rt+Bh7lCzTrGMYMZ7dmRKcAjtot3xrPnYGwsjdt8gzQ==", "dev": true, "dependencies": { "types-ramda": "^0.29.5" @@ -2333,9 +2333,9 @@ "integrity": "sha512-77Mq/2BeHU894J364dUv9tSwxxyCLtcX228Pc8TwZpP5bvOoMns+gZoftp3LYl3FBH8vChpWbuagKGiMki2c1A==" }, "node_modules/@types/uuid": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.5.tgz", - "integrity": "sha512-xfHdwa1FMJ082prjSJpoEI57GZITiQz10r3vEJCHa2khEFQjKy91aWKz6+zybzssCvXUwE1LQWgWVwZ4nYUvHQ==", + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.6.tgz", + "integrity": "sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew==", "dev": true }, "node_modules/@types/ws": { @@ -5678,9 +5678,9 @@ } }, "node_modules/kubernetes-fluent-client": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/kubernetes-fluent-client/-/kubernetes-fluent-client-1.6.1.tgz", - "integrity": "sha512-v/MlBzwVzNiPPJNAjb0XrgL81bJWGsHnYSw85Zq2lgJtEji73LByvjE0NF5Q8kahz2z6bW1EGgoL/effc9Jbcg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/kubernetes-fluent-client/-/kubernetes-fluent-client-1.7.0.tgz", + "integrity": "sha512-8VreybOUSzjq46CfWmUirpb+YEw6keKH+soDpIGZ6mJXD7DFuoZGNWkJu6TBupHjz2hCj9+Exe4sl794ulnWWQ==", "dependencies": { "@kubernetes/client-node": "1.0.0-rc3", "byline": "5.0.0", diff --git a/package.json b/package.json index e380de787..7943fab8b 100644 --- a/package.json +++ b/package.json @@ -24,14 +24,14 @@ "test:journey:build": "npm run build && npm pack", "test:journey:image": "docker buildx build --tag pepr:dev . && k3d image import pepr:dev -c pepr-dev", "test:journey:k3d": "k3d cluster delete pepr-dev && k3d cluster create pepr-dev --k3s-arg '--debug@server:0'", - "test:journey:run": "jest journey/entrypoint.test.ts", - "test:journey:run-wasm": "jest journey/entrypoint-wasm.test.ts", + "test:journey:run": "jest --detectOpenHandles journey/entrypoint.test.ts", + "test:journey:run-wasm": "jest --detectOpenHandles journey/entrypoint-wasm.test.ts", "test:unit": "npm run gen-data-json && jest src --coverage" }, "dependencies": { "express": "4.18.2", "fast-json-patch": "3.1.1", - "kubernetes-fluent-client": "1.6.1", + "kubernetes-fluent-client": "1.7.0", "pino": "8.16.0", "pino-pretty": "10.2.3", "prom-client": "15.0.0", @@ -41,13 +41,13 @@ "@commitlint/cli": "17.8.0", "@commitlint/config-conventional": "17.8.0", "@jest/globals": "29.7.0", - "@types/eslint": "8.44.4", - "@types/express": "4.17.19", + "@types/eslint": "8.44.6", + "@types/express": "4.17.20", "@types/node": "18.x.x", - "@types/node-forge": "1.3.7", - "@types/prompts": "2.4.6", - "@types/ramda": "0.29.6", - "@types/uuid": "9.0.5", + "@types/node-forge": "1.3.8", + "@types/prompts": "2.4.7", + "@types/ramda": "0.29.7", + "@types/uuid": "9.0.6", "jest": "29.7.0", "nock": "13.3.4", "ts-jest": "29.1.1" diff --git a/src/templates/tsconfig.module.json b/src/templates/tsconfig.module.json index 8745fb89e..93106209c 100644 --- a/src/templates/tsconfig.module.json +++ b/src/templates/tsconfig.module.json @@ -5,7 +5,7 @@ "declarationMap": true, "emitDeclarationOnly": true, "esModuleInterop": true, - "lib": ["ES2022", "DOM"], + "lib": ["ES2022"], "module": "CommonJS", "moduleResolution": "node", "outDir": "dist",