diff --git a/Makefile b/Makefile index 8e5426d..1ef75ea 100644 --- a/Makefile +++ b/Makefile @@ -16,3 +16,8 @@ build-and-load-configure-image: docker buildx build --builder kratix-image-builder --load --platform linux/arm64 \ -t ghcr.io/syntasso/example-deployment-configure:v0.0.1 -f examples/deployment/Dockerfile . kind load docker-image ghcr.io/syntasso/example-deployment-configure:v0.0.1 -n platform + +build-and-load-system-test-image: + docker buildx build --builder kratix-image-builder --load --platform linux/arm64 \ + -t ghcr.io/syntasso/kratix-python/sdk-test:v1.0.0 -f system/assets/workflow/Dockerfile . + kind load docker-image ghcr.io/syntasso/kratix-python/sdk-test:v1.0.0 -n platform diff --git a/system/assets/example-resource.yaml b/system/assets/example-resource.yaml new file mode 100644 index 0000000..f0fabea --- /dev/null +++ b/system/assets/example-resource.yaml @@ -0,0 +1,10 @@ +apiVersion: syntasso.io/v1 +kind: config +metadata: + name: sdk-resource +spec: + fields: + - name: "field0" + value: "value0" + - name: "field1" + value: "value1" \ No newline at end of file diff --git a/system/assets/promise.yaml b/system/assets/promise.yaml new file mode 100644 index 0000000..24f1483 --- /dev/null +++ b/system/assets/promise.yaml @@ -0,0 +1,61 @@ +apiVersion: platform.kratix.io/v1alpha1 +kind: Promise +metadata: + creationTimestamp: null + name: config +spec: + api: + apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + metadata: + name: configs.syntasso.io + spec: + group: syntasso.io + names: + kind: config + plural: configs + singular: config + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + properties: + spec: + properties: + fields: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + workflows: + promise: + configure: + - apiVersion: platform.kratix.io/v1alpha1 + kind: Pipeline + metadata: + name: promise + spec: + containers: + - image: ghcr.io/syntasso/kratix-python/sdk-test:v1.0.0 + name: promise-pipeline + command: ["python", "configure.py", "promise-configure"] + resource: + configure: + - apiVersion: platform.kratix.io/v1alpha1 + kind: Pipeline + metadata: + name: instance + spec: + containers: + - image: ghcr.io/syntasso/kratix-python/sdk-test:v1.0.0 + name: resource-pipeline + command: ["python", "configure.py", "resource-configure"] \ No newline at end of file diff --git a/system/assets/workflow/Dockerfile b/system/assets/workflow/Dockerfile new file mode 100644 index 0000000..905f4c8 --- /dev/null +++ b/system/assets/workflow/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.12-slim + +WORKDIR /app + +RUN pip install --no-cache-dir kubernetes + +COPY kratix_sdk /app/kratix_sdk + +# Put /app on PYTHONPATH so kratix_sdk is importable +ENV PYTHONPATH=/app + +COPY system/assets/workflow /app/system/assets/workflow + +WORKDIR /app/system/assets/workflow + +ENTRYPOINT ["/bin/sh", "-c"] +CMD ["echo Set command to promise-configure or resource-configure"] diff --git a/system/assets/workflow/configure.py b/system/assets/workflow/configure.py new file mode 100644 index 0000000..e18975a --- /dev/null +++ b/system/assets/workflow/configure.py @@ -0,0 +1,117 @@ +import sys +import kratix_sdk as ks +from typing import List +import yaml + +def promise_configure() -> int: + sdk = ks.KratixSDK() + print("Helper variables:") + print("Workflow action: ", sdk.workflow_action()) + print("Workflow type: ", sdk.workflow_type()) + print("Promise name: ", sdk.promise_name()) + print("Workflow action: ", sdk.pipeline_name()) + + print("Reading Promise input...") + promise = sdk.read_promise_input() + name = promise.get_name() + manifest = { + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": {"name": name + "-config", "namespace": "default"}, + "data": { + "workflowAction": sdk.workflow_action(), + "workflowType": sdk.workflow_type(), + "promiseName": name, + "pipelineName": sdk.pipeline_name(), + }, + } + data = yaml.safe_dump(manifest).encode("utf-8") + sdk.write_output("config.yaml", data) + + print("All tests passed") + return 0 + +def resource_configure() -> int: + sdk = ks.KratixSDK() + print("Helper variables:") + print("Workflow action: ", sdk.workflow_action()) + print("Workflow type: ", sdk.workflow_type()) + print("Promise name: ", sdk.promise_name()) + print("Workflow action: ", sdk.pipeline_name()) + + print("Reading Resource input...") + resource = sdk.read_resource_input() + + print("Getting fields...") + fields = resource.get_value("spec.fields") + print("Fields: ", fields) + + manifest = { + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": {"name": resource.get_name() + "-config", "namespace": resource.get_namespace()}, + "data": { + "workflowAction": sdk.workflow_action(), + "workflowType": sdk.workflow_type(), + "promiseName": sdk.promise_name(), + "pipelineName": sdk.pipeline_name(), + }, + } + for field in fields: + manifest["data"][field["name"]] = field["value"] + + data = yaml.safe_dump(manifest).encode("utf-8") + sdk.write_output("config.yaml", data) + + print("Publishing 'publishedDirectly' status...") + status = ks.Status() + status.set("publishedDirectly", True) + sdk.publish_status(resource, status) + + print("Wrtiting status file...") + status = ks.Status() + status.set("viaFile", True) + sdk.write_status(status) + print("Validating status file...") + status = sdk.read_status() + if not status.get("viaFile"): + print("Status file validation failed: 'viaFile' is not True", file=sys.stderr) + return 1 + + print("Validating destination selectors...") + selectors: List[ks.DestinationSelector] = [ + ks.DestinationSelector(match_labels={"environment": "dev"}) + ] + sdk.write_destination_selectors(selectors) + + selectors = sdk.read_destination_selectors() + if len(selectors) != 1: + print("Destination selectors validation failed: expected 1 selector, got", len(selectors), file=sys.stderr) + return 1 + if selectors[0].match_labels["environment"] != "dev": + print("Destination selectors validation failed: expected 'environment=dev', got", selectors[0].match_labels, file=sys.stderr) + return 1 + + + print("All tests passed") + return 0 + + +def main() -> int: + # Dispatch by argv[1] + if len(sys.argv) < 2: + print("usage: handlers.py [promise-configure|resource-configure]", file=sys.stderr) + return 2 + + cmd = sys.argv[1] + if cmd == "promise-configure": + return promise_configure() + if cmd == "resource-configure": + return resource_configure() + + print(f"unknown command: {cmd}", file=sys.stderr) + return 2 + + +if __name__ == "__main__": + raise SystemExit(main())