From a8286e6e30d1502112e6edd4c8ffb307689cd4c5 Mon Sep 17 00:00:00 2001 From: David Morrison Date: Sat, 15 Jun 2024 15:11:07 -0700 Subject: [PATCH 1/4] release make target --- Cargo.toml | 2 +- Makefile | 11 +++++++++++ cli/run.rs | 4 ++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2a328c7a..e0ca53b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ anyhow = { version = "1.0.75", features = ["backtrace"] } async-recursion = "1.0.5" bytes = "1.5.0" chrono = "0.4.26" -clap = { version = "4.3.21", features = ["cargo", "derive"] } +clap = { version = "4.3.21", features = ["cargo", "derive", "string"] } either = "1.12.0" futures = "0.3.28" json-patch = "1.2.0" diff --git a/Makefile b/Makefile index dbe42b5d..83d40438 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,17 @@ cover: --excl-start '#\[cfg\((test|feature = "testutils")' @if [ "$(RUST_COVER_TYPE)" = "markdown" ]; then cat $(RUST_COVER_FILE); fi +.PHONY: release-patch release-minor release-major +release-patch release-minor release-major: + make _release -e VERSION=$(subst release-,,$@) + +.PHONY: _release +_release: + cargo set-version --bump $(VERSION) + VERSION=`cargo read-manifest | jq -r .version` && \ + git commit -a -m "Release version v$$VERSION" && \ + git tag v$$VERSION + .PHONY: crd crd: skctl $(BUILD_DIR)/skctl crd > k8s/raw/simkube.io_simulations.yml diff --git a/cli/run.rs b/cli/run.rs index e6cd5a51..4fa98878 100644 --- a/cli/run.rs +++ b/cli/run.rs @@ -1,5 +1,6 @@ use std::fs; +use clap::crate_version; use simkube::api::v1::{ SimulationDriverConfig, SimulationHooksConfig, @@ -7,6 +8,8 @@ use simkube::api::v1::{ use simkube::metrics::api::prometheus::PrometheusRemoteWrite; use simkube::prelude::*; +const DRIVER_IMAGE: &str = "quay.io/appliedcomputing/sk-driver"; + #[derive(clap::Args)] #[command(disable_help_flag = true, disable_version_flag = true)] pub struct Args { @@ -33,6 +36,7 @@ pub struct Args { short = 'I', long, long_help = "name of the docker image to use for sk-driver", + default_value = format!("{DRIVER_IMAGE}:v{}", crate_version!()), help_heading = "Driver" )] pub driver_image: String, From 6be61701d1d55a1ba3cd1caae8ad9b358bf6496f Mon Sep 17 00:00:00 2001 From: David Morrison Date: Mon, 17 Jun 2024 12:43:20 -0700 Subject: [PATCH 2/4] add kustomize output --- .pre-commit-config.yaml | 24 +- .yamllint | 1 + Makefile | 17 +- README.md | 4 + build | 2 +- k8s/kustomize/0000-global.k8s.yaml | 4 + k8s/kustomize/0001-sk-tracer.k8s.yaml | 89 ++++ k8s/kustomize/0002-sk-ctrl.k8s.yaml | 60 +++ k8s/kustomize/kustomization.yml | 9 + k8s/kustomize/simkube.io_simulations.yml | 636 +++++++++++++++++++++++ k8s/main.py | 90 +++- k8s/poetry.lock | 19 +- k8s/pyproject.toml | 2 +- k8s/sk_ctrl.py | 39 +- k8s/sk_tracer.py | 55 +- k8s/test_deployment.py | 24 - 16 files changed, 957 insertions(+), 118 deletions(-) create mode 100644 k8s/kustomize/0000-global.k8s.yaml create mode 100644 k8s/kustomize/0001-sk-tracer.k8s.yaml create mode 100644 k8s/kustomize/0002-sk-ctrl.k8s.yaml create mode 100644 k8s/kustomize/kustomization.yml create mode 100644 k8s/kustomize/simkube.io_simulations.yml delete mode 100644 k8s/test_deployment.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 98fd4a1f..8435675c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,21 +29,21 @@ repos: - id: fmt name: rust-fmt args: ['--', '--unstable-features'] - - repo: https://github.com/pycqa/isort - rev: 5.13.2 + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.4.1 hooks: - - id: isort - args: - - --sl - - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 + - id: mypy + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.4.2 hooks: - - id: flake8 + - id: ruff + args: ["--fix"] + - id: ruff-format - repo: local hooks: - - id: check-crds - name: Check Generated CRDs + - id: check-k8s + name: Check Generated K8s YAML language: system - entry: bash -c 'make crd && git diff --quiet' + entry: bash -c 'make kustomize && git diff --quiet' pass_filenames: false - files: 'lib/api/v1/.*' + files: 'lib/api/v1/.*|k8s/.*|Cargo.toml' diff --git a/.yamllint b/.yamllint index 7e085f62..635176be 100644 --- a/.yamllint +++ b/.yamllint @@ -4,6 +4,7 @@ extends: default ignore: - examples/metrics - k8s/raw/simkube.io_simulations.yml + - k8s/kustomize rules: line-length: diff --git a/Makefile b/Makefile index 83d40438..6ca2bd9b 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,8 @@ DOCKER_ARGS=-it --init endif RUST_COVER_FILE=$(COVERAGE_DIR)/rust-coverage.$(RUST_COVER_TYPE) +APP_VERSION_CMD=cargo read-manifest | jq -r .version +APP_VERSION=$(shell $(APP_VERSION_CMD)) include build/base.mk include build/k8s.mk @@ -67,19 +69,18 @@ cover: .PHONY: release-patch release-minor release-major release-patch release-minor release-major: - make _release -e VERSION=$(subst release-,,$@) - -.PHONY: _release -_release: - cargo set-version --bump $(VERSION) - VERSION=`cargo read-manifest | jq -r .version` && \ - git commit -a -m "Release version v$$VERSION" && \ - git tag v$$VERSION + cargo set-version --bump $(subst release-,,$@) + make kustomize + NEW_APP_VERSION=`$(APP_VERSION_CMD)` && \ + git commit -a -m "Release version v$$NEW_APP_VERSION" && \ + git tag v$$NEW_APP_VERSION .PHONY: crd crd: skctl $(BUILD_DIR)/skctl crd > k8s/raw/simkube.io_simulations.yml +pre-k8s:: crd + .PHONY: api api: openapi-generator generate -i api/v1/simkube.yml -g rust --global-property models -o generated-api diff --git a/README.md b/README.md index 4493174d..b6b32099 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,10 @@ This package provides the following components: [![Watch the video](https://img.youtube.com/vi/Q1XpH1H4It8/hqdefault.jpg)](https://www.youtube.com/watch?v=Q1XpH1H4It8) +## Installation + +`kubectl apply -k k8s/kustomize` + ## Documentation Full [documentation for SimKube](https://appliedcomputing.io/simkube/index.html) is available on Applied diff --git a/build b/build index d54c1059..474efc36 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit d54c1059af1ffad7234eb9d8912070ec7aa98358 +Subproject commit 474efc360d8015eadc22d3b3a3c00ee32ac26b43 diff --git a/k8s/kustomize/0000-global.k8s.yaml b/k8s/kustomize/0000-global.k8s.yaml new file mode 100644 index 00000000..1e279119 --- /dev/null +++ b/k8s/kustomize/0000-global.k8s.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: simkube diff --git a/k8s/kustomize/0001-sk-tracer.k8s.yaml b/k8s/kustomize/0001-sk-tracer.k8s.yaml new file mode 100644 index 00000000..739522df --- /dev/null +++ b/k8s/kustomize/0001-sk-tracer.k8s.yaml @@ -0,0 +1,89 @@ +apiVersion: v1 +kind: Service +metadata: + name: sk-tracer-svc + namespace: simkube +spec: + ports: + - port: 7777 + targetPort: 7777 + selector: + app.kubernetes.io/name: sk-tracer +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sk-tracer-sa + namespace: simkube +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: sk-tracer-crb +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: sk-tracer-sa + namespace: simkube +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: sk-tracer-tracer-config + namespace: simkube +data: + tracer-config.yml: | + --- + trackedObjects: + apps/v1.Deployment: + podSpecTemplatePath: /spec/template +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: sk-tracer + name: sk-tracer-depl + namespace: simkube +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: sk-tracer + template: + metadata: + labels: + app.kubernetes.io/name: sk-tracer + spec: + containers: + - args: + - /sk-tracer + - --server-port + - "7777" + - -c + - /config/tracer-config.yml + env: + - name: RUST_BACKTRACE + value: "1" + - name: POD_OWNER + value: sk-tracer-depl + image: quay.io/appliedcomputing/sk-tracer:v0.10.0 + name: sk-tracer + ports: + - containerPort: 7777 + volumeMounts: + - mountPath: /config + name: tracer-config + nodeSelector: + type: kind-worker + serviceAccountName: sk-tracer-sa + volumes: + - configMap: + items: + - key: tracer-config.yml + path: tracer-config.yml + name: sk-tracer-tracer-config + name: tracer-config diff --git a/k8s/kustomize/0002-sk-ctrl.k8s.yaml b/k8s/kustomize/0002-sk-ctrl.k8s.yaml new file mode 100644 index 00000000..bda05f90 --- /dev/null +++ b/k8s/kustomize/0002-sk-ctrl.k8s.yaml @@ -0,0 +1,60 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sk-ctrl-sa + namespace: simkube +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: sk-ctrl-crb +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: sk-ctrl-sa + namespace: simkube +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: sk-ctrl + name: sk-ctrl-depl + namespace: simkube +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: sk-ctrl + template: + metadata: + labels: + app.kubernetes.io/name: sk-ctrl + spec: + containers: + - args: + - /sk-ctrl + - --use-cert-manager + - --cert-manager-issuer + - selfsigned + env: + - name: RUST_BACKTRACE + value: "1" + - name: POD_SVC_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: CTRL_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_OWNER + value: sk-ctrl-depl + image: quay.io/appliedcomputing/sk-ctrl:v0.10.0 + name: sk-ctrl + nodeSelector: + type: kind-worker + serviceAccountName: sk-ctrl-sa diff --git a/k8s/kustomize/kustomization.yml b/k8s/kustomize/kustomization.yml new file mode 100644 index 00000000..ccb8d707 --- /dev/null +++ b/k8s/kustomize/kustomization.yml @@ -0,0 +1,9 @@ + +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - simkube.io_simulations.yml + - 0000-global.k8s.yaml + - 0001-sk-tracer.k8s.yaml + - 0002-sk-ctrl.k8s.yaml diff --git a/k8s/kustomize/simkube.io_simulations.yml b/k8s/kustomize/simkube.io_simulations.yml new file mode 100644 index 00000000..9cba8d85 --- /dev/null +++ b/k8s/kustomize/simkube.io_simulations.yml @@ -0,0 +1,636 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: simulations.simkube.io +spec: + group: simkube.io + names: + categories: [] + kind: Simulation + plural: simulations + shortNames: + - sim + - sims + singular: simulation + scope: Cluster + versions: + - additionalPrinterColumns: + - description: simulation driver start time + jsonPath: .status.startTime + name: start time + type: string + - description: simulation driver end time + jsonPath: .status.endTime + name: end time + type: string + - description: simulation state + jsonPath: .status.state + name: state + type: string + name: v1 + schema: + openAPIV3Schema: + description: Auto-generated derived type for SimulationSpec via `CustomResource` + properties: + spec: + properties: + driver: + properties: + image: + type: string + namespace: + type: string + port: + format: int32 + type: integer + tracePath: + type: string + required: + - image + - namespace + - port + - tracePath + type: object + duration: + nullable: true + type: string + hooks: + nullable: true + properties: + postRunHooks: + items: + properties: + args: + items: + type: string + type: array + cmd: + type: string + ignoreFailure: + nullable: true + type: boolean + sendSim: + nullable: true + type: boolean + required: + - args + - cmd + type: object + nullable: true + type: array + postStopHooks: + items: + properties: + args: + items: + type: string + type: array + cmd: + type: string + ignoreFailure: + nullable: true + type: boolean + sendSim: + nullable: true + type: boolean + required: + - args + - cmd + type: object + nullable: true + type: array + preRunHooks: + items: + properties: + args: + items: + type: string + type: array + cmd: + type: string + ignoreFailure: + nullable: true + type: boolean + sendSim: + nullable: true + type: boolean + required: + - args + - cmd + type: object + nullable: true + type: array + preStartHooks: + items: + properties: + args: + items: + type: string + type: array + cmd: + type: string + ignoreFailure: + nullable: true + type: boolean + sendSim: + nullable: true + type: boolean + required: + - args + - cmd + type: object + nullable: true + type: array + type: object + metrics: + nullable: true + properties: + namespace: + nullable: true + type: string + podMonitorNames: + items: + type: string + nullable: true + type: array + podMonitorNamespaces: + items: + type: string + nullable: true + type: array + prometheusShards: + format: int32 + nullable: true + type: integer + remoteWriteConfigs: + items: + properties: + authorization: + nullable: true + properties: + credentials: + nullable: true + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + credentialsFile: + nullable: true + type: string + type: + nullable: true + type: string + type: object + basicAuth: + nullable: true + properties: + password: + nullable: true + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + username: + nullable: true + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + type: object + bearerToken: + nullable: true + type: string + bearerTokenFile: + nullable: true + type: string + headers: + additionalProperties: + type: string + nullable: true + type: object + metadataConfig: + nullable: true + properties: + send: + nullable: true + type: boolean + sendInterval: + nullable: true + type: string + type: object + name: + nullable: true + type: string + oauth2: + nullable: true + properties: + clientId: + properties: + configMap: + nullable: true + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + secret: + nullable: true + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + type: object + clientSecret: + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + endpointParams: + additionalProperties: + type: string + nullable: true + type: object + scopes: + items: + type: string + nullable: true + type: array + tokenUrl: + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyUrl: + nullable: true + type: string + queueConfig: + nullable: true + properties: + batchSendDeadline: + nullable: true + type: string + capacity: + format: int64 + nullable: true + type: integer + maxBackoff: + nullable: true + type: string + maxRetries: + format: int64 + nullable: true + type: integer + maxSamplesPerSend: + format: int64 + nullable: true + type: integer + maxShards: + format: int64 + nullable: true + type: integer + minBackoff: + nullable: true + type: string + minShards: + format: int64 + nullable: true + type: integer + retryOnRateLimit: + nullable: true + type: boolean + type: object + remoteTimeout: + nullable: true + type: string + sendExemplars: + nullable: true + type: boolean + sendNativeHistograms: + nullable: true + type: boolean + sigv4: + nullable: true + properties: + accessKey: + nullable: true + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + profile: + nullable: true + type: string + region: + nullable: true + type: string + roleArn: + nullable: true + type: string + secretKey: + nullable: true + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + type: object + tlsConfig: + nullable: true + properties: + ca: + nullable: true + properties: + configMap: + nullable: true + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + secret: + nullable: true + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + type: object + caFile: + nullable: true + type: string + cert: + nullable: true + properties: + configMap: + nullable: true + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + secret: + nullable: true + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + type: object + certFile: + nullable: true + type: string + insecureSkipVerify: + nullable: true + type: boolean + keyFile: + nullable: true + type: string + keySecret: + nullable: true + properties: + key: + type: string + name: + nullable: true + type: string + optional: + nullable: true + type: boolean + required: + - key + type: object + serverName: + nullable: true + type: string + type: object + url: + type: string + writeRelabelConfigs: + items: + properties: + action: + enum: + - replace + - keep + - drop + - hashmod + - labelmap + - labeldrop + - labelkeep + - lowercase + - uppercase + - keepequal + - dropequal + nullable: true + type: string + modulus: + format: int64 + nullable: true + type: integer + regex: + nullable: true + type: string + replacement: + nullable: true + type: string + separator: + nullable: true + type: string + sourceLabels: + items: + type: string + nullable: true + type: array + targetLabel: + nullable: true + type: string + type: object + nullable: true + type: array + required: + - url + type: object + type: array + serviceAccount: + nullable: true + type: string + serviceMonitorNames: + items: + type: string + nullable: true + type: array + serviceMonitorNamespaces: + items: + type: string + nullable: true + type: array + required: + - remoteWriteConfigs + type: object + repetitions: + format: int32 + nullable: true + type: integer + required: + - driver + type: object + status: + nullable: true + properties: + endTime: + format: date-time + nullable: true + type: string + observedGeneration: + format: int64 + type: integer + startTime: + format: date-time + nullable: true + type: string + state: + enum: + - Blocked + - Initializing + - Finished + - Failed + - Retrying + - Running + nullable: true + type: string + required: + - observedGeneration + type: object + required: + - spec + title: Simulation + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: simulationroots.simkube.io +spec: + group: simkube.io + names: + categories: [] + kind: SimulationRoot + plural: simulationroots + shortNames: + - simroot + - simroots + singular: simulationroot + scope: Cluster + versions: + - additionalPrinterColumns: [] + name: v1 + schema: + openAPIV3Schema: + description: Auto-generated derived type for SimulationRootSpec via `CustomResource` + properties: + spec: + type: object + required: + - spec + title: SimulationRoot + type: object + served: true + storage: true + subresources: {} diff --git a/k8s/main.py b/k8s/main.py index 715e5a2a..4b8a2f49 100755 --- a/k8s/main.py +++ b/k8s/main.py @@ -1,28 +1,82 @@ #!/usr/bin/env python import os +import argparse +import typing as T import fireconfig as fire -from sk_ctrl import SKController -from sk_tracer import SKTracer -from test_deployment import TestDeployment +from sk_ctrl import SkCtrl +from sk_tracer import SkTracer DAG_FILENAME = "dag.mermaid" DIFF_FILENAME = "k8s.df" +KUSTOMIZATION_YML = """ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - simkube.io_simulations.yml + - 0000-global.k8s.yaml + - 0001-sk-tracer.k8s.yaml + - 0002-sk-ctrl.k8s.yaml +""" +QUAY_IO_PREFIX = "quay.io/appliedcomputing" + + +def setup_args() -> argparse.Namespace: + root_parser = argparse.ArgumentParser(prog="k8sgen") + root_parser.add_argument( + "--kustomize", + action="store_true", + ) + return root_parser.parse_args() + + +def get_images(to_build: T.List, kustomize: bool, build_dir: str) -> T.List[str]: + if kustomize: + return [ + f"{QUAY_IO_PREFIX}/{app.id()}:v{os.getenv('APP_VERSION')}" + for app in to_build + ] + + images = [] + for app in to_build: + try: + with open(build_dir + f"/{app.id()}-image") as f: + image = f.read() + except FileNotFoundError: + image = "PLACEHOLDER" + images.append(image) + + return images + + +def main(): + args = setup_args() + debug = not args.kustomize + + build_dir = os.getenv("BUILD_DIR") + dag_path = None if args.kustomize else f"{build_dir}/{DAG_FILENAME}" + diff_path = f"{build_dir}/{DIFF_FILENAME}" + kustomization_path = f"{build_dir}/kustomization.yml" + + apps = [SkTracer, SkCtrl] + images = get_images(apps, args.kustomize, build_dir) + + graph, diff = fire.compile( + {"simkube": [app(image, debug) for app, image in zip(apps, images)]}, + dag_path, + ) + + if args.kustomize: + with open(kustomization_path, "w") as f: + f.write(KUSTOMIZATION_YML) + else: + with open(dag_path, "w") as f: + f.write(graph) + + with open(diff_path, "w") as f: + f.write(diff) if __name__ == "__main__": - dag_path = f"{os.getenv('BUILD_DIR')}/{DAG_FILENAME}" - diff_path = f"{os.getenv('BUILD_DIR')}/{DIFF_FILENAME}" - graph, diff = fire.compile({ - "simkube": [ - SKTracer(), - SKController(), - TestDeployment(), - ], - }, dag_path) - - with open(dag_path, "w") as f: - f.write(graph) - - with open(diff_path, "w") as f: - f.write(diff) + main() diff --git a/k8s/poetry.lock b/k8s/poetry.lock index 2ebdfe31..744131d6 100644 --- a/k8s/poetry.lock +++ b/k8s/poetry.lock @@ -95,7 +95,7 @@ optimize = ["orjson"] [[package]] name = "fireconfig" -version = "0.5.1" +version = "0.5.3" description = "Configuration language for Kubernetes manifests" optional = false python-versions = "^3.10" @@ -107,12 +107,13 @@ cdk8s = "^2.68" deepdiff = "^6.7.1" pyyaml = "^6.0.1" simplejson = "^3.19.2" +stringcase = "^1.2.0" [package.source] type = "git" url = "https://github.com/acrlabs/fireconfig" -reference = "v0.5.2" -resolved_reference = "7f45b24a0159d2ef67691cc62db12f9da139cc1e" +reference = "v0.5.3" +resolved_reference = "7b9ca82a2b8e8016768ae42ddcd151d472d398af" [[package]] name = "importlib-resources" @@ -412,6 +413,16 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "stringcase" +version = "1.2.0" +description = "String case converter." +optional = false +python-versions = "*" +files = [ + {file = "stringcase-1.2.0.tar.gz", hash = "sha256:48a06980661908efe8d9d34eab2b6c13aefa2163b3ced26972902e3bdfd87008"}, +] + [[package]] name = "typeguard" version = "2.13.3" @@ -441,4 +452,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "6e66b5e150fd4dfe3b04edeb40a80ac08f1f128ada4714332137d06a0c812346" +content-hash = "8e32d1979a4e8cf288b0496ecbc5c96e45695ef9dfc80920ceaf4d32d174c479" diff --git a/k8s/pyproject.toml b/k8s/pyproject.toml index b7784c0c..512808ba 100644 --- a/k8s/pyproject.toml +++ b/k8s/pyproject.toml @@ -5,7 +5,7 @@ package-mode = false [tool.poetry.dependencies] python = "^3.11" cdk8s = "^2" -fireconfig = { git = "https://github.com/acrlabs/fireconfig", tag = "v0.5.2" } +fireconfig = { git = "https://github.com/acrlabs/fireconfig", tag = "v0.5.3" } [tool.poetry.group.dev.dependencies] mypy = "^1" diff --git a/k8s/sk_ctrl.py b/k8s/sk_ctrl.py index 2429704f..983cc9d0 100644 --- a/k8s/sk_ctrl.py +++ b/k8s/sk_ctrl.py @@ -1,5 +1,3 @@ -import os - import fireconfig as fire from constructs import Construct from fireconfig.types import Capability @@ -10,38 +8,35 @@ CTRL_NS_ENV_VAR = "CTRL_NAMESPACE" -class SKController(fire.AppPackage): - def __init__(self): - env = (fire.EnvBuilder({"RUST_BACKTRACE": "1"}) - .with_field_ref(POD_SVC_ACCOUNT_ENV_VAR, DownwardAPIField.SERVICE_ACCOUNT_NAME) +class SkCtrl(fire.AppPackage): + def __init__(self, image: str, debug: bool): + env = ( + fire.EnvBuilder({"RUST_BACKTRACE": "1"}) + .with_field_ref( + POD_SVC_ACCOUNT_ENV_VAR, DownwardAPIField.SERVICE_ACCOUNT_NAME + ) .with_field_ref(CTRL_NS_ENV_VAR, DownwardAPIField.NAMESPACE) ) - try: - with open(os.getenv('BUILD_DIR') + f'/{self.id}-image') as f: - image = f.read() - except FileNotFoundError: - image = 'PLACEHOLDER' - container = fire.ContainerBuilder( - name=self.id, + name=self.id(), image=image, args=[ "/sk-ctrl", "--use-cert-manager", - "--cert-manager-issuer", "selfsigned", + "--cert-manager-issuer", + "selfsigned", ], - ).with_security_context(Capability.DEBUG).with_env(env) + ).with_env(env) + if debug: + container = container.with_security_context(Capability.DEBUG) - self._depl = (fire.DeploymentBuilder(app_label=self.id) - .with_service_account_and_role_binding('cluster-admin', True) + self._depl = ( + fire.DeploymentBuilder(app_label=self.id()) + .with_service_account_and_role_binding("cluster-admin", True) .with_containers(container) .with_node_selector("type", "kind-worker") ) def compile(self, chart: Construct): - self._depl.build(chart) - - @property - def id(self) -> str: - return "sk-ctrl" + self._depl.build(chart) # type: ignore diff --git a/k8s/sk_tracer.py b/k8s/sk_tracer.py index d744875e..7a1193c2 100644 --- a/k8s/sk_tracer.py +++ b/k8s/sk_tracer.py @@ -1,7 +1,6 @@ -import os - import fireconfig as fire from constructs import Construct +from fireconfig.types import Capability SERVER_PORT = 7777 TRACER_CONFIG_PATH = "tracer-config.yml" @@ -13,39 +12,39 @@ CONFIGMAP_NAME = "tracer-config" -class SKTracer(fire.AppPackage): - def __init__(self): +class SkTracer(fire.AppPackage): + def __init__(self, image: str, debug: bool): env = fire.EnvBuilder({"RUST_BACKTRACE": "1"}) - volumes = (fire.VolumesBuilder() - .with_config_map(CONFIGMAP_NAME, "/config", {TRACER_CONFIG_PATH: TRACER_CONFIG_YML}) + volumes = fire.VolumesBuilder().with_config_map( + CONFIGMAP_NAME, "/config", {TRACER_CONFIG_PATH: TRACER_CONFIG_YML} ) - try: - with open(os.getenv('BUILD_DIR') + f'/{self.id}-image') as f: - image = f.read() - except FileNotFoundError: - image = 'PLACEHOLDER' - - container = fire.ContainerBuilder( - name=self.id, - image=image, - args=[ - "/sk-tracer", - "--server-port", f"{SERVER_PORT}", - "-c", volumes.get_path_to_config_map(CONFIGMAP_NAME, TRACER_CONFIG_PATH), - ], - ).with_ports(SERVER_PORT).with_volumes(volumes).with_env(env) + container = ( + fire.ContainerBuilder( + name=self.id(), + image=image, + args=[ + "/sk-tracer", + "--server-port", + f"{SERVER_PORT}", + "-c", + volumes.get_path_to_config_map(CONFIGMAP_NAME, TRACER_CONFIG_PATH), + ], + ) + .with_ports(SERVER_PORT) + .with_volumes(volumes) + .with_env(env) + ) + if debug: + container = container.with_security_context(Capability.DEBUG) - self._depl = (fire.DeploymentBuilder(app_label=self.id) - .with_service_account_and_role_binding('cluster-admin', True) + self._depl = ( + fire.DeploymentBuilder(app_label=self.id()) + .with_service_account_and_role_binding("cluster-admin", True) .with_containers(container) .with_service() .with_node_selector("type", "kind-worker") ) def compile(self, chart: Construct): - self._depl.build(chart) - - @property - def id(self) -> str: - return "sk-tracer" + self._depl.build(chart) # type: ignore diff --git a/k8s/test_deployment.py b/k8s/test_deployment.py deleted file mode 100644 index e8d77740..00000000 --- a/k8s/test_deployment.py +++ /dev/null @@ -1,24 +0,0 @@ -import fireconfig as fire -from constructs import Construct -from fireconfig.types import TaintEffect - - -class TestDeployment(fire.AppPackage): - def __init__(self): - container = fire.ContainerBuilder( - name="nginx", - image="nginx:latest", - ).with_resources(requests={"cpu": "1"}) - - self._depl = (fire.DeploymentBuilder(app_label=self.id) - .with_containers(container) - .with_toleration("kwok-provider", "true", TaintEffect.NoSchedule) - .with_node_selector("type", "virtual") - ) - - def compile(self, chart: Construct): - self._depl.build(chart) - - @property - def id(self) -> str: - return "test" From 810b135bb4d5a7367eb4d3fe41e563203764e653 Mon Sep 17 00:00:00 2001 From: David Morrison Date: Mon, 17 Jun 2024 13:08:01 -0700 Subject: [PATCH 3/4] docs update --- Makefile | 3 ++ docs/dev/contributing.md | 11 ++++-- docs/intro/installation.md | 74 ++++++++++++++------------------------ 3 files changed, 38 insertions(+), 50 deletions(-) diff --git a/Makefile b/Makefile index 6ca2bd9b..cf39ddff 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,9 @@ unit: itest: $(CARGO_TEST_PREFIX) cargo test --features=testutils itest -- --nocapture --test-threads=1 +lint: + pre-commit run --all + cover: grcov . --binary-path $(BUILD_DIR)/debug/deps -s . -t $(RUST_COVER_TYPE) -o $(RUST_COVER_FILE) --branch \ --ignore '../*' \ diff --git a/docs/dev/contributing.md b/docs/dev/contributing.md index ac1a8343..94294da4 100644 --- a/docs/dev/contributing.md +++ b/docs/dev/contributing.md @@ -14,11 +14,18 @@ In addition to the project prerequisites, you will need to have the following in - [pre-commit](https://pre-commit.com) - Nightly version of rustfmt +SimKube uses [🔥Config](https://github.com/acrlabs/fireconfig) to generate Kubernetes manifests from definitions located +in `./k8s/`. If you want to make changes to the generated Kubernetes manifests, you will need to install the +following additional dependencies: + +- Python 3.11 +- Python Poetry (https://python-poetry.org/docs/) +- NodeJS + ### Optional prerequisites - [grcov](https://github.com/mozilla/grcov) (if you want to generate coverage reports locally) - [openapi-generator](https://openapi-generator.tech) (if you need to make changes to the SimKube API) -- [delve](https://github.com/go-delve/delve) (for debugging Golang code) - [msgpack-tools](https://github.com/ludocode/msgpack-tools) (for inspecting the contents of exported trace files) ### Setup @@ -119,7 +126,7 @@ tests, do `make test`. ### Linting your changes Code linting rules are defined in `.rustfmt.toml`. We also use [clippy](https://doc.rust-lang.org/stable/clippy/usage.html) - for additional Rust linting and checks. We use a _nightly_ version of rustfmt to take advantage of unstable formatting +for additional Rust linting and checks. We use a _nightly_ version of rustfmt to take advantage of unstable formatting rules, so you will need to install a nightly toolchain here. (Note that all actual Rust code does not use any nightly features). You can run all lints with `make lint`. diff --git a/docs/intro/installation.md b/docs/intro/installation.md index c3a621c8..6c4bb239 100644 --- a/docs/intro/installation.md +++ b/docs/intro/installation.md @@ -23,16 +23,8 @@ Additional prerequisites are necessary for your simulation cluster: ### Optional Prerequisites -SimKube uses [🔥Config](https://github.com/acrlabs/fireconfig) to generate Kubernetes manifests from definitions located -in `./k8s/`. If you want to use this mechanism for generating Kubernetes manifests, you will need to install the -following additional dependencies: - -- Python 3.10 -- Python Poetry (https://python-poetry.org/docs/) -- NodeJS - -Additionally, if you want to run SimKube on a local development cluster, [kind](https://kind.sigs.k8s.io) >= 0.19 is the -supported tooling for doing so. +If you want to run SimKube on a local development cluster, [kind](https://kind.sigs.k8s.io) >= 0.19 is the supported +tooling for doing so. If you want to test autoscaling, SimKube currently supports either the [Kubernetes Cluster Autoscaler](https://github.com/kubernetes/autoscaler) or [Karpenter](https://karpenter.sh). You will need to install and configure these applications to use the @@ -40,7 +32,21 @@ corresponding KWOK provider. For the Kubernetes Cluster Autoscaler, a KWOK [clo is available, and for Karpenter, a basic [KWOK provider](https://github.com/kubernetes-sigs/karpenter/tree/main/kwok) is used. See [Autoscaling](../adv/autoscaling.md) for more information on configuring these tools. -## Building SimKube +## Installation using hosted quay.io images and kustomize + +SimKube images are [hosted on quay.io](https://quay.io/organization/appliedcomputing); the easiest way to install and +run SimKube in your cluster is to use these images along with the provided [kustomize](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/) +YAML files in `k8s/kustomize`: + +``` +kubectl apply -k k8s/kustomize +``` + +## Installation from source + +If you instead want to build and install SimKube from source, you can follow these steps: + +### Building SimKube To build all SimKube artifacts for the first time run: @@ -53,6 +59,10 @@ For all subsequent builds of SimKube artifacts, run only `make build` from the r To build and push Docker images for all the artifacts, run `DOCKER_REGISTRY=path_to_your_registry:5000 make image` +### Running the artifacts: + +To run the artifacts using the images you built in the previous step, run `make run`. + ### Cleaning up All build artifacts are placed in the `.build/` directory. You can remove this directory or run `make clean` to clean @@ -146,30 +156,11 @@ spec: > kubectl apply -f self-signed.yml ``` -## Deploying SimKube +## Customizing SimKube -### Generating Kubernetes Manifests +The following section describes some options for customizing the behaviour of your SimKube installation -SimKube currently uses [🔥Config](https://github.com/acrlabs/fireconfig) to generate Kubernetes manifests. You can -generate the required manifests for all SimKube components by running `make k8s` from the root of this repository. - -> [!NOTE] -> 🔥Config uses [cdk8s](https://cdk8s.io) internally, which (unfortunately) runs a NodeJS subprocess. If you don't have -> NodeJS and/or Poetry installed, you can generate the manifests inside a Docker container (thanks -> [@vsoch](https://github.com/vsoch)!):
-> -> `> docker run -it --entrypoint bash -v $PWD/:/code node:bookworm`
-> `> apt-get update && apt-get install -y python3-poetry`
-> `> make k8s`
- -
- -> [!WARNING] -> The generated manifests are fairly primitive right now and you may need to customize them in order to get them to -> install in your environment. We also don't (currently) have any Helm charts available, but we'd welcome a -> contribution! (See this [GitHub issue](https://github.com/acrlabs/simkube/issues/97)) - -### Running `sk-tracer` +### Configuration `sk-tracer` The SimKube tracer runs in a real cluster and collects data about changes to objects in that cluster. You can configure what objects it watches via a config file. Here is an example config file you can use to watch changes to Deployments, @@ -195,13 +186,6 @@ trackedObjects: as well as pods. For example, if you use the above configuration, you will need the following RBAC policy attached to the service account used by `sk-tracer`: -To install `sk-tracer` into your cluster, run - -``` -> kubectl apply -f .build/manifests/0000-global.k8s.yaml -> kubectl apply -f .build/manifests/0001-sk-tracer.k8s.yaml -``` - ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -219,16 +203,10 @@ rules: verbs: ["get", "watch", "list"] ``` -### Running `sk-ctrl` +### Configuring `sk-ctrl` The SimKube controller just needs the SimKube custom resources installed in the target environment, and needs no other -configuration. After running `make k8s`, run the following commands to install everything: - -``` -> kubectl apply -f .build/manifests/raw -> kubectl apply -f .build/manifests/0000-global.k8s.yaml -> kubectl apply -f .build/manifests/0002-sk-ctrl.k8s.yaml -``` +configuration. The SimKube controller needs, at a minimum, write access for all of the objects that it will be simulating. In theory, since this is an isolated (or potentially even local) environment, it should be safe to give it `cluster-admin`, which From 0ca46768da2d87a61a4fcd9e477331c2428f2ccd Mon Sep 17 00:00:00 2001 From: David Morrison Date: Mon, 17 Jun 2024 13:10:00 -0700 Subject: [PATCH 4/4] fix workflows --- .github/workflows/pr_comment_finished.yml | 8 ++++---- .github/workflows/verify.yml | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr_comment_finished.yml b/.github/workflows/pr_comment_finished.yml index 64e508cb..82847a67 100644 --- a/.github/workflows/pr_comment_finished.yml +++ b/.github/workflows/pr_comment_finished.yml @@ -43,10 +43,10 @@ jobs: echo "" > fireconfig-comment.md echo "## Kubernetes Object DAG" >> fireconfig-comment.md cat k8s-plan-artifacts/dag.mermaid >> fireconfig-comment.md - echo ' New object' >> fireconfig-comment.md - echo ' Deleted object' >> fireconfig-comment.md - echo ' Updated object' >> fireconfig-comment.md - echo ' Updated object (causes pod recreation)' \ + echo " New object" >> fireconfig-comment.md + echo " Deleted object" >> fireconfig-comment.md + echo " Updated object" >> fireconfig-comment.md + echo " Updated object (causes pod recreation)" \ >> fireconfig-comment.md echo "## Detailed Diff" >> fireconfig-comment.md cat k8s-plan-artifacts/k8s.df >> fireconfig-comment.md diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index adbb5b80..7e5a7df5 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -56,6 +56,12 @@ jobs: run: | rustup toolchain install nightly-x86_64-unknown-linux-gnu rustup component add rustfmt --toolchain nightly-x86_64-unknown-linux-gnu + - name: Install Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Install poetry + uses: snok/install-poetry@v1 - name: Run pre-commit uses: pre-commit/action@v3.0.1 - name: Format Rust code