From 87668ac17fc8b1ca1592333d8935e91958d2b3c8 Mon Sep 17 00:00:00 2001 From: f1ames Date: Fri, 13 Oct 2023 13:04:58 +0200 Subject: [PATCH 01/17] test: add basic integration tests --- tests/package-lock.json | 1353 +++++++++++++++++++++++++++++++++ tests/package.json | 20 + tests/src/integration.spec.ts | 141 ++++ tests/tsconfig.json | 14 + 4 files changed, 1528 insertions(+) create mode 100644 tests/package-lock.json create mode 100644 tests/package.json create mode 100644 tests/src/integration.spec.ts create mode 100644 tests/tsconfig.json diff --git a/tests/package-lock.json b/tests/package-lock.json new file mode 100644 index 0000000..337dc70 --- /dev/null +++ b/tests/package-lock.json @@ -0,0 +1,1353 @@ +{ + "name": "admission-webhook-tests", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "admission-webhook-tests", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@types/node": "^20.1.7", + "@types/shelljs": "^0.8.13", + "shelljs": "^0.8.5", + "typescript": "^4.6.3", + "vitest": "^0.34.6" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@types/chai": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.8.tgz", + "integrity": "sha512-yW/qTM4mRBBcsA9Xw9FbcImYtFPY7sgr+G/O5RDYVmxiy9a+pE5FyoFUi8JYCZY5nicj8atrr1pcfPiYpeNGOA==", + "dev": true + }, + "node_modules/@types/chai-subset": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz", + "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", + "dev": true, + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.8.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.5.tgz", + "integrity": "sha512-SPlobFgbidfIeOYlzXiEjSYeIJiOCthv+9tSQVpvk4PAdIIc+2SmjNVzWXk9t0Y7dl73Zdf+OgXKHX9XtkqUpw==", + "dev": true, + "dependencies": { + "undici-types": "~5.25.1" + } + }, + "node_modules/@types/shelljs": { + "version": "0.8.13", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.13.tgz", + "integrity": "sha512-++uMLOQSLlse1kCfEOwhgmHuaABZwinkylmUKCpvcEGZUov3TtM+gJZloSkW/W+9pEAEg/VBOwiSR05oqJsa5A==", + "dev": true, + "dependencies": { + "@types/glob": "~7.2.0", + "@types/node": "*" + } + }, + "node_modules/@vitest/expect": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz", + "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==", + "dev": true, + "dependencies": { + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz", + "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==", + "dev": true, + "dependencies": { + "@vitest/utils": "0.34.6", + "p-limit": "^4.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz", + "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.1", + "pathe": "^1.1.1", + "pretty-format": "^29.5.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", + "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", + "dev": true, + "dependencies": { + "tinyspy": "^2.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz", + "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==", + "dev": true, + "dependencies": { + "diff-sequences": "^29.4.3", + "loupe": "^2.3.6", + "pretty-format": "^29.5.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chai": { + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mlly": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", + "integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==", + "dev": true, + "dependencies": { + "acorn": "^8.10.0", + "pathe": "^1.1.1", + "pkg-types": "^1.0.3", + "ufo": "^1.3.0" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/pathe": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz", + "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==", + "dev": true + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/pkg-types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", + "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.2.0", + "pathe": "^1.1.0" + } + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "node_modules/std-env": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.4.3.tgz", + "integrity": "sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==", + "dev": true + }, + "node_modules/strip-literal": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz", + "integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==", + "dev": true, + "dependencies": { + "acorn": "^8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tinybench": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.1.tgz", + "integrity": "sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==", + "dev": true + }, + "node_modules/tinypool": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz", + "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.0.tgz", + "integrity": "sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ufo": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.1.tgz", + "integrity": "sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==", + "dev": true + }, + "node_modules/undici-types": { + "version": "5.25.3", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", + "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "dev": true + }, + "node_modules/vite": { + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz", + "integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==", + "dev": true, + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz", + "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "mlly": "^1.4.0", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": ">=v14.18.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz", + "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==", + "dev": true, + "dependencies": { + "@types/chai": "^4.3.5", + "@types/chai-subset": "^1.3.3", + "@types/node": "*", + "@vitest/expect": "0.34.6", + "@vitest/runner": "0.34.6", + "@vitest/snapshot": "0.34.6", + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", + "acorn": "^8.9.0", + "acorn-walk": "^8.2.0", + "cac": "^6.7.14", + "chai": "^4.3.10", + "debug": "^4.3.4", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.1", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.3.3", + "strip-literal": "^1.0.1", + "tinybench": "^2.5.0", + "tinypool": "^0.7.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0", + "vite-node": "0.34.6", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": ">=v14.18.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@vitest/browser": "*", + "@vitest/ui": "*", + "happy-dom": "*", + "jsdom": "*", + "playwright": "*", + "safaridriver": "*", + "webdriverio": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "playwright": { + "optional": true + }, + "safaridriver": { + "optional": true + }, + "webdriverio": { + "optional": true + } + } + }, + "node_modules/why-is-node-running": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", + "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/tests/package.json b/tests/package.json new file mode 100644 index 0000000..c1eccc4 --- /dev/null +++ b/tests/package.json @@ -0,0 +1,20 @@ +{ + "name": "admission-webhook-tests", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "type": "module", + "scripts": { + "test": "vitest run", + "build": "tsc -p tsconfig.json" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "@types/node": "^20.1.7", + "@types/shelljs": "^0.8.13", + "shelljs": "^0.8.5", + "typescript": "^4.6.3", + "vitest": "^0.34.6" + } +} diff --git a/tests/src/integration.spec.ts b/tests/src/integration.spec.ts new file mode 100644 index 0000000..c3aaf8e --- /dev/null +++ b/tests/src/integration.spec.ts @@ -0,0 +1,141 @@ +import { join, resolve } from 'path'; +import { afterEach, assert, beforeAll, describe, it } from 'vitest' +import shell from 'shelljs'; + +const VERBOSE = process.env.VERBOSE === 'true'; + +const currentDir = __dirname; +const mainDir = resolve(join(currentDir, '..', '..')); + +// IMPORTANT: As a prerequisite to run this tests, you need to have a cluster running, configured with your kubectl +// and Monokle Admission Controller deployed there as described in the README.md file. + +describe(`All (dir: ${mainDir})`, () => { + beforeAll(async () => { + await waitForResult('kubectl -n monokle-admission-controller get pod', (result) => { + return result.includes('monokle-admission-controller-server') && result.includes('Running'); + }, 50000); + + await cleanup(); + }, 60000); + + afterEach(async () => { + await cleanup(); + }); + + it('creates resource (any) with no warnings when no policy defined for namespace', async () => { + const output = await run(`cd "${mainDir}" && kubectl -n nstest2 apply -f examples/pod-valid.yaml`); + + assert.match(output, /pod\/pod-valid created/); + assert.notMatch(output, /warning/gi); + assert.notMatch(output, /error/gi); + }); + + it('creates resource (valid) with no warnings when policy defined for namespace', async () => { + await run(`cd "${mainDir}" && kubectl apply -f examples/policy-sample-1.yaml`); + await run(`cd "${mainDir}" && kubectl apply -f examples/policy-binding-sample-2.yaml`); + + const output = await run(`cd "${mainDir}" && kubectl -n default apply -f examples/pod-valid.yaml`); + + assert.match(output, /pod\/pod-valid created/); + assert.notMatch(output, /warning/gi); + assert.notMatch(output, /error/gi); + }); + + it('creates resource (misconfigured) with warnings when policy defined for namespace', async () => { + await run(`cd "${mainDir}" && kubectl apply -f examples/policy-sample-2.yaml`); + await run(`cd "${mainDir}" && kubectl apply -f examples/policy-binding-sample-3.yaml`); + + const output = await run(`cd "${mainDir}" && kubectl -n nstest1 apply -f examples/pod-warning.yaml`); + + assert.match(output, /pod\/pod-warning created/); + assert.match(output, /warning/gi); + + const warningsCount = (output.match(/\(warning\)/gi) || []).length; + + assert.equal(warningsCount, 11); + }); + + it('creates resource (valid) with no warnings when policy defined globally', async () => { + await run(`cd "${mainDir}" && kubectl apply -f examples/policy-sample-1.yaml`); + await run(`cd "${mainDir}" && kubectl apply -f examples/policy-binding-sample-1.yaml`); + + const output = await run(`cd "${mainDir}" && kubectl -n default apply -f examples/pod-valid.yaml`); + + assert.match(output, /pod\/pod-valid created/); + assert.notMatch(output, /warning/gi); + assert.notMatch(output, /error/gi); + }); + + it('creates resource (misconfigured) with warnings when policy defined globally', async () => { + await run(`cd "${mainDir}" && kubectl apply -f examples/policy-sample-1.yaml`); + await run(`cd "${mainDir}" && kubectl apply -f examples/policy-binding-sample-1.yaml`); + + const output = await run(`cd "${mainDir}" && kubectl -n nstest2 apply -f examples/pod-errors.yaml`); + + assert.match(output, /pod\/pod-errors created/); + assert.match(output, /warning/gi); + assert.match(output, /error/gi); + + const warningsCount = (output.match(/\(warning\)/gi) || []).length; + const errorsCount = (output.match(/\(error\)/gi) || []).length; + + assert.equal(warningsCount, 8); + assert.equal(errorsCount, 4); + }); +}); + +const run = async (command: string): Promise => { + return new Promise((resolve, reject) => { + shell.exec(command, {async: true, silent: true}, (code, stdout, stderr) => { + + VERBOSE && console.log('stdout', stdout); + VERBOSE && console.log('stderr', stderr); + + if (code !== 0) { + reject(stderr); + } else { + resolve(`${stdout}\n${stderr}`); // Warnings are send to stderr so we pass it from successful run as well. + } + }); + }); +}; + +const waitForResult = async (command: string, isExpected: (result: string) => boolean, timeoutMs = 5000) => { + let isValid = false; + + const startTime = Date.now(); + while (!isValid) { + if (Date.now() - startTime > timeoutMs) { + throw new Error(`Timeout waiting for result of command: ${command}`); + } + + const result = await run(command); + isValid = isExpected(result); + + if (!isValid) { + sleep(250); + } + } +}; + +const cleanup = async () => { + return Promise.allSettled([ + run(`cd "${mainDir}" && kubectl delete -f examples/policy-sample-1.yaml`), + run(`cd "${mainDir}" && kubectl delete -f examples/policy-sample-2.yaml`), + run(`cd "${mainDir}" && kubectl delete -f examples/policy-binding-sample-1.yaml`), + run(`cd "${mainDir}" && kubectl delete -f examples/policy-binding-sample-2.yaml`), + run(`cd "${mainDir}" && kubectl delete -f examples/policy-binding-sample-3.yaml`), + run(`cd "${mainDir}" && kubectl delete -f examples/pod-valid.yaml -n nstest2`), + run(`cd "${mainDir}" && kubectl delete -f examples/pod-valid.yaml -n default`), + run(`cd "${mainDir}" && kubectl delete -f examples/pod-warning.yaml -n nstest1`), + run(`cd "${mainDir}" && kubectl delete -f examples/pod-valid.yaml -n default`), + run(`cd "${mainDir}" && kubectl delete -f examples/pod-errors.yaml -n nstest2 `), + ]); +}; + +const sleep = (ms: number) => { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +}; diff --git a/tests/tsconfig.json b/tests/tsconfig.json new file mode 100644 index 0000000..bf8c6f0 --- /dev/null +++ b/tests/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "target": "ESNext", + "moduleResolution": "node", + "outDir": "./dist" /* Specify an output folder for all emitted files. */, + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + "strict": true /* Enable all strict type-checking options. */, + }, + "exclude": ["node_modules", "dist"], + "include": ["src"] +} \ No newline at end of file From 5ceddd208b712d589c70cc4f85d09975ceb13592 Mon Sep 17 00:00:00 2001 From: f1ames Date: Fri, 13 Oct 2023 14:38:13 +0200 Subject: [PATCH 02/17] test: add test CI job --- .github/workflows/test.yaml | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/test.yaml diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..7eb5172 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,39 @@ +name: Test + +on: + pull_request: + push: + branches: + - main + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Setup Skaffold + run: curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64 && sudo install skaffold /usr/local/bin/ + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: 18 + + - name: Checkout Repo + uses: actions/checkout@v2 + + - name: Start Minikube + run: minikube start --uuid 00000000-0000-0000-0000-000000000001 --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook + + - name: Deploy Admission Controller + run: ./scripts/deploy.sh + + - name: Install Dependencies + working-directory: ./tests/ + run: npm ci + + - name: Test + working-directory: ./tests/ + run: npm test From 5ccb8ae1f7167790c8aa7e918420acc201163dc1 Mon Sep 17 00:00:00 2001 From: f1ames Date: Fri, 13 Oct 2023 14:43:38 +0200 Subject: [PATCH 03/17] test: wait for admission controller setup --- .github/workflows/test.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 7eb5172..5ece7ff 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -30,6 +30,9 @@ jobs: - name: Deploy Admission Controller run: ./scripts/deploy.sh + - name: Wait for Admission Controller + run: sleep 60 + - name: Install Dependencies working-directory: ./tests/ run: npm ci From e8483241dd5a87babbe4bf10c96f6ab1385869b7 Mon Sep 17 00:00:00 2001 From: f1ames Date: Mon, 16 Oct 2023 10:39:09 +0200 Subject: [PATCH 04/17] test: add minor corrections/comments --- .github/workflows/test.yaml | 4 ++++ tests/src/integration.spec.ts | 1 + 2 files changed, 5 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5ece7ff..4b09478 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -30,9 +30,13 @@ jobs: - name: Deploy Admission Controller run: ./scripts/deploy.sh + # @TODO move to test beforeAll to correctly detect if admission-controller pod is ready. - name: Wait for Admission Controller run: sleep 60 + - name: Preview namespace state + run: kubectl -n monokle-admission-controller get all,CustomResourceDefinition,ValidatingWebhookConfiguration,secrets + - name: Install Dependencies working-directory: ./tests/ run: npm ci diff --git a/tests/src/integration.spec.ts b/tests/src/integration.spec.ts index c3aaf8e..db46ef7 100644 --- a/tests/src/integration.spec.ts +++ b/tests/src/integration.spec.ts @@ -120,6 +120,7 @@ const waitForResult = async (command: string, isExpected: (result: string) => bo }; const cleanup = async () => { + // @TODO not very efficient, should be improved return Promise.allSettled([ run(`cd "${mainDir}" && kubectl delete -f examples/policy-sample-1.yaml`), run(`cd "${mainDir}" && kubectl delete -f examples/policy-sample-2.yaml`), From 8c28c5f56f5884877bacbee0538c89a8f8e99f82 Mon Sep 17 00:00:00 2001 From: f1ames Date: Mon, 16 Oct 2023 11:22:58 +0200 Subject: [PATCH 05/17] refactor: add helm chart skeleton --- .github/workflows/test.yaml | 43 +++++++++- README.md | 17 ++++ helm/.helmignore | 23 +++++ helm/Chart.yaml | 24 ++++++ helm/templates/_helpers.tpl | 62 ++++++++++++++ helm/templates/deployment.yaml | 85 +++++++++++++++++++ .../templates/monokle-policy-binding-crd.yaml | 46 ++++++++++ helm/templates/monokle-policy-crd.yaml | 50 +++++++++++ helm/templates/namespace.yaml | 4 + helm/templates/service-account.yaml | 76 +++++++++++++++++ helm/values.yaml | 82 ++++++++++++++++++ 11 files changed, 511 insertions(+), 1 deletion(-) create mode 100644 helm/.helmignore create mode 100644 helm/Chart.yaml create mode 100644 helm/templates/_helpers.tpl create mode 100644 helm/templates/deployment.yaml create mode 100644 helm/templates/monokle-policy-binding-crd.yaml create mode 100644 helm/templates/monokle-policy-crd.yaml create mode 100644 helm/templates/namespace.yaml create mode 100644 helm/templates/service-account.yaml create mode 100644 helm/values.yaml diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4b09478..4484960 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -9,7 +9,7 @@ on: concurrency: ${{ github.workflow }}-${{ github.ref }} jobs: - test: + test-skaffold: name: Test runs-on: ubuntu-latest steps: @@ -44,3 +44,44 @@ jobs: - name: Test working-directory: ./tests/ run: npm test + + test-helm: + name: Test + runs-on: ubuntu-latest + steps: + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: 18 + + - name: Checkout Repo + uses: actions/checkout@v2 + + - name: Start Minikube + run: minikube start --uuid 00000000-0000-0000-0000-000000000001 --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook + + - name: Build local images (init container) + run: eval $(minikube -p minikube docker-env) && minikube image build -t admission-webhook-init -f ./Dockerfile . + working-directory: ./admission-controller/init + + - name: Build local images (server container) + run: eval $(minikube -p minikube docker-env) && minikube image build -t admission-webhook -f ./Dockerfile . + working-directory: ./admission-controller/server + + - name: Helm install + run: eval $(minikube -p minikube docker-env) && helm install monokle-ac ./helm + + # @TODO move to test beforeAll to correctly detect if admission-controller pod is ready. + - name: Wait for Admission Controller + run: sleep 60 + + - name: Preview namespace state + run: kubectl -n monokle-admission-controller get all,CustomResourceDefinition,ValidatingWebhookConfiguration,secrets + + - name: Install Dependencies + working-directory: ./tests/ + run: npm ci + + - name: Test + working-directory: ./tests/ + run: npm test diff --git a/README.md b/README.md index c3509a3..8af9079 100644 --- a/README.md +++ b/README.md @@ -143,3 +143,20 @@ kubectl delete crd policybindings.monokle.io * https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ * https://kubernetes-client.github.io/javascript/index.html * https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/ + + +### Helm with minikube for testing + +```bash +eval $(minikube -p minikube docker-env) +``` +```bash +cd admission-controller/[server|init] +minikube image build -t admission-webhook-init -f ./Dockerfile . +minikube image build -t admission-webhook -f ./Dockerfile . +docker images +``` + +```bash +helm install monokle-ac ./monokle-admission-controller --dry-run --debug +``` \ No newline at end of file diff --git a/helm/.helmignore b/helm/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helm/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/Chart.yaml b/helm/Chart.yaml new file mode 100644 index 0000000..2675740 --- /dev/null +++ b/helm/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: monokle-admission-controller +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl new file mode 100644 index 0000000..24e3439 --- /dev/null +++ b/helm/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "monokle-admission-controller.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "monokle-admission-controller.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "monokle-admission-controller.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "monokle-admission-controller.labels" -}} +helm.sh/chart: {{ include "monokle-admission-controller.chart" . }} +{{ include "monokle-admission-controller.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "monokle-admission-controller.selectorLabels" -}} +app.kubernetes.io/name: {{ include "monokle-admission-controller.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "monokle-admission-controller.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "monokle-admission-controller.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml new file mode 100644 index 0000000..1926b4e --- /dev/null +++ b/helm/templates/deployment.yaml @@ -0,0 +1,85 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: monokle-admission-controller-server + namespace: monokle-admission-controller + labels: + app: monokle-admission-controller-server +spec: + replicas: 1 + selector: + matchLabels: + app: monokle-admission-controller-server + template: + metadata: + labels: + app: monokle-admission-controller-server + spec: + initContainers: + - name: init + image: admission-webhook-init + imagePullPolicy: Never + containers: + - name: server + image: admission-webhook + imagePullPolicy: Never + ports: + - containerPort: 8443 + name: webhook-api + volumeMounts: + - name: webhook-tls-certs + mountPath: /run/secrets/tls + readOnly: true + env: + - name: MONOKLE_LOG_LEVEL + value: DEBUG + - name: MONOKLE_IGNORE_NAMESPACES + value: '' + volumes: + - name: webhook-tls-certs + secret: + secretName: monokle-admission-controller-tls + optional: true + serviceAccountName: monokle-policies-sa +--- +apiVersion: v1 +kind: Service +metadata: + name: monokle-admission-controller-server + namespace: monokle-admission-controller +spec: + selector: + app: monokle-admission-controller-server + ports: + - port: 443 + targetPort: webhook-api +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: monokle-admission-controller-webhook +webhooks: + - name: monokle-admission-controller-server.monokle-admission-controller.svc + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + clientConfig: + service: + name: monokle-admission-controller-server + namespace: monokle-admission-controller + path: "/validate" + caBundle: "" + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: + - kube-node-lease + - kube-public + - kube-system + - monokle-admission-controller + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*"] + scope: "*" \ No newline at end of file diff --git a/helm/templates/monokle-policy-binding-crd.yaml b/helm/templates/monokle-policy-binding-crd.yaml new file mode 100644 index 0000000..92a0c6b --- /dev/null +++ b/helm/templates/monokle-policy-binding-crd.yaml @@ -0,0 +1,46 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: policybindings.monokle.io +spec: + group: monokle.io + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - policyName + - validationActions + properties: + policyName: + type: string + validationActions: + type: array + items: + type: string + enum: [Warn] + matchResources: + type: object + properties: + namespaceSelector: + type: object + properties: + matchLabels: + type: object + additionalProperties: + type: string + scope: Cluster + names: + plural: policybindings + singular: policybinding + kind: MonoklePolicyBinding + shortNames: + - mpb \ No newline at end of file diff --git a/helm/templates/monokle-policy-crd.yaml b/helm/templates/monokle-policy-crd.yaml new file mode 100644 index 0000000..31fabad --- /dev/null +++ b/helm/templates/monokle-policy-crd.yaml @@ -0,0 +1,50 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: policies.monokle.io +spec: + group: monokle.io + versions: + - name: v1alpha1 + served: true + storage: true + schema: + # For schema see: + # - maps/dicts - https://swagger.io/docs/specification/data-models/dictionaries/ + # - structural schema - https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema + # + # Object values as multitypes: + # Even though it's supported by OpenAPI spec, e.g. https://stackoverflow.com/a/46475776, + # Kubernetes requires "structural" definition # https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema + # which seems to be in opposite to it "does not set description, type, default, additionalProperties, nullable + # within an allOf, anyOf, oneOf or not, with the exception of the two pattern for x-kubernetes-int-or-string: true (see below)." + openAPIV3Schema: + type: object + required: + - spec + properties: + spec: + type: object + required: + - plugins + properties: + plugins: + type: object + additionalProperties: + type: boolean + rules: + type: object + additionalProperties: true + settings: + type: object + additionalProperties: + type: object + additionalProperties: + type: string + scope: Cluster + names: + plural: policies + singular: policy + kind: MonoklePolicy + shortNames: + - mp diff --git a/helm/templates/namespace.yaml b/helm/templates/namespace.yaml new file mode 100644 index 0000000..9a18955 --- /dev/null +++ b/helm/templates/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: monokle-admission-controller diff --git a/helm/templates/service-account.yaml b/helm/templates/service-account.yaml new file mode 100644 index 0000000..636fdbb --- /dev/null +++ b/helm/templates/service-account.yaml @@ -0,0 +1,76 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: monokle-policies-sa + namespace: monokle-admission-controller + +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: monokle-policies +rules: +- apiGroups: ["monokle.io"] + resources: ["policies", "policybindings"] + verbs: ["list", "watch"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: monokle-policies +subjects: +- kind: ServiceAccount + name: monokle-policies-sa + namespace: monokle-admission-controller +roleRef: + kind: ClusterRole + name: monokle-policies + apiGroup: rbac.authorization.k8s.io + +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: monokle-policies-init-vwc +rules: +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get", "patch"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: monokle-policies-init-vwc +subjects: +- kind: ServiceAccount + name: monokle-policies-sa + namespace: monokle-admission-controller +roleRef: + kind: ClusterRole + name: monokle-policies-init-vwc + apiGroup: rbac.authorization.k8s.io + +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: monokle-policies-init-secrets + namespace: monokle-admission-controller +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "create", "delete"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: monokle-policies-init-secrets + namespace: monokle-admission-controller +subjects: +- kind: ServiceAccount + name: monokle-policies-sa + namespace: monokle-admission-controller +roleRef: + kind: Role + name: monokle-policies-init-secrets + apiGroup: rbac.authorization.k8s.io diff --git a/helm/values.yaml b/helm/values.yaml new file mode 100644 index 0000000..c26999e --- /dev/null +++ b/helm/values.yaml @@ -0,0 +1,82 @@ +# Default values for monokle-admission-controller. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# replicaCount: 1 + +# image: +# repository: nginx +# pullPolicy: IfNotPresent +# # Overrides the image tag whose default is the chart appVersion. +# tag: "" + +# imagePullSecrets: [] +# nameOverride: "" +# fullnameOverride: "" + +# serviceAccount: +# # Specifies whether a service account should be created +# create: true +# # Annotations to add to the service account +# annotations: {} +# # The name of the service account to use. +# # If not set and create is true, a name is generated using the fullname template +# name: "" + +# podAnnotations: {} + +# podSecurityContext: {} +# # fsGroup: 2000 + +# securityContext: {} +# # capabilities: +# # drop: +# # - ALL +# # readOnlyRootFilesystem: true +# # runAsNonRoot: true +# # runAsUser: 1000 + +# service: +# type: ClusterIP +# port: 80 + +# ingress: +# enabled: false +# className: "" +# annotations: {} +# # kubernetes.io/ingress.class: nginx +# # kubernetes.io/tls-acme: "true" +# hosts: +# - host: chart-example.local +# paths: +# - path: / +# pathType: ImplementationSpecific +# tls: [] +# # - secretName: chart-example-tls +# # hosts: +# # - chart-example.local + +# resources: {} +# # We usually recommend not to specify default resources and to leave this as a conscious +# # choice for the user. This also increases chances charts run on environments with little +# # resources, such as Minikube. If you do want to specify resources, uncomment the following +# # lines, adjust them as necessary, and remove the curly braces after 'resources:'. +# # limits: +# # cpu: 100m +# # memory: 128Mi +# # requests: +# # cpu: 100m +# # memory: 128Mi + +# autoscaling: +# enabled: false +# minReplicas: 1 +# maxReplicas: 100 +# targetCPUUtilizationPercentage: 80 +# # targetMemoryUtilizationPercentage: 80 + +# nodeSelector: {} + +# tolerations: [] + +# affinity: {} From 698351c84f2dcd53af8b92894489d89dc5c00355 Mon Sep 17 00:00:00 2001 From: f1ames Date: Mon, 16 Oct 2023 11:50:33 +0200 Subject: [PATCH 06/17] test: fix helm test job --- .github/workflows/test.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4484960..fcaa395 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -10,7 +10,7 @@ concurrency: ${{ github.workflow }}-${{ github.ref }} jobs: test-skaffold: - name: Test + name: Skaffold runs-on: ubuntu-latest steps: - name: Setup Skaffold @@ -46,7 +46,7 @@ jobs: run: npm test test-helm: - name: Test + name: Helm runs-on: ubuntu-latest steps: - name: Setup Node.js @@ -75,6 +75,9 @@ jobs: - name: Wait for Admission Controller run: sleep 60 + - name: Create test namespaces + run: kubectl create namespace nstest1 && kubectl create namespace nstest2 + - name: Preview namespace state run: kubectl -n monokle-admission-controller get all,CustomResourceDefinition,ValidatingWebhookConfiguration,secrets From 922202f703b8651e6348d302be4a12e077a11d53 Mon Sep 17 00:00:00 2001 From: f1ames Date: Mon, 16 Oct 2023 14:04:24 +0200 Subject: [PATCH 07/17] feat: support namespace customization --- .github/workflows/test.yaml | 6 +- README.md | 2 +- admission-controller/init/src/index.ts | 2 +- .../init/src/utils/certificates.ts | 4 +- helm/Chart.yaml | 21 +--- helm/templates/_helpers.tpl | 27 +---- helm/templates/deployment.yaml | 13 ++- helm/templates/namespace.yaml | 2 +- helm/templates/service-account.yaml | 12 +-- helm/values.yaml | 100 ++++-------------- k8s/manifests/deployment.yaml | 3 + tests/src/integration.spec.ts | 3 +- 12 files changed, 51 insertions(+), 144 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index fcaa395..f128f2c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -69,7 +69,7 @@ jobs: working-directory: ./admission-controller/server - name: Helm install - run: eval $(minikube -p minikube docker-env) && helm install monokle-ac ./helm + run: eval $(minikube -p minikube docker-env) && helm install monokle-ac ./helm --set namespace=mac-test # @TODO move to test beforeAll to correctly detect if admission-controller pod is ready. - name: Wait for Admission Controller @@ -79,7 +79,7 @@ jobs: run: kubectl create namespace nstest1 && kubectl create namespace nstest2 - name: Preview namespace state - run: kubectl -n monokle-admission-controller get all,CustomResourceDefinition,ValidatingWebhookConfiguration,secrets + run: kubectl -n mac-test get all,CustomResourceDefinition,ValidatingWebhookConfiguration,secrets - name: Install Dependencies working-directory: ./tests/ @@ -87,4 +87,4 @@ jobs: - name: Test working-directory: ./tests/ - run: npm test + run: MONOKLE_NAMESPACE=mac-test && npm test diff --git a/README.md b/README.md index 8af9079..b54f3bd 100644 --- a/README.md +++ b/README.md @@ -158,5 +158,5 @@ docker images ``` ```bash -helm install monokle-ac ./monokle-admission-controller --dry-run --debug +helm install monokle-ac ./helm --dry-run --debug ``` \ No newline at end of file diff --git a/admission-controller/init/src/index.ts b/admission-controller/init/src/index.ts index e456215..2817fa7 100644 --- a/admission-controller/init/src/index.ts +++ b/admission-controller/init/src/index.ts @@ -4,7 +4,7 @@ import logger, { formatLog } from './utils/logger.js'; import { generateCertificates, isCertExpiring, isCertValid } from './utils/certificates.js'; import { getSecretCertificate, applySecretCertificate, getWebhookConfiguration, patchWebhookCertificate } from './utils/kubernetes.js'; -const NAMESPACE = 'monokle-admission-controller'; +const NAMESPACE = (process.env.MONOKLE_NAMESPACE || 'monokle-admission-controller'); const SECRET_NAME = 'monokle-admission-controller-tls'; const WEBHOOK_NAME = 'monokle-admission-controller-webhook'; diff --git a/admission-controller/init/src/utils/certificates.ts b/admission-controller/init/src/utils/certificates.ts index dce76eb..18db650 100644 --- a/admission-controller/init/src/utils/certificates.ts +++ b/admission-controller/init/src/utils/certificates.ts @@ -41,7 +41,7 @@ export function generateCertificates(namespace: string, expireInMonths: number): serverCert.setSubject([ { name: 'commonName', - value: 'monokle-admission-controller-server.monokle-admission-controller.svc', + value: `monokle-admission-controller-server.${namespace}.svc`, }, ]); serverCert.setIssuer(caCert.subject.attributes); @@ -66,7 +66,7 @@ export function generateCertificates(namespace: string, expireInMonths: number): altNames: [ { type: 2, - value: 'monokle-admission-controller-server.monokle-admission-controller.svc', + value: `monokle-admission-controller-server.${namespace}.svc`, }, ], }, diff --git a/helm/Chart.yaml b/helm/Chart.yaml index 2675740..82025ee 100644 --- a/helm/Chart.yaml +++ b/helm/Chart.yaml @@ -1,24 +1,7 @@ apiVersion: v2 name: monokle-admission-controller -description: A Helm chart for Kubernetes +description: Monokle Admission Controller Helm Chart -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) version: 0.1.0 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "1.16.0" +appVersion: "0.1.0" diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl index 24e3439..fcc377a 100644 --- a/helm/templates/_helpers.tpl +++ b/helm/templates/_helpers.tpl @@ -1,26 +1,5 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "monokle-admission-controller.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "monokle-admission-controller.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} +{{- define "monokle-admission-controller.namespace" -}} +{{ default .Release.Namespace .Values.namespace }} {{- end }} {{/* @@ -46,7 +25,7 @@ app.kubernetes.io/managed-by: {{ .Release.Service }} Selector labels */}} {{- define "monokle-admission-controller.selectorLabels" -}} -app.kubernetes.io/name: {{ include "monokle-admission-controller.name" . }} +{{/*app.kubernetes.io/name: {{ include "monokle-admission-controller.name" . }} */}} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml index 1926b4e..24a9035 100644 --- a/helm/templates/deployment.yaml +++ b/helm/templates/deployment.yaml @@ -2,7 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: monokle-admission-controller-server - namespace: monokle-admission-controller + namespace: {{ include "monokle-admission-controller.namespace" . }} labels: app: monokle-admission-controller-server spec: @@ -19,6 +19,9 @@ spec: - name: init image: admission-webhook-init imagePullPolicy: Never + env: + - name: MONOKLE_NAMESPACE + value: {{ include "monokle-admission-controller.namespace" . }} containers: - name: server image: admission-webhook @@ -46,7 +49,7 @@ apiVersion: v1 kind: Service metadata: name: monokle-admission-controller-server - namespace: monokle-admission-controller + namespace: {{ include "monokle-admission-controller.namespace" . }} spec: selector: app: monokle-admission-controller-server @@ -59,13 +62,13 @@ kind: ValidatingWebhookConfiguration metadata: name: monokle-admission-controller-webhook webhooks: - - name: monokle-admission-controller-server.monokle-admission-controller.svc + - name: monokle-admission-controller-server.{{ include "monokle-admission-controller.namespace" . }}.svc sideEffects: None admissionReviewVersions: ["v1", "v1beta1"] clientConfig: service: name: monokle-admission-controller-server - namespace: monokle-admission-controller + namespace: {{ include "monokle-admission-controller.namespace" . }} path: "/validate" caBundle: "" namespaceSelector: @@ -76,7 +79,7 @@ webhooks: - kube-node-lease - kube-public - kube-system - - monokle-admission-controller + - {{ include "monokle-admission-controller.namespace" . }} rules: - operations: ["CREATE", "UPDATE"] apiGroups: ["*"] diff --git a/helm/templates/namespace.yaml b/helm/templates/namespace.yaml index 9a18955..291e978 100644 --- a/helm/templates/namespace.yaml +++ b/helm/templates/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: monokle-admission-controller + name: {{ include "monokle-admission-controller.namespace" . }} diff --git a/helm/templates/service-account.yaml b/helm/templates/service-account.yaml index 636fdbb..5ffe31a 100644 --- a/helm/templates/service-account.yaml +++ b/helm/templates/service-account.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: ServiceAccount metadata: name: monokle-policies-sa - namespace: monokle-admission-controller + namespace: {{ include "monokle-admission-controller.namespace" . }} --- kind: ClusterRole @@ -21,7 +21,7 @@ metadata: subjects: - kind: ServiceAccount name: monokle-policies-sa - namespace: monokle-admission-controller + namespace: {{ include "monokle-admission-controller.namespace" . }} roleRef: kind: ClusterRole name: monokle-policies @@ -44,7 +44,7 @@ metadata: subjects: - kind: ServiceAccount name: monokle-policies-sa - namespace: monokle-admission-controller + namespace: {{ include "monokle-admission-controller.namespace" . }} roleRef: kind: ClusterRole name: monokle-policies-init-vwc @@ -55,7 +55,7 @@ kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: monokle-policies-init-secrets - namespace: monokle-admission-controller + namespace: {{ include "monokle-admission-controller.namespace" . }} rules: - apiGroups: [""] resources: ["secrets"] @@ -65,11 +65,11 @@ kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: monokle-policies-init-secrets - namespace: monokle-admission-controller + namespace: {{ include "monokle-admission-controller.namespace" . }} subjects: - kind: ServiceAccount name: monokle-policies-sa - namespace: monokle-admission-controller + namespace: {{ include "monokle-admission-controller.namespace" . }} roleRef: kind: Role name: monokle-policies-init-secrets diff --git a/helm/values.yaml b/helm/values.yaml index c26999e..fb25463 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -1,82 +1,20 @@ -# Default values for monokle-admission-controller. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -# replicaCount: 1 - # image: -# repository: nginx -# pullPolicy: IfNotPresent -# # Overrides the image tag whose default is the chart appVersion. -# tag: "" - -# imagePullSecrets: [] -# nameOverride: "" -# fullnameOverride: "" - -# serviceAccount: -# # Specifies whether a service account should be created -# create: true -# # Annotations to add to the service account -# annotations: {} -# # The name of the service account to use. -# # If not set and create is true, a name is generated using the fullname template -# name: "" - -# podAnnotations: {} - -# podSecurityContext: {} -# # fsGroup: 2000 - -# securityContext: {} -# # capabilities: -# # drop: -# # - ALL -# # readOnlyRootFilesystem: true -# # runAsNonRoot: true -# # runAsUser: 1000 - -# service: -# type: ClusterIP -# port: 80 - -# ingress: -# enabled: false -# className: "" -# annotations: {} -# # kubernetes.io/ingress.class: nginx -# # kubernetes.io/tls-acme: "true" -# hosts: -# - host: chart-example.local -# paths: -# - path: / -# pathType: ImplementationSpecific -# tls: [] -# # - secretName: chart-example-tls -# # hosts: -# # - chart-example.local - -# resources: {} -# # We usually recommend not to specify default resources and to leave this as a conscious -# # choice for the user. This also increases chances charts run on environments with little -# # resources, such as Minikube. If you do want to specify resources, uncomment the following -# # lines, adjust them as necessary, and remove the curly braces after 'resources:'. -# # limits: -# # cpu: 100m -# # memory: 128Mi -# # requests: -# # cpu: 100m -# # memory: 128Mi - -# autoscaling: -# enabled: false -# minReplicas: 1 -# maxReplicas: 100 -# targetCPUUtilizationPercentage: 80 -# # targetMemoryUtilizationPercentage: 80 - -# nodeSelector: {} - -# tolerations: [] - -# affinity: {} +# init: +# # repository: nginx +# pullPolicy: IfNotPresent +# # Overrides the image tag whose default is the chart appVersion. +# tag: "" +# overridePath: '' +# server: +# # repository: nginx +# pullPolicy: IfNotPresent +# # Overrides the image tag whose default is the chart appVersion. +# tag: "" +# overridePath: '' + +# Deploy Monokle Admission Controller resources to below namespace. +namespace: monokle-admission-controller + +# # Do not validate resources from these namespaces. +# ignoreNamespaces: +# - ns1 diff --git a/k8s/manifests/deployment.yaml b/k8s/manifests/deployment.yaml index e3f9935..c92be71 100644 --- a/k8s/manifests/deployment.yaml +++ b/k8s/manifests/deployment.yaml @@ -18,6 +18,9 @@ spec: initContainers: - name: init image: admission-webhook-init + env: + - name: MONOKLE_NAMESPACE + value: monokle-admission-controller containers: - name: server image: admission-webhook diff --git a/tests/src/integration.spec.ts b/tests/src/integration.spec.ts index db46ef7..4e6240e 100644 --- a/tests/src/integration.spec.ts +++ b/tests/src/integration.spec.ts @@ -3,6 +3,7 @@ import { afterEach, assert, beforeAll, describe, it } from 'vitest' import shell from 'shelljs'; const VERBOSE = process.env.VERBOSE === 'true'; +const NAMESPACE = process.env.MONOKLE_NAMESPACE || 'monokle-admission-controller'; const currentDir = __dirname; const mainDir = resolve(join(currentDir, '..', '..')); @@ -12,7 +13,7 @@ const mainDir = resolve(join(currentDir, '..', '..')); describe(`All (dir: ${mainDir})`, () => { beforeAll(async () => { - await waitForResult('kubectl -n monokle-admission-controller get pod', (result) => { + await waitForResult(`kubectl -n ${NAMESPACE} get pod`, (result) => { return result.includes('monokle-admission-controller-server') && result.includes('Running'); }, 50000); From e77bd94632dddb3f8be41d92cf668ff89dbe77cd Mon Sep 17 00:00:00 2001 From: f1ames Date: Mon, 16 Oct 2023 14:11:02 +0200 Subject: [PATCH 08/17] test: fix helm test job --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f128f2c..5259795 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -87,4 +87,4 @@ jobs: - name: Test working-directory: ./tests/ - run: MONOKLE_NAMESPACE=mac-test && npm test + run: MONOKLE_NAMESPACE=mac-test npm test From 204a0ece605a78964e017454324c1ffaca04a40d Mon Sep 17 00:00:00 2001 From: f1ames Date: Mon, 16 Oct 2023 16:43:20 +0200 Subject: [PATCH 09/17] fix: propagate values to chart --- .github/workflows/test.yaml | 9 +++++++- helm/templates/_helpers.tpl | 26 +++++------------------ helm/templates/deployment.yaml | 25 ++++++++++++++++++---- helm/templates/namespace.yaml | 2 ++ helm/templates/service-account.yaml | 14 ++++++++++++ helm/values.yaml | 33 ++++++++++++++++------------- 6 files changed, 68 insertions(+), 41 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5259795..7b95c04 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -69,7 +69,14 @@ jobs: working-directory: ./admission-controller/server - name: Helm install - run: eval $(minikube -p minikube docker-env) && helm install monokle-ac ./helm --set namespace=mac-test + run: | + eval $(minikube -p minikube docker-env) + helm install monokle-ac ./helm \ + --set namespace=mac-test \ + --set image.init.pullPolicy=Never \ + --set image.init.overridePath=admission-webhook-init \ + --set image.server.pullPolicy=Never \ + --set image.server.overridePath=admission-webhook # @TODO move to test beforeAll to correctly detect if admission-controller pod is ready. - name: Wait for Admission Controller diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl index fcc377a..d4988d9 100644 --- a/helm/templates/_helpers.tpl +++ b/helm/templates/_helpers.tpl @@ -1,17 +1,15 @@ +{{- define "monokle-admission-controller.name" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" }} +{{- end }} + {{- define "monokle-admission-controller.namespace" -}} {{ default .Release.Namespace .Values.namespace }} {{- end }} -{{/* -Create chart name and version as used by the chart label. -*/}} {{- define "monokle-admission-controller.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} {{- end }} -{{/* -Common labels -*/}} {{- define "monokle-admission-controller.labels" -}} helm.sh/chart: {{ include "monokle-admission-controller.chart" . }} {{ include "monokle-admission-controller.selectorLabels" . }} @@ -21,21 +19,7 @@ app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end }} -{{/* -Selector labels -*/}} {{- define "monokle-admission-controller.selectorLabels" -}} -{{/*app.kubernetes.io/name: {{ include "monokle-admission-controller.name" . }} */}} +app.kubernetes.io/name: {{ include "monokle-admission-controller.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "monokle-admission-controller.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "monokle-admission-controller.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml index 24a9035..8ff6ae4 100644 --- a/helm/templates/deployment.yaml +++ b/helm/templates/deployment.yaml @@ -5,6 +5,7 @@ metadata: namespace: {{ include "monokle-admission-controller.namespace" . }} labels: app: monokle-admission-controller-server + {{- include "monokle-admission-controller.labels" . | nindent 4 }} spec: replicas: 1 selector: @@ -14,18 +15,27 @@ spec: metadata: labels: app: monokle-admission-controller-server + {{- include "monokle-admission-controller.labels" . | nindent 8 }} spec: initContainers: - name: init - image: admission-webhook-init - imagePullPolicy: Never + {{- if not .Values.image.init.overridePath }} + image: "{{ .Values.image.init.repository }}:{{ .Values.image.init.tag | default .Chart.AppVersion }}" + {{- else }} + image: {{ .Values.image.init.overridePath }} + {{- end }} + imagePullPolicy: {{ .Values.image.init.pullPolicy }} env: - name: MONOKLE_NAMESPACE value: {{ include "monokle-admission-controller.namespace" . }} containers: - name: server - image: admission-webhook - imagePullPolicy: Never + {{- if not .Values.image.server.overridePath }} + image: "{{ .Values.image.server.repository }}:{{ .Values.image.server.tag | default .Chart.AppVersion }}" + {{- else }} + image: {{ .Values.image.server.overridePath }} + {{- end }} + imagePullPolicy: {{ .Values.image.server.pullPolicy }} ports: - containerPort: 8443 name: webhook-api @@ -50,6 +60,8 @@ kind: Service metadata: name: monokle-admission-controller-server namespace: {{ include "monokle-admission-controller.namespace" . }} + labels: + {{- include "monokle-admission-controller.labels" . | nindent 4 }} spec: selector: app: monokle-admission-controller-server @@ -61,6 +73,8 @@ apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: name: monokle-admission-controller-webhook + labels: + {{- include "monokle-admission-controller.labels" . | nindent 4 }} webhooks: - name: monokle-admission-controller-server.{{ include "monokle-admission-controller.namespace" . }}.svc sideEffects: None @@ -80,6 +94,9 @@ webhooks: - kube-public - kube-system - {{ include "monokle-admission-controller.namespace" . }} + {{- with .Values.ignoreNamespaces }} + {{- toYaml . | nindent 12 }} + {{- end }} rules: - operations: ["CREATE", "UPDATE"] apiGroups: ["*"] diff --git a/helm/templates/namespace.yaml b/helm/templates/namespace.yaml index 291e978..b7ee910 100644 --- a/helm/templates/namespace.yaml +++ b/helm/templates/namespace.yaml @@ -2,3 +2,5 @@ apiVersion: v1 kind: Namespace metadata: name: {{ include "monokle-admission-controller.namespace" . }} + labels: + {{- include "monokle-admission-controller.labels" . | nindent 4 }} diff --git a/helm/templates/service-account.yaml b/helm/templates/service-account.yaml index 5ffe31a..1999410 100644 --- a/helm/templates/service-account.yaml +++ b/helm/templates/service-account.yaml @@ -3,12 +3,16 @@ kind: ServiceAccount metadata: name: monokle-policies-sa namespace: {{ include "monokle-admission-controller.namespace" . }} + labels: + {{- include "monokle-admission-controller.labels" . | nindent 4 }} --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: monokle-policies + labels: + {{- include "monokle-admission-controller.labels" . | nindent 4 }} rules: - apiGroups: ["monokle.io"] resources: ["policies", "policybindings"] @@ -18,6 +22,8 @@ kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: monokle-policies + labels: + {{- include "monokle-admission-controller.labels" . | nindent 4 }} subjects: - kind: ServiceAccount name: monokle-policies-sa @@ -32,6 +38,8 @@ kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: monokle-policies-init-vwc + labels: + {{- include "monokle-admission-controller.labels" . | nindent 4 }} rules: - apiGroups: ["admissionregistration.k8s.io"] resources: ["validatingwebhookconfigurations"] @@ -41,6 +49,8 @@ kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: monokle-policies-init-vwc + labels: + {{- include "monokle-admission-controller.labels" . | nindent 4 }} subjects: - kind: ServiceAccount name: monokle-policies-sa @@ -56,6 +66,8 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: monokle-policies-init-secrets namespace: {{ include "monokle-admission-controller.namespace" . }} + labels: + {{- include "monokle-admission-controller.labels" . | nindent 4 }} rules: - apiGroups: [""] resources: ["secrets"] @@ -66,6 +78,8 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: monokle-policies-init-secrets namespace: {{ include "monokle-admission-controller.namespace" . }} + labels: + {{- include "monokle-admission-controller.labels" . | nindent 4 }} subjects: - kind: ServiceAccount name: monokle-policies-sa diff --git a/helm/values.yaml b/helm/values.yaml index fb25463..0197700 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -1,20 +1,23 @@ -# image: -# init: -# # repository: nginx -# pullPolicy: IfNotPresent -# # Overrides the image tag whose default is the chart appVersion. -# tag: "" -# overridePath: '' -# server: -# # repository: nginx -# pullPolicy: IfNotPresent -# # Overrides the image tag whose default is the chart appVersion. -# tag: "" -# overridePath: '' +image: + init: + repository: monokle-admission-controller-init + pullPolicy: IfNotPresent + # Override the image tag whose default is the chart appVersion. + tag: "" + # Override entire image path. + overridePath: "" + server: + repository: monokle-admission-controller-server + pullPolicy: IfNotPresent + # Override the image tag whose default is the chart appVersion. + tag: "" + # Override entire image path. + overridePath: "" # Deploy Monokle Admission Controller resources to below namespace. namespace: monokle-admission-controller -# # Do not validate resources from these namespaces. -# ignoreNamespaces: +# Do not validate resources from below namespaces. +ignoreNamespaces: # - ns1 +# - ns2 From 2d5e5154bdcbdba2ffb4fe7fdc7f230156a31288 Mon Sep 17 00:00:00 2001 From: f1ames Date: Mon, 16 Oct 2023 16:58:50 +0200 Subject: [PATCH 10/17] test: wait for admission controller readiness in beforeAll --- .github/workflows/test.yaml | 8 -------- tests/src/integration.spec.ts | 8 ++++++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 7b95c04..0081889 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -30,10 +30,6 @@ jobs: - name: Deploy Admission Controller run: ./scripts/deploy.sh - # @TODO move to test beforeAll to correctly detect if admission-controller pod is ready. - - name: Wait for Admission Controller - run: sleep 60 - - name: Preview namespace state run: kubectl -n monokle-admission-controller get all,CustomResourceDefinition,ValidatingWebhookConfiguration,secrets @@ -78,10 +74,6 @@ jobs: --set image.server.pullPolicy=Never \ --set image.server.overridePath=admission-webhook - # @TODO move to test beforeAll to correctly detect if admission-controller pod is ready. - - name: Wait for Admission Controller - run: sleep 60 - - name: Create test namespaces run: kubectl create namespace nstest1 && kubectl create namespace nstest2 diff --git a/tests/src/integration.spec.ts b/tests/src/integration.spec.ts index 4e6240e..a7adf25 100644 --- a/tests/src/integration.spec.ts +++ b/tests/src/integration.spec.ts @@ -15,10 +15,14 @@ describe(`All (dir: ${mainDir})`, () => { beforeAll(async () => { await waitForResult(`kubectl -n ${NAMESPACE} get pod`, (result) => { return result.includes('monokle-admission-controller-server') && result.includes('Running'); - }, 50000); + }, 60 * 1000); + + await waitForResult(`kubectl -n ${NAMESPACE} logs -l app=monokle-admission-controller-server --tail 100`, (result) => { + return result.includes('Server listening at'); + }, 60 * 1000); await cleanup(); - }, 60000); + }, 120 * 1000); afterEach(async () => { await cleanup(); From 04701470c4abe690bd2239f06e0f229d83457549 Mon Sep 17 00:00:00 2001 From: f1ames Date: Mon, 16 Oct 2023 17:02:35 +0200 Subject: [PATCH 11/17] test: fix helm test job steps order --- .github/workflows/test.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 0081889..3b42149 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -56,6 +56,9 @@ jobs: - name: Start Minikube run: minikube start --uuid 00000000-0000-0000-0000-000000000001 --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook + - name: Create test namespaces + run: kubectl create namespace nstest1 && kubectl create namespace nstest2 + - name: Build local images (init container) run: eval $(minikube -p minikube docker-env) && minikube image build -t admission-webhook-init -f ./Dockerfile . working-directory: ./admission-controller/init @@ -74,9 +77,6 @@ jobs: --set image.server.pullPolicy=Never \ --set image.server.overridePath=admission-webhook - - name: Create test namespaces - run: kubectl create namespace nstest1 && kubectl create namespace nstest2 - - name: Preview namespace state run: kubectl -n mac-test get all,CustomResourceDefinition,ValidatingWebhookConfiguration,secrets From 74504099f282f2d74661e8f30394de8b41b16be6 Mon Sep 17 00:00:00 2001 From: f1ames Date: Mon, 16 Oct 2023 17:06:00 +0200 Subject: [PATCH 12/17] test: catch errors in waitForResult helper --- tests/src/integration.spec.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/src/integration.spec.ts b/tests/src/integration.spec.ts index a7adf25..d026818 100644 --- a/tests/src/integration.spec.ts +++ b/tests/src/integration.spec.ts @@ -115,8 +115,12 @@ const waitForResult = async (command: string, isExpected: (result: string) => bo throw new Error(`Timeout waiting for result of command: ${command}`); } - const result = await run(command); - isValid = isExpected(result); + try { + const result = await run(command); + isValid = isExpected(result); + } catch (err) { + VERBOSE && console.log('waitForResult error', err); + } if (!isValid) { sleep(250); From 7a511123948969c652d816bf04b91501be6d09be Mon Sep 17 00:00:00 2001 From: f1ames Date: Tue, 17 Oct 2023 13:43:41 +0200 Subject: [PATCH 13/17] chore: cleanup old files and update docs --- .github/workflows/test.yaml | 6 +- .gitignore | 3 + CONTRIBUTING.md | 181 ++++++++++++++++++ README.md | 159 +-------------- k8s/manifests/deployment.yaml | 86 --------- k8s/manifests/monokle-policy-binding-crd.yaml | 46 ----- k8s/manifests/monokle-policy-crd.yaml | 50 ----- k8s/manifests/namespace.yaml | 4 - k8s/manifests/service-account.yaml | 76 -------- scripts/deploy.sh | 14 +- {k8s => scripts}/skaffold.yaml | 2 +- tests/src/integration.spec.ts | 3 + 12 files changed, 197 insertions(+), 433 deletions(-) create mode 100644 CONTRIBUTING.md delete mode 100644 k8s/manifests/deployment.yaml delete mode 100644 k8s/manifests/monokle-policy-binding-crd.yaml delete mode 100644 k8s/manifests/monokle-policy-crd.yaml delete mode 100644 k8s/manifests/namespace.yaml delete mode 100644 k8s/manifests/service-account.yaml rename {k8s => scripts}/skaffold.yaml (93%) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 3b42149..79e0f38 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -56,9 +56,6 @@ jobs: - name: Start Minikube run: minikube start --uuid 00000000-0000-0000-0000-000000000001 --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook - - name: Create test namespaces - run: kubectl create namespace nstest1 && kubectl create namespace nstest2 - - name: Build local images (init container) run: eval $(minikube -p minikube docker-env) && minikube image build -t admission-webhook-init -f ./Dockerfile . working-directory: ./admission-controller/init @@ -70,7 +67,8 @@ jobs: - name: Helm install run: | eval $(minikube -p minikube docker-env) - helm install monokle-ac ./helm \ + helm package ./helm --version 0.0.0 + helm install monokle-ac monokle-admission-controller-0.0.0.tgz \ --set namespace=mac-test \ --set image.init.pullPolicy=Never \ --set image.init.overridePath=admission-webhook-init \ diff --git a/.gitignore b/.gitignore index f4cefe8..5489213 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,6 @@ test/types/index.js # compiled app dist + +# other tmp files +scripts/install.yaml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4a8d0bd --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,181 @@ +# Contributing and development + +## Prerequisites + +* Minikube (or any other K8s cluster running) +* kubectl +* helm +* Skaffold +* nodejs + +## Running + +Start Minikube (or any other cluster of your choice): + +```bash +minikube start --uuid 00000000-0000-0000-0000-000000000001 --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook +``` + +### Deploying (via Skaffold) + +```bash +./scripts/deploy.sh +``` + +After changes in `./admission-controller` can be reloaded with: + +```bash +skaffold dev -f scripts/skaffold.yaml +``` + +You can also do manual clean-up and re-run `deploy.sh` script again: + +```bash +kubectl delete all -n monokle-admission-controller --all && \ +kubectl delete validatingwebhookconfiguration.admissionregistration.k8s.io/monokle-admission-controller-webhook && \ +kubectl delete namespace monokle-admission-controller && \ +kubectl delete namespace nstest1 && \ +kubectl delete namespace nstest2 && \ +kubectl delete crd policies.monokle.io && \ +kubectl delete crd policybindings.monokle.io +``` + +### Deploying (via Helm + Minikube registry) + +Deploying with helm requires having local docker registry (for locally build images). THis can be done with Minikube: + +```bash +eval $(minikube -p minikube docker-env) +``` + +And then building images: + +```bash +cd admission-controller/init +minikube image build -t admission-webhook-init -f ./Dockerfile . + +cd admission-controller/server +minikube image build -t admission-webhook -f ./Dockerfile . + +docker images +``` + +```bash +helm install monokle-ac ./helm \ +--set image.init.pullPolicy=Never \ +--set image.init.overridePath=admission-webhook-init \ +--set image.server.pullPolicy=Never \ +--set image.server.overridePath=admission-webhook +``` + +To uninstall: + +```bash +helm uninstall monokle-ac +``` + +### Checking deployment state + +Namespaced resources (webhook server) will be deployed to dedicated `monokle-admission-controller` namespace, to watch it you can run: + +```bash +watch kubectl -n monokle-admission-controller get all,CustomResourceDefinition,ValidatingWebhookConfiguration,secrets +``` + +After it runs, the result should be something like: + +```bash +NAME READY STATUS RESTARTS AGE +pod/monokle-admission-controller-server-6958c9bbf8-jvkvk 1/1 Running 0 5m11s + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +service/monokle-admission-controller-server ClusterIP 10.99.122.106 443/TCP 5m11s + +NAME READY UP-TO-DATE AVAILABLE AGE +deployment.apps/monokle-admission-controller-server 1/1 1 1 5m11s + +NAME DESIRED CURRENT READY AGE +replicaset.apps/monokle-admission-controller-server-6958c9bbf8 1 1 1 5m11s + +NAME CREATED AT +customresourcedefinition.apiextensions.k8s.io/policies.monokle.io 2023-10-12T12:16:04Z +customresourcedefinition.apiextensions.k8s.io/policybindings.monokle.io 2023-10-12T12:16:04Z + +NAME WEBHOOKS AGE +validatingwebhookconfiguration.admissionregistration.k8s.io/monokle-admission-controller-webhook 1 5m11s + +NAME TYPE DATA AGE +secret/default-token-w56nz kubernetes.io/service-account-token 3 5m39s +secret/monokle-admission-controller-tls kubernetes.io/tls 2 5m1s +secret/monokle-policies-sa-token-fcpld kubernetes.io/service-account-token 3 5m49s +``` + +For getting info about CRDs: + +```bash +kubectl get crd +kubectl describe crd policies.monokle.io +kubectl describe crd policybindings.monokle.io +``` + +#### Init container logs + +The `monokle-admission-controller-server` has one init container which is responsible for certificate creation/renewal and propagation into cluster. Logs from it can be viewed with: + +```bash +kubectl -n monokle-admission-controller logs pod/monokle-admission-controller-server-... -c init +``` + +## Testing + +Create test namespaces first: + +```bash +kubectl create namespace nstest1 +kubectl create namespace nstest2 +``` + +First you need to create policy resource, for example: + +```bash +kubectl apply -f examples/policy-sample-1.yaml +kubectl apply -f examples/policy-sample-2.yaml +``` + +Then it needs to be bind to be used for validation. Either without scope (globally to all, but ignored namespaces) or with `matchResource` field: + +```bash +kubectl apply -f examples/policy-binding-sample-1.yaml +kubectl apply -f examples/policy-binding-sample-2.yaml +kubectl apply -f examples/policy-binding-sample-3.yaml +``` + +You can inspect deployed policies with: + +```bash +kubectl get policy +kubectl describe policy + +kubectl get policybinding +kubectl describe policybinding +``` + +Then you can try to create sample resource and see webhook response: + +```bash +kubectl apply -f examples/pod-valid.yaml +kubectl apply -f examples/pod-warning.yaml +kubectl apply -f examples/pod-errors.yaml +``` + +## Refs + +* https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/ +* https://github.com/stackrox/admission-controller-webhook-demo/tree/master +* https://www.witodelnat.eu/blog/2021/local-kubernetes-development +* https://minikube.sigs.k8s.io/docs/tutorials/using_psp/ +* https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/ +* https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/ +* https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ +* https://kubernetes-client.github.io/javascript/index.html +* https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/ diff --git a/README.md b/README.md index b54f3bd..6bd9c10 100644 --- a/README.md +++ b/README.md @@ -2,161 +2,10 @@ Monokle Admission Controller is an admission controller for validating resources in the cluster. -## Development - -### Prerequisites - -* Minikube (or any other K8s cluster running) -* kubectl -* Skaffold -* nodejs - -### Running - -#### Minikube - -Start Minikube: - -```bash -minikube start --uuid 00000000-0000-0000-0000-000000000001 --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook -``` - -#### Deploying - -```bash -./scripts/deploy.sh -``` - -Namespaced resources (webhook server) will be deployed to dedicated `monokle-admission-controller` namespace, to watch it you can run: - -```bash -watch kubectl -n monokle-admission-controller get all,CustomResourceDefinition,ValidatingWebhookConfiguration,secrets -``` - -After it runs, the result should be something like: - -```bash -NAME READY STATUS RESTARTS AGE -pod/monokle-admission-controller-server-6958c9bbf8-jvkvk 1/1 Running 0 5m11s - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -service/monokle-admission-controller-server ClusterIP 10.99.122.106 443/TCP 5m11s - -NAME READY UP-TO-DATE AVAILABLE AGE -deployment.apps/monokle-admission-controller-server 1/1 1 1 5m11s - -NAME DESIRED CURRENT READY AGE -replicaset.apps/monokle-admission-controller-server-6958c9bbf8 1 1 1 5m11s - -NAME CREATED AT -customresourcedefinition.apiextensions.k8s.io/policies.monokle.io 2023-10-12T12:16:04Z -customresourcedefinition.apiextensions.k8s.io/policybindings.monokle.io 2023-10-12T12:16:04Z - -NAME WEBHOOKS AGE -validatingwebhookconfiguration.admissionregistration.k8s.io/monokle-admission-controller-webhook 1 5m11s - -NAME TYPE DATA AGE -secret/default-token-w56nz kubernetes.io/service-account-token 3 5m39s -secret/monokle-admission-controller-tls kubernetes.io/tls 2 5m1s -secret/monokle-policies-sa-token-fcpld kubernetes.io/service-account-token 3 5m49s -``` - -For getting info about CRDs: - -```bash -kubectl get crd -kubectl describe crd policies.monokle.io -kubectl describe crd policybindings.monokle.io -``` - -##### Init container logs +## Installation -The `monokle-admission-controller-server` has one init container which is responsible for certificate creation/renewal and propagation into cluster. Logs from it can be viewed with: +// TBD -```bash -kubectl -n monokle-admission-controller logs pod/monokle-admission-controller-server-... -c init -``` - -#### Testing - -First you need to create policy resource, for example: - -```bash -kubectl apply -f examples/policy-sample-1.yaml -kubectl apply -f examples/policy-sample-2.yaml -``` - -Then it needs to be bind to be used for validation. Either without scope (globally to all, but ignored namespaces) or with `matchResource` field: - -```bash -kubectl apply -f examples/policy-binding-sample-1.yaml -kubectl apply -f examples/policy-binding-sample-2.yaml -kubectl apply -f examples/policy-binding-sample-3.yaml -``` - -You can inspect deployed policies with: - -```bash -kubectl get policy -kubectl describe policy - -kubectl get policybinding -kubectl describe policybinding -``` - -Then you can try to create sample resource and see webhook response: - -```bash -kubectl apply -f examples/pod-valid.yaml -kubectl apply -f examples/pod-warning.yaml -kubectl apply -f examples/pod-errors.yaml -``` - -#### Iterating - -After everything is running you can allow hot-reload by running: - -```bash -skaffold dev -f k8s/skaffold.yaml -``` - -You can also do manual clean-up and re-run `./deploy.sh` script again: - -```bash -kubectl delete all -n monokle-admission-controller --all && \ -kubectl delete validatingwebhookconfiguration.admissionregistration.k8s.io/monokle-admission-controller-webhook && \ -kubectl delete namespace monokle-admission-controller && \ -kubectl delete namespace nstest1 && \ -kubectl delete namespace nstest2 && \ -kubectl delete crd policies.monokle.io && \ -kubectl delete crd policybindings.monokle.io -``` - -### Refs - -* https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/ -* https://github.com/stackrox/admission-controller-webhook-demo/tree/master -* https://www.witodelnat.eu/blog/2021/local-kubernetes-development -* https://minikube.sigs.k8s.io/docs/tutorials/using_psp/ -* https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/ -* https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/ -* https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ -* https://kubernetes-client.github.io/javascript/index.html -* https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/ - - -### Helm with minikube for testing - -```bash -eval $(minikube -p minikube docker-env) -``` -```bash -cd admission-controller/[server|init] -minikube image build -t admission-webhook-init -f ./Dockerfile . -minikube image build -t admission-webhook -f ./Dockerfile . -docker images -``` +## Development -```bash -helm install monokle-ac ./helm --dry-run --debug -``` \ No newline at end of file +See [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/k8s/manifests/deployment.yaml b/k8s/manifests/deployment.yaml deleted file mode 100644 index c92be71..0000000 --- a/k8s/manifests/deployment.yaml +++ /dev/null @@ -1,86 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: monokle-admission-controller-server - namespace: monokle-admission-controller - labels: - app: monokle-admission-controller-server -spec: - replicas: 1 - selector: - matchLabels: - app: monokle-admission-controller-server - template: - metadata: - labels: - app: monokle-admission-controller-server - spec: - initContainers: - - name: init - image: admission-webhook-init - env: - - name: MONOKLE_NAMESPACE - value: monokle-admission-controller - containers: - - name: server - image: admission-webhook - ports: - - containerPort: 8443 - name: webhook-api - volumeMounts: - - name: webhook-tls-certs - mountPath: /run/secrets/tls - readOnly: true - env: - - name: MONOKLE_LOG_LEVEL - value: DEBUG - - name: MONOKLE_IGNORE_NAMESPACES - value: '' - volumes: - - name: webhook-tls-certs - secret: - secretName: monokle-admission-controller-tls - optional: true - serviceAccountName: monokle-policies-sa ---- -apiVersion: v1 -kind: Service -metadata: - name: monokle-admission-controller-server - namespace: monokle-admission-controller -spec: - selector: - app: monokle-admission-controller-server - ports: - - port: 443 - targetPort: webhook-api ---- -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - name: monokle-admission-controller-webhook -webhooks: - - name: monokle-admission-controller-server.monokle-admission-controller.svc - sideEffects: None - admissionReviewVersions: ["v1", "v1beta1"] - clientConfig: - service: - name: monokle-admission-controller-server - namespace: monokle-admission-controller - path: "/validate" - caBundle: "" - namespaceSelector: - matchExpressions: - - key: kubernetes.io/metadata.name - operator: NotIn - values: - - kube-node-lease - - kube-public - - kube-system - - monokle-admission-controller - rules: - - operations: ["CREATE", "UPDATE"] - apiGroups: ["*"] - apiVersions: ["*"] - resources: ["*"] - scope: "*" \ No newline at end of file diff --git a/k8s/manifests/monokle-policy-binding-crd.yaml b/k8s/manifests/monokle-policy-binding-crd.yaml deleted file mode 100644 index 92a0c6b..0000000 --- a/k8s/manifests/monokle-policy-binding-crd.yaml +++ /dev/null @@ -1,46 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: policybindings.monokle.io -spec: - group: monokle.io - versions: - - name: v1alpha1 - served: true - storage: true - schema: - openAPIV3Schema: - type: object - required: - - spec - properties: - spec: - type: object - required: - - policyName - - validationActions - properties: - policyName: - type: string - validationActions: - type: array - items: - type: string - enum: [Warn] - matchResources: - type: object - properties: - namespaceSelector: - type: object - properties: - matchLabels: - type: object - additionalProperties: - type: string - scope: Cluster - names: - plural: policybindings - singular: policybinding - kind: MonoklePolicyBinding - shortNames: - - mpb \ No newline at end of file diff --git a/k8s/manifests/monokle-policy-crd.yaml b/k8s/manifests/monokle-policy-crd.yaml deleted file mode 100644 index 31fabad..0000000 --- a/k8s/manifests/monokle-policy-crd.yaml +++ /dev/null @@ -1,50 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: policies.monokle.io -spec: - group: monokle.io - versions: - - name: v1alpha1 - served: true - storage: true - schema: - # For schema see: - # - maps/dicts - https://swagger.io/docs/specification/data-models/dictionaries/ - # - structural schema - https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema - # - # Object values as multitypes: - # Even though it's supported by OpenAPI spec, e.g. https://stackoverflow.com/a/46475776, - # Kubernetes requires "structural" definition # https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema - # which seems to be in opposite to it "does not set description, type, default, additionalProperties, nullable - # within an allOf, anyOf, oneOf or not, with the exception of the two pattern for x-kubernetes-int-or-string: true (see below)." - openAPIV3Schema: - type: object - required: - - spec - properties: - spec: - type: object - required: - - plugins - properties: - plugins: - type: object - additionalProperties: - type: boolean - rules: - type: object - additionalProperties: true - settings: - type: object - additionalProperties: - type: object - additionalProperties: - type: string - scope: Cluster - names: - plural: policies - singular: policy - kind: MonoklePolicy - shortNames: - - mp diff --git a/k8s/manifests/namespace.yaml b/k8s/manifests/namespace.yaml deleted file mode 100644 index 9a18955..0000000 --- a/k8s/manifests/namespace.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: monokle-admission-controller diff --git a/k8s/manifests/service-account.yaml b/k8s/manifests/service-account.yaml deleted file mode 100644 index 636fdbb..0000000 --- a/k8s/manifests/service-account.yaml +++ /dev/null @@ -1,76 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: monokle-policies-sa - namespace: monokle-admission-controller - ---- -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: monokle-policies -rules: -- apiGroups: ["monokle.io"] - resources: ["policies", "policybindings"] - verbs: ["list", "watch"] ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: monokle-policies -subjects: -- kind: ServiceAccount - name: monokle-policies-sa - namespace: monokle-admission-controller -roleRef: - kind: ClusterRole - name: monokle-policies - apiGroup: rbac.authorization.k8s.io - ---- -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: monokle-policies-init-vwc -rules: -- apiGroups: ["admissionregistration.k8s.io"] - resources: ["validatingwebhookconfigurations"] - verbs: ["get", "patch"] ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: monokle-policies-init-vwc -subjects: -- kind: ServiceAccount - name: monokle-policies-sa - namespace: monokle-admission-controller -roleRef: - kind: ClusterRole - name: monokle-policies-init-vwc - apiGroup: rbac.authorization.k8s.io - ---- -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: monokle-policies-init-secrets - namespace: monokle-admission-controller -rules: -- apiGroups: [""] - resources: ["secrets"] - verbs: ["get", "create", "delete"] ---- -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: monokle-policies-init-secrets - namespace: monokle-admission-controller -subjects: -- kind: ServiceAccount - name: monokle-policies-sa - namespace: monokle-admission-controller -roleRef: - kind: Role - name: monokle-policies-init-secrets - apiGroup: rbac.authorization.k8s.io diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 922f25f..e6864d4 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -5,19 +5,11 @@ set -euo pipefail basedir="$(dirname "$0")" -resdir="${basedir}/../k8s/manifests" -# Create test namespaces -kubectl create namespace nstest1 -kubectl create namespace nstest2 - -# Apply monokle-admission-controller releated resources -kubectl apply -f "${resdir}/namespace.yaml" -kubectl apply -f "${resdir}/monokle-policy-crd.yaml" -kubectl apply -f "${resdir}/monokle-policy-binding-crd.yaml" -kubectl apply -f "${resdir}/service-account.yaml" +# Generate install.yaml +helm template "${basedir}/../helm" --set image.init.overridePath=admission-webhook-init --set image.server.overridePath=admission-webhook > "${basedir}/install.yaml" # Run deployment through skaffold with locally build images -skaffold run -n monokle-admission-controller -f k8s/skaffold.yaml +skaffold run -n monokle-admission-controller -f "${basedir}/skaffold.yaml" echo "Deployment complete." diff --git a/k8s/skaffold.yaml b/scripts/skaffold.yaml similarity index 93% rename from k8s/skaffold.yaml rename to scripts/skaffold.yaml index ea4135c..8cb2941 100644 --- a/k8s/skaffold.yaml +++ b/scripts/skaffold.yaml @@ -14,7 +14,7 @@ build: dockerfile: ./admission-controller/init/Dockerfile manifests: rawYaml: - - ./k8s/manifests/deployment.yaml + - ./scripts/install.yaml portForward: - resourceType: service resourceName: monokle-admission-controller-server diff --git a/tests/src/integration.spec.ts b/tests/src/integration.spec.ts index d026818..226e9cc 100644 --- a/tests/src/integration.spec.ts +++ b/tests/src/integration.spec.ts @@ -22,6 +22,9 @@ describe(`All (dir: ${mainDir})`, () => { }, 60 * 1000); await cleanup(); + + await run('kubectl create namespace nstest1'); + await run('kubectl create namespace nstest2'); }, 120 * 1000); afterEach(async () => { From b37986ae18cc24ae722459940b2574c7484a7fd2 Mon Sep 17 00:00:00 2001 From: f1ames Date: Tue, 17 Oct 2023 13:59:00 +0200 Subject: [PATCH 14/17] refactor: cleanup manifests --- helm/templates/deployment.yaml | 49 ------------------- .../templates/monokle-policy-binding-crd.yaml | 2 +- helm/templates/service-account.yaml | 36 +++----------- helm/templates/service.yaml | 13 +++++ helm/templates/webhook.yaml | 34 +++++++++++++ 5 files changed, 54 insertions(+), 80 deletions(-) create mode 100644 helm/templates/service.yaml create mode 100644 helm/templates/webhook.yaml diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml index 8ff6ae4..6721334 100644 --- a/helm/templates/deployment.yaml +++ b/helm/templates/deployment.yaml @@ -54,52 +54,3 @@ spec: secretName: monokle-admission-controller-tls optional: true serviceAccountName: monokle-policies-sa ---- -apiVersion: v1 -kind: Service -metadata: - name: monokle-admission-controller-server - namespace: {{ include "monokle-admission-controller.namespace" . }} - labels: - {{- include "monokle-admission-controller.labels" . | nindent 4 }} -spec: - selector: - app: monokle-admission-controller-server - ports: - - port: 443 - targetPort: webhook-api ---- -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - name: monokle-admission-controller-webhook - labels: - {{- include "monokle-admission-controller.labels" . | nindent 4 }} -webhooks: - - name: monokle-admission-controller-server.{{ include "monokle-admission-controller.namespace" . }}.svc - sideEffects: None - admissionReviewVersions: ["v1", "v1beta1"] - clientConfig: - service: - name: monokle-admission-controller-server - namespace: {{ include "monokle-admission-controller.namespace" . }} - path: "/validate" - caBundle: "" - namespaceSelector: - matchExpressions: - - key: kubernetes.io/metadata.name - operator: NotIn - values: - - kube-node-lease - - kube-public - - kube-system - - {{ include "monokle-admission-controller.namespace" . }} - {{- with .Values.ignoreNamespaces }} - {{- toYaml . | nindent 12 }} - {{- end }} - rules: - - operations: ["CREATE", "UPDATE"] - apiGroups: ["*"] - apiVersions: ["*"] - resources: ["*"] - scope: "*" \ No newline at end of file diff --git a/helm/templates/monokle-policy-binding-crd.yaml b/helm/templates/monokle-policy-binding-crd.yaml index 92a0c6b..432c63b 100644 --- a/helm/templates/monokle-policy-binding-crd.yaml +++ b/helm/templates/monokle-policy-binding-crd.yaml @@ -43,4 +43,4 @@ spec: singular: policybinding kind: MonoklePolicyBinding shortNames: - - mpb \ No newline at end of file + - mpb diff --git a/helm/templates/service-account.yaml b/helm/templates/service-account.yaml index 1999410..a94a2cc 100644 --- a/helm/templates/service-account.yaml +++ b/helm/templates/service-account.yaml @@ -10,37 +10,13 @@ metadata: kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: monokle-policies + name: monokle-policies-cluster labels: {{- include "monokle-admission-controller.labels" . | nindent 4 }} rules: - apiGroups: ["monokle.io"] resources: ["policies", "policybindings"] verbs: ["list", "watch"] ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: monokle-policies - labels: - {{- include "monokle-admission-controller.labels" . | nindent 4 }} -subjects: -- kind: ServiceAccount - name: monokle-policies-sa - namespace: {{ include "monokle-admission-controller.namespace" . }} -roleRef: - kind: ClusterRole - name: monokle-policies - apiGroup: rbac.authorization.k8s.io - ---- -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: monokle-policies-init-vwc - labels: - {{- include "monokle-admission-controller.labels" . | nindent 4 }} -rules: - apiGroups: ["admissionregistration.k8s.io"] resources: ["validatingwebhookconfigurations"] verbs: ["get", "patch"] @@ -48,7 +24,7 @@ rules: kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: monokle-policies-init-vwc + name: monokle-policies-cluster labels: {{- include "monokle-admission-controller.labels" . | nindent 4 }} subjects: @@ -57,14 +33,14 @@ subjects: namespace: {{ include "monokle-admission-controller.namespace" . }} roleRef: kind: ClusterRole - name: monokle-policies-init-vwc + name: monokle-policies-cluster apiGroup: rbac.authorization.k8s.io --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: monokle-policies-init-secrets + name: monokle-policies-namespace namespace: {{ include "monokle-admission-controller.namespace" . }} labels: {{- include "monokle-admission-controller.labels" . | nindent 4 }} @@ -76,7 +52,7 @@ rules: kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: monokle-policies-init-secrets + name: monokle-policies-namespace namespace: {{ include "monokle-admission-controller.namespace" . }} labels: {{- include "monokle-admission-controller.labels" . | nindent 4 }} @@ -86,5 +62,5 @@ subjects: namespace: {{ include "monokle-admission-controller.namespace" . }} roleRef: kind: Role - name: monokle-policies-init-secrets + name: monokle-policies-namespace apiGroup: rbac.authorization.k8s.io diff --git a/helm/templates/service.yaml b/helm/templates/service.yaml new file mode 100644 index 0000000..edbe2ed --- /dev/null +++ b/helm/templates/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: monokle-admission-controller-server + namespace: {{ include "monokle-admission-controller.namespace" . }} + labels: + {{- include "monokle-admission-controller.labels" . | nindent 4 }} +spec: + selector: + app: monokle-admission-controller-server + ports: + - port: 443 + targetPort: webhook-api diff --git a/helm/templates/webhook.yaml b/helm/templates/webhook.yaml new file mode 100644 index 0000000..62e7dd6 --- /dev/null +++ b/helm/templates/webhook.yaml @@ -0,0 +1,34 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: monokle-admission-controller-webhook + labels: + {{- include "monokle-admission-controller.labels" . | nindent 4 }} +webhooks: + - name: monokle-admission-controller-server.{{ include "monokle-admission-controller.namespace" . }}.svc + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] + clientConfig: + service: + name: monokle-admission-controller-server + namespace: {{ include "monokle-admission-controller.namespace" . }} + path: "/validate" + caBundle: "" + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: + - kube-node-lease + - kube-public + - kube-system + - {{ include "monokle-admission-controller.namespace" . }} + {{- with .Values.ignoreNamespaces }} + {{- toYaml . | nindent 12 }} + {{- end }} + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*"] + scope: "*" From 0dc0c23cfc657100c8e9879d893507ee5cbfade0 Mon Sep 17 00:00:00 2001 From: f1ames Date: Thu, 19 Oct 2023 13:47:18 +0200 Subject: [PATCH 15/17] chore: get rid of minikube uuid --- .github/workflows/test.yaml | 4 ++-- CONTRIBUTING.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 79e0f38..704cc20 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -25,7 +25,7 @@ jobs: uses: actions/checkout@v2 - name: Start Minikube - run: minikube start --uuid 00000000-0000-0000-0000-000000000001 --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook + run: minikube start --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook - name: Deploy Admission Controller run: ./scripts/deploy.sh @@ -54,7 +54,7 @@ jobs: uses: actions/checkout@v2 - name: Start Minikube - run: minikube start --uuid 00000000-0000-0000-0000-000000000001 --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook + run: minikube start --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook - name: Build local images (init container) run: eval $(minikube -p minikube docker-env) && minikube image build -t admission-webhook-init -f ./Dockerfile . diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4a8d0bd..7564fce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ Start Minikube (or any other cluster of your choice): ```bash -minikube start --uuid 00000000-0000-0000-0000-000000000001 --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook +minikube start --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook ``` ### Deploying (via Skaffold) From 979d087a8b610e9d3cc60f62a61b2abf1b3faa9b Mon Sep 17 00:00:00 2001 From: f1ames Date: Thu, 19 Oct 2023 13:47:42 +0200 Subject: [PATCH 16/17] feat: add configurable replicas to Helm chart --- helm/templates/deployment.yaml | 2 +- helm/values.yaml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml index 6721334..94e61de 100644 --- a/helm/templates/deployment.yaml +++ b/helm/templates/deployment.yaml @@ -7,7 +7,7 @@ metadata: app: monokle-admission-controller-server {{- include "monokle-admission-controller.labels" . | nindent 4 }} spec: - replicas: 1 + replicas: {{ .Values.replicas }} selector: matchLabels: app: monokle-admission-controller-server diff --git a/helm/values.yaml b/helm/values.yaml index 0197700..a2cc773 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -14,6 +14,8 @@ image: # Override entire image path. overridePath: "" +replicas: 1 + # Deploy Monokle Admission Controller resources to below namespace. namespace: monokle-admission-controller From 5e833cf6f946dcc5ad353da8434fd0fcded7cd9a Mon Sep 17 00:00:00 2001 From: f1ames Date: Thu, 19 Oct 2023 13:59:43 +0200 Subject: [PATCH 17/17] test: run tests with k8s x helm matrix strategy --- .github/workflows/test.yaml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 704cc20..208fa3e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -44,17 +44,31 @@ jobs: test-helm: name: Helm runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + k8s: [v1.25.15, v1.26.10, v1.27.7, v1.28.3] + helm: [v3.11.3, v3.12.3, v3.13.1] + steps: - name: Setup Node.js uses: actions/setup-node@v2 with: node-version: 18 + - name: Setup Helm + uses: azure/setup-helm@v3 + with: + version: ${{ matrix.helm }} + + - name: Debug helm + run: helm version + - name: Checkout Repo uses: actions/checkout@v2 - name: Start Minikube - run: minikube start --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook + run: minikube start --kubernetes-version=${{ matrix.k8s }} --extra-config=apiserver.enable-admission-plugins=ValidatingAdmissionWebhook - name: Build local images (init container) run: eval $(minikube -p minikube docker-env) && minikube image build -t admission-webhook-init -f ./Dockerfile .