From 9d160d2a541fc616f89e5454b34647a0fb16bc09 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Wed, 11 Oct 2023 22:51:52 +0300 Subject: [PATCH] support referencing an existing eks cluster --- .gitignore | 3 +- README.md | 20 +++++++++-- eks-values.sh | 15 +++++++++ package-lock.json | 72 ++++++++++++++++++---------------------- package.json | 6 ++-- sim/util.js | 18 ++++++++++ test/containers.test.w | 4 +-- test/simple.test.w | 9 +++++ test/values.test.w | 6 +++- tf-aws/eks.w | 28 +++++++++++++--- {test => tf-aws}/util.js | 18 ---------- tf-aws/values.w | 47 +++++++++++++++++++++----- tf-aws/workload.w | 2 +- values.yaml | 3 -- 14 files changed, 166 insertions(+), 85 deletions(-) create mode 100755 eks-values.sh create mode 100644 sim/util.js create mode 100644 test/simple.test.w rename {test => tf-aws}/util.js (70%) delete mode 100644 values.yaml diff --git a/.gitignore b/.gitignore index dc574e0..a4311c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ -target/ \ No newline at end of file +target/ +values.yaml diff --git a/README.md b/README.md index 2853078..668a679 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,22 @@ When executed in the Wing Simulator, the workload is started within a local Dock ### `tf-aws` -On AWS, an EKS cluster is provisioned and the workload is deployed through Helm into the Kubernetes -cluster. +By default an EKS cluster is provisioned and the workload is deployed through Helm into the +Kubernetes cluster. + +To use an existing EKS cluster, the following platform values are required: + +* `eks.cluster_name` - the name of the cluster +* `eks.endpoint` - the url of the kuberenets api endpoint of the cluster +* `eks.certificate` - the certificate authority of this cluster. + +The `eks-values.sh` script can be used to query the values for an existing cluster and create a +values file: + +```sh +$ ./eks-values.sh CLUSTER-NAME > values.yaml +$ wing compile -t tf-aws --values ./values.yaml main.w +``` ## TODO @@ -46,7 +60,7 @@ See [Captain's Log](https://winglang.slack.com/archives/C047QFSUL5R/p16968681568 - [x] EKS as a singleton - [ ] Add support for local Dockerfiles (currently only images from Docker Hub are supported), this includes publishing into an ECR. -- [ ] Reference existing EKS repository. +- [x] Reference existing EKS repository. - [ ] Use a `cloud.Redis` database - [ ] Implement `cloud.Service` using containers. - [ ] Deploy multiple workloads (maybe guestbook?) diff --git a/eks-values.sh b/eks-values.sh new file mode 100755 index 0000000..fc79a95 --- /dev/null +++ b/eks-values.sh @@ -0,0 +1,15 @@ +#!/bin/sh +if [ -z "$1" ]; then + echo "Usage: $0 " + exit 1 +fi + +export cluster_name=$1 +export cluster_endpoint=$(aws eks describe-cluster --name $cluster_name --query "cluster.endpoint") +export cluster_certificate=$(aws eks describe-cluster --name $cluster_name --query "cluster.certificateAuthority.data") + +cat << EOF +eks.cluster_name: $cluster_name +eks.endpoint: $cluster_endpoint +eks.certificate: $cluster_certificate +EOF diff --git a/package-lock.json b/package-lock.json index c1d737e..d694fe4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@cdktf/provider-kubernetes": "^9.0.0", "cdk8s-plus-27": "^2.7.33", "cdktf": "^0.18.2", - "winglang": "^0.36.1" + "winglang": "^0.37.1" } }, "node_modules/@cdktf/provider-aws": { @@ -531,14 +531,6 @@ "@octokit/openapi-types": "^12.11.0" } }, - "node_modules/@opentelemetry/api": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.6.0.tgz", - "integrity": "sha512-OWlrQAnWn9577PhVgqjUvMr1pg57Bc4jv0iL4w0PRuOSRvq67rvHW9Ie/dZVMvCzhSCB+UxhcY/PmCmFj33Q+g==", - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -549,9 +541,9 @@ } }, "node_modules/@segment/analytics-core": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@segment/analytics-core/-/analytics-core-1.3.1.tgz", - "integrity": "sha512-KGblJ8WQNC4t0j31zeyYBm2thHWuPULNAoP7waU5ts7Asz9ipvGoHqFSLG6warqvcnBdkiRbNam242zmxX53oA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@segment/analytics-core/-/analytics-core-1.3.2.tgz", + "integrity": "sha512-NpeBCfOyMdO2/BDKfhCUNHcEwxg88N2iTnswBoEMh38rtsQ03TWLVYwgiTakPjNQFezdKkR6jq3JhQ3WWgq67g==", "dependencies": { "@lukeed/uuid": "^2.0.0", "dset": "^3.1.2", @@ -559,12 +551,12 @@ } }, "node_modules/@segment/analytics-node": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@segment/analytics-node/-/analytics-node-1.1.1.tgz", - "integrity": "sha512-YNn32SfD8KrxIBowLz3MVav0GzhGIbBRgAtjW4Kv57oHwgaJNSLEp/z/ypnu7vAqUjm9jAwAW9Wfc24ssZI49g==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@segment/analytics-node/-/analytics-node-1.1.2.tgz", + "integrity": "sha512-pYQwG4/1YDxwzu97v2glfxZpwMj3A7UOKId1IdnSyDharesYawdbXpiTxBqOS3JpgP7iU4TZSiRmk7InFel/MA==", "dependencies": { "@lukeed/uuid": "^2.0.0", - "@segment/analytics-core": "1.3.1", + "@segment/analytics-core": "1.3.2", "buffer": "^6.0.3", "node-fetch": "^2.6.7", "tslib": "^2.4.1" @@ -673,22 +665,22 @@ "optional": true }, "node_modules/@wingconsole/app": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/@wingconsole/app/-/app-0.36.1.tgz", - "integrity": "sha512-zwVVGi3O/1D8T22lAju4++naSb/gdmcNW1gd/qjT4rkxC7T3BBVjpiTNgtxCvQOXJTeEiEOMvmud8McRBkby6w==", + "version": "0.37.1", + "resolved": "https://registry.npmjs.org/@wingconsole/app/-/app-0.37.1.tgz", + "integrity": "sha512-gk6IT6BziScKcILhBDB1DimnnaswLSx1aLrYIGvw6qpBwt44k1w8JULSVHgkCDl+XgVBqjINTzPWQfary/N6fg==", "dependencies": { "@segment/analytics-node": "^1.1.0", - "@wingconsole/server": "0.36.1", + "@wingconsole/server": "0.37.1", "express": "^4.18.2" } }, "node_modules/@wingconsole/server": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/@wingconsole/server/-/server-0.36.1.tgz", - "integrity": "sha512-8UdisJAjKzprDxCZQ7D0yItz3C2YZglenX9tkX5dsITWz21uW1ogoTnFn+IQke/A399Vg+pRtkTR4dXIwl4FBQ==", + "version": "0.37.1", + "resolved": "https://registry.npmjs.org/@wingconsole/server/-/server-0.37.1.tgz", + "integrity": "sha512-4IgiqriPXOXVy7FfO8XRQ7fj58jzkwmhxrfEjcx2gP1dlYYu5vW3ksv2wvEUjmvI0O0T3aa5u1MNkn8Kuj1jIw==", "dependencies": { - "@winglang/compiler": "0.36.1", - "@winglang/sdk": "0.36.1", + "@winglang/compiler": "0.37.1", + "@winglang/sdk": "0.37.1", "codespan-wasm": "^0.4.0", "debug": "^4.3.4", "launch-editor": "^2.6.0", @@ -696,14 +688,14 @@ } }, "node_modules/@winglang/compiler": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/@winglang/compiler/-/compiler-0.36.1.tgz", - "integrity": "sha512-FdYk5WK49IGM5Lamc6TkGhbsq0W//VMTfeAL0jjMA9LTxuQ7+UXad9SYCRz8khykkjL0RaU5B5+HwNYkk1BfLg==", + "version": "0.37.1", + "resolved": "https://registry.npmjs.org/@winglang/compiler/-/compiler-0.37.1.tgz", + "integrity": "sha512-vsSBmL/z0UzcDQ2JJkSWURyNUl7n2PLL7JfBbi0roYxlkkcRUYRqBwjW8hjhjZrAzEgZvcnYEneJdFc7RCp40g==", "bundleDependencies": [ "wasi-js" ], "dependencies": { - "@winglang/sdk": "0.36.1", + "@winglang/sdk": "0.37.1", "wasi-js": "^1.7.3" }, "engines": { @@ -837,9 +829,9 @@ } }, "node_modules/@winglang/sdk": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/@winglang/sdk/-/sdk-0.36.1.tgz", - "integrity": "sha512-Tal/Rlpwwec0GLg+YDHc/1VuNnZRdFsMZDUpgAckiK2nxHa28GjRC0gVrNxlUJdD2fD41xgQ6n974xmCw2BwSg==", + "version": "0.37.1", + "resolved": "https://registry.npmjs.org/@winglang/sdk/-/sdk-0.37.1.tgz", + "integrity": "sha512-8Y6oXRZe6yTsn6pKq0sAw/r04Roj1s2BJp3MFKlOg63rF2fHSGe1PaDqs6xeUX+ksqoZ293qD9lRQ2YuEw3puw==", "bundleDependencies": [ "@aws-sdk/client-cloudwatch-logs", "@aws-sdk/client-dynamodb", @@ -8708,7 +8700,6 @@ "version": "2.4.3", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "optional": true, "engines": { "node": ">=10" } @@ -9534,21 +9525,22 @@ } }, "node_modules/winglang": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/winglang/-/winglang-0.36.1.tgz", - "integrity": "sha512-b1Bk+vYgzlrhud7FK4AgJLBwmwhVnvMZCVcfBXrMvCL20qV/caBgwRUrIZya8//3RDJIUFXmmbNf+Fy5Xt+Rog==", + "version": "0.37.1", + "resolved": "https://registry.npmjs.org/winglang/-/winglang-0.37.1.tgz", + "integrity": "sha512-WZBLqlHIhCQJtEobYJEGbqhVGT9n07TcGPbfNHxNGeIPQMcZ17AaIQYSR1Pk1cLPwrOzeAAzo1cBUxU1jFIUNg==", "dependencies": { "@npmcli/arborist": "^7.2.0", "@segment/analytics-node": "^1.1.0", - "@wingconsole/app": "0.36.1", - "@wingconsole/server": "0.36.1", - "@winglang/compiler": "0.36.1", - "@winglang/sdk": "0.36.1", + "@wingconsole/app": "0.37.1", + "@wingconsole/server": "0.37.1", + "@winglang/compiler": "0.37.1", + "@winglang/sdk": "0.37.1", "chalk": "^4.1.2", "codespan-wasm": "0.4.0", "commander": "^10.0.1", "compare-versions": "^5.0.3", "debug": "^4.3.4", + "glob": "^10.3.10", "minimatch": "^9.0.3", "nanoid": "^3.3.6", "npm-packlist": "^8.0.0", diff --git a/package.json b/package.json index 7985cfe..38eb373 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "wing-containers", "version": "1.0.0", - "description": "", + "description": "A containers library for Wing", "main": "index.js", "scripts": { - "build": "wing test test/containers.test.w" + "build": "wing test test/*.test.w" }, "author": { "email": "eladb@wing.cloud", @@ -17,6 +17,6 @@ "@cdktf/provider-kubernetes": "^9.0.0", "cdk8s-plus-27": "^2.7.33", "cdktf": "^0.18.2", - "winglang": "^0.36.1" + "winglang": "^0.37.1" } } diff --git a/sim/util.js b/sim/util.js new file mode 100644 index 0000000..64b8216 --- /dev/null +++ b/sim/util.js @@ -0,0 +1,18 @@ +const child_process = require("child_process"); + +exports.shell = async function (command, args, cwd) { + return new Promise((resolve, reject) => { + child_process.execFile(command, args, { cwd }, (error, stdout, stderr) => { + if (error) { + console.error(stderr); + return reject(error); + } + + return resolve(stdout ? stdout : stderr); + }); + }); +}; + +exports.entrypointDir = function (scope) { + return scope.node.root.entrypointDir; +}; diff --git a/test/containers.test.w b/test/containers.test.w index f62c9bc..79b07b4 100644 --- a/test/containers.test.w +++ b/test/containers.test.w @@ -7,7 +7,7 @@ let hello = new containers.Workload( image: "paulbouwer/hello-kubernetes:1", port: 8080, readiness: "/", - replicas: 3, + replicas: 2, env: { "MESSAGE" => message, }, @@ -18,7 +18,7 @@ new containers.Workload( image: "hashicorp/http-echo", port: 5678, public: true, - replicas: 20, + replicas: 2, args: ["-text=hello1234"], ) as "http-echo"; diff --git a/test/simple.test.w b/test/simple.test.w new file mode 100644 index 0000000..88643cb --- /dev/null +++ b/test/simple.test.w @@ -0,0 +1,9 @@ +bring "../containers.w" as containers; + +new containers.Workload( + image: "hashicorp/http-echo", + port: 5678, + public: true, + replicas: 2, + args: ["-text=bang_bang"], +); diff --git a/test/values.test.w b/test/values.test.w index e5332ac..d05e935 100644 --- a/test/values.test.w +++ b/test/values.test.w @@ -1,2 +1,6 @@ bring "../tf-aws/values.w" as values; -values.get("foo"); +bring util; + +if let x = values.tryGet("foo") { + log(x); +} \ No newline at end of file diff --git a/tf-aws/eks.w b/tf-aws/eks.w index f1c2e45..4273d49 100644 --- a/tf-aws/eks.w +++ b/tf-aws/eks.w @@ -56,12 +56,32 @@ class Cluster impl ICluster { /** singleton */ pub static getOrCreate(scope: std.IResource): ICluster { - // values.get("foo"); - let stack = cdktf.TerraformStack.of(scope); let uid = "WingEksCluster"; - let existing: Cluster? = unsafeCast(stack.node.tryFindChild(uid)); - return existing ?? new Cluster() as uid in stack; + let existing: ICluster? = unsafeCast(stack.node.tryFindChild(uid)); + + let newCluster = (): ICluster => { + if let attrs = Cluster.tryGetClusterAttributes() { + return new ClusterRef(attrs) as uid in stack; + } else { + return new Cluster() as uid in stack; + } + }; + + return existing ?? newCluster(); + } + + static tryGetClusterAttributes(): ClusterAttributes? { + if !values.has("eks.cluster_name") { + return nil; + } + + return ClusterAttributes { + name: values.get("eks.cluster_name"), + certificate: values.get("eks.certificate"), + endpoint: values.get("eks.endpoint"), + }; + } _attributes: ClusterAttributes; diff --git a/test/util.js b/tf-aws/util.js similarity index 70% rename from test/util.js rename to tf-aws/util.js index c51e064..c357324 100644 --- a/test/util.js +++ b/tf-aws/util.js @@ -1,27 +1,9 @@ -const child_process = require("child_process"); const cdk8s = require('cdk8s'); const fs = require('fs'); const path = require('path'); const wingsdk = require('@winglang/sdk'); const crypto = require('crypto'); -exports.shell = async function (command, args, cwd) { - return new Promise((resolve, reject) => { - child_process.execFile(command, args, { cwd }, (error, stdout, stderr) => { - if (error) { - console.error(stderr); - return reject(error); - } - - return resolve(stdout ? stdout : stderr); - }); - }); -}; - -exports.entrypointDir = function (scope) { - return scope.node.root.entrypointDir; -}; - exports.toHelmChart = function(chart) { const app = cdk8s.App.of(chart); const wingdir = wingsdk.core.App.of(chart).workdir; diff --git a/tf-aws/values.w b/tf-aws/values.w index 764f84e..7f893db 100644 --- a/tf-aws/values.w +++ b/tf-aws/values.w @@ -2,20 +2,49 @@ bring "cdk8s" as values_cdk8s; bring util; class Util { - pub static get(key: str): str { + pub static all(): Map { + let all = MutMap{}; + if let valuesFile = util.tryEnv("WING_VALUES_FILE") { - let yaml = values_cdk8s.Yaml.load(valuesFile); - log("values file: ${yaml}"); + if valuesFile != "undefined" { // bug + let yaml = values_cdk8s.Yaml.load(valuesFile); + for x in yaml { + let y: Json = x; + + for entry in Json.entries(y) { + all.set(entry.key, entry.value.asStr()); + } + } + } } if let values = util.tryEnv("WING_VALUES") { - for v in values.split(",") { - let kv = v.split("="); - let key = kv.at(0); - let value = kv.at(1); - log("${key} is ${value}"); - + if values != "undefined" { + for v in values.split(",") { + let kv = v.split("="); + let key = kv.at(0); + let value = kv.at(1); + all.set(key, value); + } } } + + return all.copy(); + } + + pub static tryGet(key: str): str? { + return Util.all().get(key); + } + + pub static has(key: str): bool { + return Util.tryGet(key)?; + } + + pub static get(key: str): str { + if let value = Util.tryGet(key) { + return value; + } else { + throw "Missing platform value '${key}' (use --values or -v)"; + } } } \ No newline at end of file diff --git a/tf-aws/workload.w b/tf-aws/workload.w index 202a2c8..14baf2e 100644 --- a/tf-aws/workload.w +++ b/tf-aws/workload.w @@ -6,7 +6,7 @@ bring "cdktf" as cdktf3; class Workload impl api.IWorkload { init(props: api.WorkloadProps) { - let name = "${this.node.id.replace(".", "-")}-${this.node.addr.substring(0, 6)}"; + let name = "${this.node.id.replace(".", "-").substring(0, 40).lowercase()}-${this.node.addr.substring(0, 6)}"; let cluster = eks.Cluster.getOrCreate(this); let chart = new _Chart(name, props); let helmDir = chart.toHelm(); diff --git a/values.yaml b/values.yaml deleted file mode 100644 index 90a92e8..0000000 --- a/values.yaml +++ /dev/null @@ -1,3 +0,0 @@ -eks.cluster_name: wing-eks-c8c841 -eks.endpoint: https://920B303C8D687B733083913C0DAEED2E.gr7.eu-west-2.eks.amazonaws.com -eks.certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJWHA5QllvbjZ2TGt3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TXpFd01Ea3lNVFE0TXpCYUZ3MHpNekV3TURZeU1UUTRNekJhTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUURUUVIvSXhUclhZK2E3UCtONXNLK3RoWDFoNmhua3F3Q3d3KzJTZHFxOFhpNXBCQk8xa0lDLzRlTmEKUWo1Nnp1NVVVdVZhcm9MM2ZWMmxFdVNhZ0l6TFZDbUFFSUs5U2pCSnVHeExEK3hZRExPZEtobFp5VlRYZGpiZwpZS0tHcWlVSjJqd05qVU9idURsUzZCaXFRT0V2UWNESmRTUzAxeTZsOXh2ZjdMZmxLNnk4c25DWnBYOVRZY2JWCm9TSS9NZ3lIN0ZwYytFV2tKWEVPK2JzWU52ekpJeVJSMkZONjhISDRJWU9mcDg0RDYrY3RVU1A3YlBtdmx4NzcKRDNWUytoWUg1ZldXbVFXemw5WWlRODJ4RHNVb0dJcmYzTCtWQjJwc1lRbzhucGcvdFlzM1VqZkZWeFVwTUJnNApVQVU3cnBnT0doS1B5ZzVZS1pGVE4yZEI4Qi81QWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJTN1QvUW45VHAwdDNNL3k1a0hIaXFKcjhHWWlEQVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQnlLL0FNWU53egoybVpGd1p3NnVQQWxocDFEL1krT2FwYnQ1b3RFdS8wSEZvckZ3STMvcldSVjRzSlMxZndWN3ZIdmdwQ0dwRkZ3ClpWc0tNVnNHSXA1NUJ5TVFmbnFxZ1l1Mk9xOFpZd05QOHI5RWxsRHBIWFYzYzlzOFFaYjlZUDc0RzNBTU1vR1UKNmlocGcrMkNINDFOVTREZWpENDZtakd2TWdmajA2OUMzRWJybUNMLzBkTVZ5TUs4SVgvaWo1Q1RXRjlkSUg5TwpHK2hTaWlRSWJTVTFQWm5EOWNJSTZIM01SWnFjSmdGcGFWRFVKK3FHNW5aZVlEZm9MQWNwOHdxN2FVZHpPUjQyClF6a0RyM1ZjTmZleDRCbmlETU9NNWdXYy84NG9nM21IYUhxTURIOEIraDJHbFFTLzk1RFZRd2o4dnJIMU43aDIKZml3ZGZxMkVyNVpzCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K