diff --git a/.env.example b/.env.example index 4807670..85eae5f 100644 --- a/.env.example +++ b/.env.example @@ -3,3 +3,6 @@ # Defaults are for local dev and subsystem tests only. # POSTGRES_USER=admin # POSTGRES_PASSWORD=adminpass +# +# For the full platform stack (UI, service providers, image version pins), +# see deploy/.env.example. diff --git a/Makefile b/Makefile index 0d21305..02a2132 100644 --- a/Makefile +++ b/Makefile @@ -13,11 +13,16 @@ $(error No supported container engine found. Please install podman or docker, or endif COMPOSE_FILE := deploy/compose.yaml +COMPOSE_PROJECT_NAME ?= control-plane +COMPOSE_NETWORK := $(COMPOSE_PROJECT_NAME)_default +PROFILES ?= providers COMPOSE ?= $(shell command -v podman-compose >/dev/null 2>&1 && echo podman-compose || \ (command -v docker-compose >/dev/null 2>&1 && echo docker-compose || \ (echo "$(CONTAINER_ENGINE) compose"))) +export COMPOSE_PROJECT_NAME + CONTAINER_IMAGE_NAME ?= quay.io/dcm-project/$(BINARY_NAME) CONTAINER_IMAGE_TAG ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown) @@ -41,12 +46,42 @@ run: run-dev: go run ./cmd/$(BINARY_NAME) -# Local dev stack: Postgres, NATS, and control-plane (see deploy/compose.yaml). +# Platform stack: Postgres, NATS, control-plane, and dcm-ui (see deploy/compose.yaml). compose-up: $(COMPOSE) -f $(COMPOSE_FILE) up -d --build +# Platform stack with optional service providers (see deploy/RUN.md). +compose-up-with-providers: + $(COMPOSE) -f $(COMPOSE_FILE) --profile $(PROFILES) up -d --build + +# Tear down the compose stack. Kind (or other externals) joined to the compose +# network block "compose down" from removing it — disconnect them first. +# Network cleanup uses podman- or docker-specific commands (not portable flags). compose-down: - $(COMPOSE) -f $(COMPOSE_FILE) down -v + @for network in deploy_default $(COMPOSE_NETWORK); do \ + if [ "$(CONTAINER_ENGINE)" = podman ]; then \ + if podman network exists "$$network" 2>/dev/null; then \ + for c in $$(podman ps -a --filter network=$$network -q 2>/dev/null); do \ + podman network disconnect -f "$$network" "$$c" 2>/dev/null || true; \ + done; \ + fi; \ + elif [ "$(CONTAINER_ENGINE)" = docker ]; then \ + if docker network inspect "$$network" >/dev/null 2>&1; then \ + for c in $$(docker ps -a --filter network=$$network -q 2>/dev/null); do \ + docker network disconnect "$$network" "$$c" --force 2>/dev/null || true; \ + done; \ + fi; \ + fi; \ + done; \ + COMPOSE_PROJECT_NAME=deploy $(COMPOSE) -f $(COMPOSE_FILE) down -v --remove-orphans 2>/dev/null || true; \ + $(COMPOSE) -f $(COMPOSE_FILE) down -v --remove-orphans; \ + for network in deploy_default $(COMPOSE_NETWORK); do \ + if [ "$(CONTAINER_ENGINE)" = podman ]; then \ + podman network rm -f "$$network" 2>/dev/null || true; \ + elif [ "$(CONTAINER_ENGINE)" = docker ]; then \ + docker network rm "$$network" 2>/dev/null || true; \ + fi; \ + done image-build: $(CONTAINER_ENGINE) build -f Containerfile -t $(CONTAINER_IMAGE_NAME):$(CONTAINER_IMAGE_TAG) . @@ -74,5 +109,5 @@ test: tidy: go mod tidy -.PHONY: build run run-dev compose-up compose-down image-build clean fmt vet lint test \ - test-catalog test-placement test-policy test-sp tidy +.PHONY: build run run-dev compose-up compose-up-with-providers compose-down image-build \ + clean fmt vet lint test test-catalog test-placement test-policy test-sp tidy diff --git a/README.md b/README.md index 4fec401..8ae8798 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ internal/sp/ # service provider manager api/ # OpenAPI specs per domain pkg/ # generated HTTP clients test/subsystem/ # per-domain subsystem tests -deploy/ # compose and postgres init +deploy/ # platform compose, helm chart, postgres init ``` See the [control plane monolith enhancement](https://github.com/dcm-project/enhancements/tree/main/enhancements/control-plane-monolith). @@ -36,17 +36,17 @@ Run the monolith (pick one): |---------|---------------|----------|------------| | `make run` | host | SQLite at `/tmp/control-plane.db` | NATS disabled | | `make run-dev` | host | Postgres (`DB_*` defaults) | Postgres + NATS running locally | -| `make compose-up` | containers | Postgres in compose | also starts NATS and control-plane | +| `make compose-up` | containers | Postgres in compose | also starts NATS, control-plane, and dcm-ui | ```bash make run # SQLite, no containers -make compose-up # full stack in containers +make compose-up # platform stack in containers make compose-down # stop stack and remove volumes ``` Compose uses `POSTGRES_USER` and `POSTGRES_PASSWORD` (defaults in compose are for local dev only). Override via environment or a `.env` file; see -`.env.example`. +`deploy/.env.example`. Policy evaluation and placement provisioning run in-process in the monolith (`EvaluationService`, `PlacementService` via local clients). There is no public @@ -71,3 +71,36 @@ CI pushes to `quay.io/dcm-project/control-plane` on merges to `main` and `release/v*` branches (and on version tags). See [Releasing](https://github.com/dcm-project/shared-workflows#release-flow) in shared-workflows for tag behavior and version conventions. + +## Platform deploy + +Full-stack Compose and Helm packaging live under `deploy/`: + +- **Compose:** control-plane, postgres, nats, dcm-ui, and optional service providers +- **Helm:** Kubernetes/OpenShift chart at `deploy/helm/dcm` + +See [deploy/RUN.md](deploy/RUN.md) for local stack usage and service provider profiles. +See [deploy/helm/dcm/README.md](deploy/helm/dcm/README.md) for cluster installs. + +The control-plane API is exposed on `:8080`. + +### Image versions + +Service repos push images to `quay.io/dcm-project/` with the following tags: + +| Tag format | Example | When created | +|---|---|---| +| `main` | `main` | Every push to `main` | +| `` | `a6882f7` | Every push to `main` or `release/v*` branch, and `v*` git tag pushes | +| `v-rc.N` | `v0.0.1-rc.2` | Retag script (promotes a release branch SHA to an RC tag) | +| `v` | `v0.0.1` | When a `v*` git tag is pushed (final release) | + +Browse available tags at `https://quay.io/repository/dcm-project/?tab=tags`. + +Pin versions in `.env` (see `deploy/.env.example`): + +```bash +CONTROL_PLANE_VERSION=v0.0.1 +``` + +Omitting the variable defaults to `main`. diff --git a/deploy/.env.example b/deploy/.env.example new file mode 100644 index 0000000..6b2b26a --- /dev/null +++ b/deploy/.env.example @@ -0,0 +1,37 @@ +# Optional: copy to .env in the repo root and set for local overrides. +# Used by deploy/compose.yaml. Defaults (admin / adminpass) are for local dev only. +# POSTGRES_USER=admin +# POSTGRES_PASSWORD=adminpass + +# K8s container service provider (profile: k8s-container) +# K8S_CONTAINER_SP_KUBECONFIG=/path/to/kubeconfig +# K8S_CONTAINER_SP_NAMESPACE=default +# K8S_CONTAINER_SP_NAME=k8s-container-provider +# K8S_CONTAINER_SP_EXTERNAL_SVC_TYPE=NodePort + +# Three-tier demo app service provider (profile: three-tier) +# Same kubeconfig + cluster namespace as k8s-container (K8S_CONTAINER_SP_* above). +# THREE_TIER_SP_NAME=three-tier-provider + +# ACM cluster service provider (profile: acm-cluster) +# Supports two platforms: KubeVirt (default) and BareMetal. +# Both enabled by default (SP_ENABLED_PLATFORMS=kubevirt,baremetal). +# ACM_CLUSTER_SP_NAME=acm-cluster-sp +# ACM_CLUSTER_SP_BASE_DOMAIN=apps.example.com +# ACM_CLUSTER_SP_PULL_SECRET= +# BareMetal platform only — not used by KubeVirt: +# ACM_CLUSTER_SP_DEFAULT_INFRA_ENV=my-infra-env +# ACM_CLUSTER_SP_AGENT_NAMESPACE=my-agent-namespace + +# --- Service image versions --- +# Pin specific versions instead of "main". Valid values: +# main - most recent main build (default) +# v0.0.1 - final release (from git tag) +# v0.0.1-rc.3 - release candidate (from release branch) +# abc1234 - specific commit build (for local testing only) +# CONTROL_PLANE_VERSION=main +# KUBEVIRT_SERVICE_PROVIDER_VERSION=main +# K8S_CONTAINER_SERVICE_PROVIDER_VERSION=main +# ACM_CLUSTER_SERVICE_PROVIDER_VERSION=main +# THREE_TIER_DEMO_SERVICE_PROVIDER_VERSION=main +# DCM_UI_VERSION=main diff --git a/deploy/RUN.md b/deploy/RUN.md new file mode 100644 index 0000000..cd73b8b --- /dev/null +++ b/deploy/RUN.md @@ -0,0 +1,197 @@ +# Running DCM + +## Prerequisites + +- [Podman](https://podman.io/) or [Docker](https://www.docker.com/) (the Makefile auto-detects which engine is available) +- (Optional) A Kubernetes cluster with KubeVirt for the kubevirt-service-provider +- (Optional) A Kubernetes cluster for the k8s-container-service-provider +- (Optional) An OpenShift cluster with ACM/MCE and HyperShift for the acm-cluster-service-provider + +## Quick start + +Start the core platform (postgres, nats, control-plane, and dcm-ui): + +```bash +make compose-up +``` + +The control-plane API is at `http://localhost:8080`. DCM UI is at `http://localhost:7007`. + +## CLI configuration + +The [DCM CLI](https://github.com/dcm-project/cli) uses the same control-plane URL by default +(`http://localhost:8080`). Override it with the `control-plane-url` key in `~/.dcm/config.yaml` +or the `DCM_CONTROL_PLANE_URL` environment variable. See the [CLI README](https://github.com/dcm-project/cli/blob/main/README.md) +for install and usage. + +## Running with service providers + +Service providers are behind compose profiles and do not start by default. + +### KubeVirt service provider + +To include the `kubevirt-service-provider`, set the required environment variables and +activate the `kubevirt` profile: + +```bash +export KUBERNETES_NAMESPACE=vms +export KUBEVIRT_KUBECONFIG="/path/to/kubeconfig" +make compose-up-with-providers PROFILES=kubevirt +``` + +### K8s container service provider + +To include the `k8s-container-service-provider`, set the required environment variables and +activate the `k8s-container` profile: + +```bash +export K8S_CONTAINER_SP_KUBECONFIG="/path/to/kubeconfig" +make compose-up-with-providers PROFILES=k8s-container +``` + +If using Kind, see [K8s Container SP with Kind](docs/k8s-container-sp-kind.md) for additional network setup. + +Optionally override the provider name or external service type: + +```bash +export K8S_CONTAINER_SP_NAME=my-provider +export K8S_CONTAINER_SP_EXTERNAL_SVC_TYPE=LoadBalancer +``` + +### ACM cluster service provider + +To include the `acm-cluster-service-provider`, set the required environment variables and +activate the `acm-cluster` profile: + +```bash +export ACM_CLUSTER_SP_KUBECONFIG="/path/to/kubeconfig" +export ACM_CLUSTER_SP_PULL_SECRET="" +make compose-up-with-providers PROFILES=acm-cluster +``` + +Optionally override the provider name, namespace, or base domain: + +```bash +export ACM_CLUSTER_SP_NAME=my-acm-provider +export ACM_CLUSTER_SP_NAMESPACE=clusters +export ACM_CLUSTER_SP_BASE_DOMAIN="apps.example.com" +``` + +For BareMetal provisioning, also set: + +```bash +export ACM_CLUSTER_SP_DEFAULT_INFRA_ENV="my-infra-env" +export ACM_CLUSTER_SP_AGENT_NAMESPACE="my-agent-namespace" +``` + +### Three-tier demo app service provider + +To include the `three-tier-demo-service-provider`, set the required environment variables and +activate the `three-tier` profile: + +```bash +export K8S_CONTAINER_SP_KUBECONFIG="/path/to/kubeconfig" +make compose-up-with-providers PROFILES=three-tier +``` + +When using Kind, complete the k8s-container setup (steps 1–5 in [K8s Container +SP with Kind](docs/k8s-container-sp-kind.md)) first. +For Pet Clinic usage, see [Three-Tier Demo App with Kind](docs/three-tier-app-kind.md). + +Optionally override the provider name or cluster namespace (`K8S_CONTAINER_SP_NAMESPACE` applies +to both k8s-container and three-tier SPs): + +```bash +export THREE_TIER_SP_NAME=my-provider +export K8S_CONTAINER_SP_NAMESPACE=default +``` + +### All providers + +To start all providers at once, set the required environment variables and run: + +```bash +export KUBEVIRT_KUBECONFIG="/path/to/kubeconfig" +export K8S_CONTAINER_SP_KUBECONFIG="/path/to/kubeconfig" +export ACM_CLUSTER_SP_KUBECONFIG="/path/to/kubeconfig" +export ACM_CLUSTER_SP_PULL_SECRET="" +# BareMetal only: +export ACM_CLUSTER_SP_DEFAULT_INFRA_ENV="my-infra-env" +export ACM_CLUSTER_SP_AGENT_NAMESPACE="my-agent-namespace" +make compose-up-with-providers +``` + +This defaults to the `providers` Compose profile (all service providers, including the +three-tier demo SP). To start a single provider instead, pass `PROFILES=`: + +```bash +make compose-up-with-providers PROFILES=kubevirt +make compose-up-with-providers PROFILES=k8s-container +make compose-up-with-providers PROFILES=acm-cluster +make compose-up-with-providers PROFILES=three-tier +``` + +## Verifying the deployment + +Check that all services are running: + +```bash +podman compose -f deploy/compose.yaml ps # or: docker compose -f deploy/compose.yaml ps +``` + +Check the health endpoint: + +```bash +curl http://localhost:8080/api/v1alpha1/health +``` + +Check health endpoint through DCM UI: + +```bash +curl http://localhost:7007/api/dcm/health +``` + +## Stopping services + +```bash +make compose-down +``` + +This stops all compose services and removes volumes. If Kind was connected to +the compose network (see [k8s-container-sp-kind.md](docs/k8s-container-sp-kind.md)), +`compose-down` disconnects external containers and removes both +`control-plane_default` and legacy `deploy_default` networks. + +## Configuration + +| Variable | Default | Description | +| ------------------------------------------ | --------------------------- | ----------------------------------------------------------------------------------------------------------- | +| `POSTGRES_USER` | `admin` | PostgreSQL username | +| `POSTGRES_PASSWORD` | `adminpass` | PostgreSQL password | +| `KUBERNETES_NAMESPACE` | `default` | Kubernetes namespace for KubeVirt VMs | +| `KUBEVIRT_KUBECONFIG` | `~/.kube/config` | Path to kubeconfig on the host | +| `KUBEVIRT_PROVIDER_NAME` | `kubevirt-service-provider` | Provider name and Compose service `container_name` | +| `K8S_CONTAINER_SP_KUBECONFIG` | `~/.kube/config` | Path to kubeconfig on the host for the k8s-container-service-provider | +| `K8S_CONTAINER_SP_NAMESPACE` | `default` | Kubernetes namespace for k8s containers | +| `K8S_CONTAINER_SP_NAME` | `k8s-container-provider` | Provider name for the k8s-container-service-provider | +| `K8S_CONTAINER_SP_EXTERNAL_SVC_TYPE` | `NodePort` | Kubernetes Service type for external ports (`NodePort` or `LoadBalancer`) | +| `ACM_CLUSTER_SP_KUBECONFIG` | `~/.kube/config` | Path to kubeconfig on the host for the acm-cluster-service-provider | +| `ACM_CLUSTER_SP_NAMESPACE` | `default` | Kubernetes namespace for ACM hosted clusters | +| `ACM_CLUSTER_SP_NAME` | `acm-cluster-sp` | Provider name for the acm-cluster-service-provider | +| `ACM_CLUSTER_SP_BASE_DOMAIN` | _(none)_ | Base DNS domain for hosted clusters; can be overridden per-request via `provider_hints.acm.base_domain` | +| `ACM_CLUSTER_SP_PULL_SECRET` | _(required)_ | Base64-encoded dockerconfigjson pull secret for ACM hosted clusters | +| `ACM_CLUSTER_SP_DEFAULT_INFRA_ENV` | _(none)_ | **BareMetal only.** Default InfraEnv name; can be overridden per-request via `provider_hints.acm.infra_env` | +| `ACM_CLUSTER_SP_AGENT_NAMESPACE` | _(none)_ | **BareMetal only.** Namespace where Agent resources are located | +| `CONTROL_PLANE_VERSION` | `main` | Image tag for control-plane monolith | +| `KUBEVIRT_SERVICE_PROVIDER_VERSION` | `main` | Image tag for kubevirt-service-provider | +| `K8S_CONTAINER_SERVICE_PROVIDER_VERSION` | `main` | Image tag for k8s-container-service-provider | +| `ACM_CLUSTER_SERVICE_PROVIDER_VERSION` | `main` | Image tag for acm-cluster-service-provider | +| `THREE_TIER_DEMO_SERVICE_PROVIDER_VERSION` | `main` | Image tag for three-tier-demo-service-provider | +| `THREE_TIER_SP_NAME` | `three-tier-provider` | Provider name for the three-tier-demo-service-provider | +| `DCM_UI_VERSION` | `main` | Image tag for dcm-ui | + +See [Image versions](../README.md#image-versions) in the README for available tag formats and how to update. + +## Kubernetes / OpenShift + +See [helm/dcm/README.md](helm/dcm/README.md). diff --git a/deploy/compose.override.example.yaml b/deploy/compose.override.example.yaml new file mode 100644 index 0000000..58c91c5 --- /dev/null +++ b/deploy/compose.override.example.yaml @@ -0,0 +1,17 @@ +# OpenShift: Route-based web exposure for three-tier-demo-service-provider. +# For Kind / default kubernetes exposure, do not install an override (remove +# deploy/compose.override.yaml if present). +# +# cp deploy/compose.override.example.yaml deploy/compose.override.yaml +# +# Match SP_OPENSHIFT_ROUTE_NAMESPACE to the k8s container SP namespace (same as +# K8S_CONTAINER_SP_NAMESPACE in .env). See deploy/docs/three-tier-app-kind.md. + +services: + three-tier-demo-service-provider: + environment: + SP_WEB_EXPOSURE: openshift + SP_OPENSHIFT_ROUTE_NAMESPACE: ${K8S_CONTAINER_SP_NAMESPACE:-default} + SP_OPENSHIFT_KUBECONFIG: /openshift-kubeconfig + volumes: + - ${KUBECONFIG:-$HOME/.kube/config}:/openshift-kubeconfig:ro,z diff --git a/deploy/compose.yaml b/deploy/compose.yaml index 90cf8b7..0397826 100644 --- a/deploy/compose.yaml +++ b/deploy/compose.yaml @@ -1,15 +1,20 @@ -# Local control-plane monolith stack (Postgres + NATS + control-plane). +# DCM platform stack: control-plane monolith, optional UI and service providers. +# +# Image version: defaults to :main. Pin with CONTROL_PLANE_VERSION in .env. +# Local dev: `make compose-up` builds control-plane from the repo Containerfile. # # Credentials: set POSTGRES_USER and POSTGRES_PASSWORD in the environment or in -# a .env file. Defaults are for local dev only. +# a .env file (see deploy/.env.example). Defaults are for local dev only. x-db-common: &db-common DB_TYPE: pgsql DB_HOST: postgres DB_PORT: "5432" DB_USER: ${POSTGRES_USER:-admin} - DB_PASSWORD: ${POSTGRES_PASSWORD:-adminpass} DB_PASS: ${POSTGRES_PASSWORD:-adminpass} + DB_PASSWORD: ${POSTGRES_PASSWORD:-adminpass} + +x-dcm-registration-url: &dcm-registration-url "http://control-plane:8080/api/v1alpha1" services: postgres: @@ -42,6 +47,8 @@ services: build: context: .. dockerfile: Containerfile + image: quay.io/dcm-project/control-plane:${CONTROL_PLANE_VERSION:-main} + pull_policy: always environment: <<: *db-common BIND_ADDRESS: ":8080" @@ -56,6 +63,111 @@ services: nats: condition: service_started + kubevirt-service-provider: + container_name: ${KUBEVIRT_PROVIDER_NAME:-kubevirt-service-provider} + profiles: ["providers", "kubevirt"] + image: quay.io/dcm-project/kubevirt-service-provider:${KUBEVIRT_SERVICE_PROVIDER_VERSION:-main} + pull_policy: always + environment: + NATS_URL: "nats://nats:4222" + SERVICE_MANAGER_ENDPOINT: *dcm-registration-url + PROVIDER_NAME: ${KUBEVIRT_PROVIDER_NAME:-kubevirt-service-provider} + PROVIDER_ENDPOINT: "http://${KUBEVIRT_PROVIDER_NAME:-kubevirt-service-provider}:8081/api/v1alpha1/vms" + KUBERNETES_NAMESPACE: ${KUBERNETES_NAMESPACE:-default} + KUBERNETES_KUBECONFIG: /kubeconfig + volumes: + - ${KUBEVIRT_KUBECONFIG:-~/.kube/config}:/kubeconfig:ro,z + depends_on: + control-plane: + condition: service_started + + k8s-container-service-provider: + profiles: ["providers", "k8s-container", "three-tier"] + image: quay.io/dcm-project/k8s-container-service-provider:${K8S_CONTAINER_SERVICE_PROVIDER_VERSION:-main} + pull_policy: always + environment: + SP_NAME: ${K8S_CONTAINER_SP_NAME:-k8s-container-provider} + SP_ENDPOINT: "http://k8s-container-service-provider:8080" + DCM_REGISTRATION_URL: *dcm-registration-url + SP_NATS_URL: "nats://nats:4222" + SP_K8S_NAMESPACE: ${K8S_CONTAINER_SP_NAMESPACE:-default} + SP_K8S_KUBECONFIG: /kubeconfig + SP_K8S_EXTERNAL_SVC_TYPE: ${K8S_CONTAINER_SP_EXTERNAL_SVC_TYPE:-NodePort} + expose: + - "8080" + volumes: + - ${K8S_CONTAINER_SP_KUBECONFIG:-~/.kube/config}:/kubeconfig:ro,z + depends_on: + control-plane: + condition: service_started + nats: + condition: service_started + + acm-cluster-service-provider: + profiles: ["providers", "acm-cluster"] + image: quay.io/dcm-project/acm-cluster-service-provider:${ACM_CLUSTER_SERVICE_PROVIDER_VERSION:-main} + pull_policy: always + environment: + SP_NAME: ${ACM_CLUSTER_SP_NAME:-acm-cluster-sp} + SP_ENDPOINT: "http://acm-cluster-service-provider:8080" + DCM_REGISTRATION_URL: *dcm-registration-url + SP_NATS_URL: "nats://nats:4222" + SP_CLUSTER_NAMESPACE: ${ACM_CLUSTER_SP_NAMESPACE:-default} + SP_BASE_DOMAIN: ${ACM_CLUSTER_SP_BASE_DOMAIN} + SP_PULL_SECRET: ${ACM_CLUSTER_SP_PULL_SECRET} + SP_DEFAULT_INFRA_ENV: ${ACM_CLUSTER_SP_DEFAULT_INFRA_ENV} + SP_AGENT_NAMESPACE: ${ACM_CLUSTER_SP_AGENT_NAMESPACE} + KUBECONFIG: /kubeconfig + expose: + - "8080" + volumes: + - ${ACM_CLUSTER_SP_KUBECONFIG:-~/.kube/config}:/kubeconfig:ro,z + depends_on: + control-plane: + condition: service_started + nats: + condition: service_started + + dcm-ui: + image: quay.io/dcm-project/dcm-ui:${DCM_UI_VERSION:-main} + pull_policy: always + ports: + - "7007:7007" + environment: + APP_BASE_URL: http://localhost:7007 + DCM_API_GATEWAY_URL: http://control-plane:8080 + depends_on: + control-plane: + condition: service_started + + three-tier-demo-service-provider: + profiles: ["providers", "three-tier"] + image: quay.io/dcm-project/three-tier-app-demo-service-provider:${THREE_TIER_DEMO_SERVICE_PROVIDER_VERSION:-main} + pull_policy: always + environment: + <<: *db-common + DB_NAME: three-tier-sp + CONTAINER_SP_URL: "http://k8s-container-service-provider:8080" + SP_NAME: ${THREE_TIER_SP_NAME:-three-tier-provider} + SP_ENDPOINT: "http://three-tier-demo-service-provider:8080" + DCM_REGISTRATION_URL: *dcm-registration-url + SP_NATS_URL: "nats://nats:4222" + SP_K8S_NAMESPACE: ${K8S_CONTAINER_SP_NAMESPACE:-default} + SP_K8S_KUBECONFIG: /kubeconfig + expose: + - "8080" + volumes: + - ${K8S_CONTAINER_SP_KUBECONFIG:-~/.kube/config}:/kubeconfig:ro,z + depends_on: + control-plane: + condition: service_started + nats: + condition: service_started + k8s-container-service-provider: + condition: service_started + postgres: + condition: service_healthy + volumes: postgres_data: {} nats_data: {} diff --git a/deploy/docs/k8s-container-sp-kind.md b/deploy/docs/k8s-container-sp-kind.md new file mode 100644 index 0000000..09636af --- /dev/null +++ b/deploy/docs/k8s-container-sp-kind.md @@ -0,0 +1,97 @@ +# K8s Container Service Provider with Kind + +When Kind runs with Podman, its API server lives on a separate +Podman network. The compose services can't reach it by default. + +## Setup (one-time, until containers are recreated) + +### 1. Create the Kind cluster + +```bash +KIND_EXPERIMENTAL_PROVIDER=podman kind create cluster +``` + +This creates a container named `kind-control-plane`. +If you use `--name `, the container will be `-control-plane`. + +### 2. Start the compose services + +This must be done **before** step 3 so the compose network exists. + +```bash +podman compose -f deploy/compose.yaml --profile k8s-container up -d +``` + +### 3. Connect Kind to the compose network + +Connect the Kind control-plane container to the compose network with +an alias that matches a SAN in Kind's API server certificate. + +To list valid SANs: + +```bash +podman exec kind-control-plane \ + openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text \ + | grep -A1 "Subject Alternative Name" +``` + +Use `kubernetes` as the alias (short, always present in the SAN list): + +```bash +podman network connect \ + --alias kubernetes \ + deploy_default \ + kind-control-plane +``` + +> **Note:** `make compose-up` sets `COMPOSE_PROJECT_NAME=control-plane`, so the +> network is `deploy_default`. Verify with `podman network ls`. +> `make compose-down` disconnects Kind and removes the network automatically. + +### 4. Generate a kubeconfig that uses the alias + +```bash +kubectl config view --minify --flatten --context kind-kind \ + | sed -E 's|https://[^:]+:[0-9]+|https://kubernetes:6443|' \ + > kubeconfig.yaml +``` + +Kind maps the API server to a random host port (e.g. `44615`), but +container-to-container traffic uses port `6443` directly. + +### 5. Point the SP to the generated kubeconfig + +The compose file mounts `${K8S_CONTAINER_SP_KUBECONFIG:-~/.kube/config}` into the +SP container. Set the variable to the generated file and restart: + +```bash +export K8S_CONTAINER_SP_KUBECONFIG="$(pwd)/kubeconfig.yaml" +podman compose -f deploy/compose.yaml --profile k8s-container up -d +``` + +### External service type + +The SP requires `SP_K8S_EXTERNAL_SVC_TYPE` to determine the Kubernetes Service +type for ports with `external` visibility. Valid values: + +| Value | Use case | +|---|---| +| `NodePort` | Default. Works out of the box with Kind and bare-metal clusters. | +| `LoadBalancer` | Cloud environments with a load-balancer controller (e.g., AWS, GCP) or clusters running MetalLB. | + +The compose file defaults to `NodePort`. Override it with: + +```bash +export K8S_CONTAINER_SP_EXTERNAL_SVC_TYPE=LoadBalancer +``` + +## Why this is needed + +| Problem | Cause | +|---|---| +| SP container can't reach Kind's IP | That IP belongs to Kind's network; compose services are on `deploy_default` | +| SP connects to `127.0.0.1:` | Kind's default kubeconfig uses the host-side port mapping, unreachable from other containers | +| TLS error using arbitrary hostname | The API server certificate only includes specific SANs | + +Connecting Kind to the compose network with a certificate-valid alias +and generating a kubeconfig that targets it solves all three. diff --git a/deploy/docs/three-tier-app-kind.md b/deploy/docs/three-tier-app-kind.md new file mode 100644 index 0000000..11a2f6b --- /dev/null +++ b/deploy/docs/three-tier-app-kind.md @@ -0,0 +1,272 @@ +# Three-Tier Demo App Service Provider with Kind + +The Three-Tier Demo App Service Provider (SP) is a DCM plugin that provisions a Pet Clinic application +into a Kubernetes cluster. It requires the k8s-container-service-provider to be configured and running. + +## Setup (one-time, until containers are recreated) + +### CLI or curl + +In the Compose setup from this repo, the control-plane API is **http://localhost:8080** by default. The +sections below give **`dcm`** ([CLI repo](https://github.com/dcm-project/cli)) and **`curl`** for the +same operations. They are equivalent, so use whichever you prefer. +Build or install **`dcm`** per the [CLI README](https://github.com/dcm-project/cli/blob/main/README.md). +Set the control-plane API URL in **`~/.dcm/config.yaml`** (`control-plane-url`) or via +**`DCM_CONTROL_PLANE_URL`** if the API is not on localhost:8080 (default). + +### Prerequisites + +Before starting the three-tier SP, you must complete the k8s-container-service-provider setup: + +1. Follow steps 1–5 in [k8s-container-sp-kind.md](k8s-container-sp-kind.md) to set up: + - A Kind cluster connected to the Compose network + - A kubeconfig configured to use the `kubernetes` alias + - The k8s-container-service-provider running and healthy + +Verify the setup: + +```bash +dcm sp provider list +``` + +Or: + +```bash +curl -s http://localhost:8080/api/v1alpha1/providers | jq '.providers[] | {name, health_status}' +``` + +> **Note:** The response should include `k8s-container-provider` in the list of available providers. + +### 1. Start the three-tier SP + +Using the Makefile (recommended): + +```bash +export K8S_CONTAINER_SP_KUBECONFIG="$(pwd)/kubeconfig.yaml" +make compose-up-with-providers PROFILES=three-tier +``` + +Or the same compose invocation without Make: + +```bash +export K8S_CONTAINER_SP_KUBECONFIG="$(pwd)/kubeconfig.yaml" +podman compose --profile three-tier up -d +``` + +> **Note:** The three-tier profile automatically includes the k8s-container-service-provider +> as a dependency. Both services will start together. + +Verify it is running: + +```bash +podman ps --format "table {{.Names}}\t{{.Status}}" | grep -E 'three-tier|k8s-container' +``` + +Check the SP is registered with DCM: + +```bash +dcm sp provider list +``` + +Or: + +```bash +curl -s http://localhost:8080/api/v1alpha1/providers | jq '.providers[] | select(.name | contains("three-tier"))' +``` + +Note the provider’s `name` (by default `three-tier-provider` unless you changed `THREE_TIER_SP_NAME` in Compose). + +### 2. Provision the Pet Clinic application + +Register a placement policy once, then create a catalog item instance via the +control-plane API (**`dcm`** or **`curl`**). The **First time only (policy)** note sits next to the commands in each subsection. + +#### With DCM CLI + +Create a folder and both YAML files there (copy and paste the whole block): + +```bash +mkdir -p /tmp/dcm-petclinic + +cat > /tmp/dcm-petclinic/three-tier-placement.yaml <<'EOF' +display_name: Three-tier placement +policy_type: GLOBAL +enabled: true +priority: 100 +rego_code: | + package policies.three_tier_default + + main := { + "rejected": false, + "selected_provider": "three-tier-provider" + } if { + input.spec.service_type == "three-tier-app-demo" + } +EOF + +cat > /tmp/dcm-petclinic/my-petclinic.yaml <<'EOF' +api_version: v1alpha1 +display_name: my-petclinic +spec: + catalog_item_id: pet-clinic + user_values: + - path: database.engine + value: postgres + - path: database.version + value: "18" +EOF +``` + +**`three-tier-placement.yaml`** is a placement policy so Policy Manager routes **`three-tier-app-demo`** to +**`three-tier-provider`**. **`my-petclinic.yaml`** is the catalog instance (Pet Clinic item and DB +settings). + +**Control-plane URL:** This repo does not ship a DCM config file. The CLI defaults to +`http://localhost:8080`, which matches this compose stack; **no config file is required** for +that case. Otherwise set `export DCM_CONTROL_PLANE_URL=…` for the session, or create +`~/.dcm/config.yaml`: + +```yaml +control-plane-url: http://localhost:8080 +``` + +If Policy Manager has never been configured, add the rule below so the +platform selects your three-tier provider (same `name` as in step **1**, usually `three-tier-provider`). +Without it, the instance create call can fail with `policy response missing selected provider`. + +Rego sees the instance **`spec`** as **`input.spec`**. This example matches +`service_type == "three-tier-app-demo"`; other service types skip this policy. + +```bash +dcm policy create --from-file /tmp/dcm-petclinic/three-tier-placement.yaml --id three-tier-placement +``` + +Then provision the three tier demo app: + +```bash +dcm catalog item list +dcm catalog instance create --from-file /tmp/dcm-petclinic/my-petclinic.yaml +``` + +#### With `curl` + +**First time only (policy):** Same placement rule as above. POST the policy below only if it is not +already present (duplicate returns **409**). + +```bash +curl -s -X POST 'http://localhost:8080/api/v1alpha1/policies?id=three-tier-placement' \ + -H 'Content-Type: application/json' \ + -d @- <<'JSON' +{ + "display_name": "Three-tier placement", + "policy_type": "GLOBAL", + "enabled": true, + "priority": 100, + "rego_code": "package policies.three_tier_default\n\nmain := {\n \"rejected\": false,\n \"selected_provider\": \"three-tier-provider\"\n} if {\n input.spec.service_type == \"three-tier-app-demo\"\n}\n" +} +JSON +``` + +List catalog items to find the Pet Clinic offering: + +```bash +curl -s http://localhost:8080/api/v1alpha1/catalog-items | jq . +``` + +> **Note:** Look for a catalog item with a `display_name` that indicates a Pet Clinic service. Note its `uid` value. + +Create a catalog item instance: + +```bash +curl -sS -X POST http://localhost:8080/api/v1alpha1/catalog-item-instances \ + -H "Content-Type: application/json" \ + -d '{ + "api_version": "v1alpha1", + "display_name": "my-petclinic", + "spec": { + "catalog_item_id": "pet-clinic", + "user_values": [ + { "path": "database.engine", "value": "postgres" }, + { "path": "database.version", "value": "18" } + ] + } +}' +``` + +> **Note:** Catalog Manager only applies `user_values` whose `path` matches an **editable** field on +> that catalog item. For the seeded Pet Clinic offering (`pet-clinic`), only **`database.engine`** +> and **`database.version`** are editable; app and web images use the catalog defaults. + +### 3. Verify the Pet Clinic application is running + +Monitor the Pet Clinic deployment in Kubernetes: + +```bash +kubectl get pods -n default +``` + +Wait for the Pet Clinic pod(s) to reach `Running` status. + +Find the services: + +```bash +kubectl get svc -n default +``` + +The **web** tier is a Service whose name ends with `-web` (HTTP). On Kind, that Service is usually **ClusterIP** only, so your browser cannot reach it directly from the host. Forward a local port to it (adjust the service name and ports to match `kubectl get svc`; web often uses port **80**): + +```bash +kubectl port-forward -n default svc/-web 8080:80 +``` + +Then open **http://localhost:8080** in a browser. +Use **Ctrl+C** in the terminal to stop forwarding. + +## Troubleshooting + +### The three-tier SP fails to start + +If **`compose up`** errors or a container exits, inspect: + +```bash +podman compose --profile three-tier ps +podman ps -a --format "{{.Names}}\t{{.Status}}" | grep -i three-tier +podman compose --profile three-tier logs --tail=80 three-tier-demo-service-provider +podman compose --profile three-tier logs --tail=80 k8s-container-service-provider +``` + +Then check logs for a specific container name if needed: + +```bash +podman logs +``` + +Common issues: + +- **Kubeconfig not mounted correctly:** Verify `K8S_CONTAINER_SP_KUBECONFIG` is set and the file exists. +- **k8s-container-service-provider not running:** Ensure the k8s-container-service-provider is healthy. +- **NATS or Postgres not ready:** Check that `nats` and `postgres` services are running. + +### Pet Clinic pod fails to start + +Check the pod events: + +```bash +kubectl describe pod -n default +``` + +Check logs: + +```bash +kubectl logs -n default +``` + +### Typical errors and causes + +| Problem | Cause | +|---|---| +| `policy response missing selected provider` | No enabled Policy Manager policy sets `selected_provider`, or the value does not match a registered provider `name`. Add the policy in step **2**. | +| `provider '…' is not in ready state (not_ready)` | Service Provider Manager periodically GETs `{endpoint}/health`. If that fails repeatedly, the provider becomes `not_ready` and SPRM rejects provisioning. Ensure the three-tier process responds with 2xx on that path (the demo SP redirects `/health` to `/api/v1alpha1/health`), then wait for the next health check cycle or restart the stack. Verify with `GET /api/v1alpha1/providers` and `health_status: "ready"`. | +| Three-tier SP cannot provision apps without k8s-container-service-provider | The three-tier SP is a high-level orchestration layer that delegates resource provisioning to a k8s-container-service-provider | +| App is unreachable from the host | Kind often exposes the web Service as ClusterIP only. Use `kubectl port-forward` to the **`-web`** Service (step **3**). | +| Deployment hangs or fails | Missing environment variables or unhealthy dependencies (NATS, Postgres, k8s-container-service-provider) | diff --git a/deploy/helm/dcm/Chart.yaml b/deploy/helm/dcm/Chart.yaml new file mode 100644 index 0000000..5e464ee --- /dev/null +++ b/deploy/helm/dcm/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +name: dcm +description: DCM control-plane platform for Kubernetes and OpenShift +type: application +version: 0.1.0 +appVersion: "main" +keywords: + - dcm + - control-plane diff --git a/deploy/helm/dcm/README.md b/deploy/helm/dcm/README.md new file mode 100644 index 0000000..d9d649b --- /dev/null +++ b/deploy/helm/dcm/README.md @@ -0,0 +1,87 @@ +# DCM Helm Chart + +## Prerequisites + +- Kubernetes 1.24+ or OpenShift 4.12+ +- Helm 3.x +- A default StorageClass configured in the cluster (for PostgreSQL and NATS persistent volumes) + +## Quick Start + +Install all the components with a kubernetes provider using default namespace. + +### OpenShift + +```bash +helm install dcm deploy/helm/dcm \ + --set k8sContainerServiceProvider.enabled=true \ + --set k8sContainerServiceProvider.namespace=default +``` + +OpenShift Routes are enabled by default for control-plane and DCM UI. + +### Kubernetes + +```bash +helm install dcm deploy/helm/dcm \ + --set controlPlane.route.enabled=false \ + --set dcmUi.route.enabled=false \ + --set k8sContainerServiceProvider.enabled=true \ + --set k8sContainerServiceProvider.namespace=default +``` + +Access via port-forward: + +```bash +kubectl port-forward svc/dcm-control-plane 8080:8080 +kubectl port-forward svc/dcm-dcm-ui 7007:7007 +``` + +Then open: +- Control-plane API: http://localhost:8080 +- DCM UI: http://localhost:7007 + +## Enabling Service Providers + +### KubeVirt Service Provider + +Manages virtual machines via KubeVirt. + +```bash +helm upgrade dcm deploy/helm/dcm --reuse-values \ + --set kubevirtServiceProvider.enabled=true \ + --set kubevirtServiceProvider.namespace=default +``` + +### ACM Cluster Service Provider + +Manages clusters via Red Hat Advanced Cluster Management. + +```bash +helm upgrade dcm deploy/helm/dcm --reuse-values \ + --set acmClusterServiceProvider.enabled=true \ + --set acmClusterServiceProvider.namespace=default \ + --set acmClusterServiceProvider.baseDomain=example.com +``` + +### Three-Tier Demo Service Provider + +A demo provider for a three-tier application. Requires the Kubernetes Container Service Provider to also be enabled. + +```bash +helm upgrade dcm deploy/helm/dcm --reuse-values \ + --set k8sContainerServiceProvider.enabled=true \ + --set threeTierDemoServiceProvider.enabled=true +``` + +## Uninstall + +```bash +helm uninstall dcm +``` + +Note: PersistentVolumeClaims for PostgreSQL and NATS are not deleted automatically. To remove them: + +```bash +kubectl delete pvc -l app.kubernetes.io/instance=dcm +``` diff --git a/deploy/helm/dcm/templates/_helpers.tpl b/deploy/helm/dcm/templates/_helpers.tpl new file mode 100644 index 0000000..6ea3d23 --- /dev/null +++ b/deploy/helm/dcm/templates/_helpers.tpl @@ -0,0 +1,59 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "dcm.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Fullname helper. +*/}} +{{- define "dcm.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 }} + +{{/* +Common labels. +*/}} +{{- define "dcm.labels" -}} +helm.sh/chart: {{ include "dcm.name" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/part-of: dcm +{{- end }} + +{{/* +Selector labels for a component. +Usage: {{ include "dcm.selectorLabels" (dict "context" . "component" "control-plane") }} +*/}} +{{- define "dcm.selectorLabels" -}} +app.kubernetes.io/name: {{ .component }} +app.kubernetes.io/instance: {{ .context.Release.Name }} +{{- end }} + +{{/* +Resolve image tag: per-component tag > global.imageTag > "main" +Usage: {{ include "dcm.imageTag" (dict "tag" .Values.controlPlane.tag "global" .Values.global) }} +*/}} +{{- define "dcm.imageTag" -}} +{{- default (default "main" .global.imageTag) .tag }} +{{- end }} + +{{/* +Init container that waits for postgres to be ready. +Usage: {{ include "dcm.waitForPostgres" . | nindent 8 }} +*/}} +{{- define "dcm.waitForPostgres" -}} +- name: wait-for-postgres + image: {{ .Values.postgres.image }} + command: ["sh", "-c", "until pg_isready -h {{ include "dcm.fullname" . }}-postgres -p 5432 -U {{ .Values.postgres.user }}; do echo 'Waiting for postgres...'; sleep 2; done"] +{{- end }} diff --git a/deploy/helm/dcm/templates/acm-cluster-service-provider.yaml b/deploy/helm/dcm/templates/acm-cluster-service-provider.yaml new file mode 100644 index 0000000..8766345 --- /dev/null +++ b/deploy/helm/dcm/templates/acm-cluster-service-provider.yaml @@ -0,0 +1,94 @@ +{{- if .Values.acmClusterServiceProvider.enabled }} +{{- if .Values.acmClusterServiceProvider.kubeconfig }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "dcm.fullname" . }}-acm-cluster-kubeconfig + labels: + {{- include "dcm.labels" . | nindent 4 }} +type: Opaque +data: + kubeconfig: {{ .Values.acmClusterServiceProvider.kubeconfig | b64enc | quote }} +--- +{{- end }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dcm.fullname" . }}-acm-cluster-service-provider + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "acm-cluster-service-provider") | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "acm-cluster-service-provider") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "acm-cluster-service-provider") | nindent 8 }} + spec: + containers: + - name: acm-cluster-service-provider + image: "{{ .Values.acmClusterServiceProvider.image }}:{{ include "dcm.imageTag" (dict "tag" .Values.acmClusterServiceProvider.tag "global" .Values.global) }}" + ports: + - containerPort: 8080 + protocol: TCP + env: + - name: SP_NAME + value: {{ .Values.acmClusterServiceProvider.spName | quote }} + - name: SP_ENDPOINT + value: "http://{{ include "dcm.fullname" . }}-acm-cluster-service-provider:8080" + - name: DCM_REGISTRATION_URL + value: "http://{{ include "dcm.fullname" . }}-control-plane:8080/api/v1alpha1" + - name: SP_NATS_URL + value: "nats://{{ include "dcm.fullname" . }}-nats:4222" + - name: SP_CLUSTER_NAMESPACE + value: {{ .Values.acmClusterServiceProvider.namespace | quote }} + {{- if .Values.acmClusterServiceProvider.baseDomain }} + - name: SP_BASE_DOMAIN + value: {{ .Values.acmClusterServiceProvider.baseDomain | quote }} + {{- end }} + {{- if .Values.acmClusterServiceProvider.pullSecret }} + - name: SP_PULL_SECRET + value: {{ .Values.acmClusterServiceProvider.pullSecret | quote }} + {{- end }} + {{- if .Values.acmClusterServiceProvider.defaultInfraEnv }} + - name: SP_DEFAULT_INFRA_ENV + value: {{ .Values.acmClusterServiceProvider.defaultInfraEnv | quote }} + {{- end }} + {{- if .Values.acmClusterServiceProvider.agentNamespace }} + - name: SP_AGENT_NAMESPACE + value: {{ .Values.acmClusterServiceProvider.agentNamespace | quote }} + {{- end }} + {{- if .Values.acmClusterServiceProvider.kubeconfig }} + - name: KUBECONFIG + value: /kubeconfig/kubeconfig + {{- end }} + {{- if .Values.acmClusterServiceProvider.kubeconfig }} + volumeMounts: + - name: kubeconfig + mountPath: /kubeconfig + readOnly: true + {{- end }} + {{- if .Values.acmClusterServiceProvider.kubeconfig }} + volumes: + - name: kubeconfig + secret: + secretName: {{ include "dcm.fullname" . }}-acm-cluster-kubeconfig + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dcm.fullname" . }}-acm-cluster-service-provider + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + selector: + {{- include "dcm.selectorLabels" (dict "context" . "component" "acm-cluster-service-provider") | nindent 4 }} + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP +{{- end }} diff --git a/deploy/helm/dcm/templates/control-plane.yaml b/deploy/helm/dcm/templates/control-plane.yaml new file mode 100644 index 0000000..25ec3b5 --- /dev/null +++ b/deploy/helm/dcm/templates/control-plane.yaml @@ -0,0 +1,112 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dcm.fullname" . }}-control-plane + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "control-plane") | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "control-plane") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "control-plane") | nindent 8 }} + spec: + initContainers: + {{- include "dcm.waitForPostgres" . | nindent 8 }} + containers: + - name: control-plane + image: "{{ .Values.controlPlane.image }}:{{ include "dcm.imageTag" (dict "tag" .Values.controlPlane.tag "global" .Values.global) }}" + ports: + - containerPort: 8080 + protocol: TCP + envFrom: + - secretRef: + name: {{ include "dcm.fullname" . }}-db + env: + - name: DB_TYPE + value: pgsql + - name: DB_HOST + value: {{ include "dcm.fullname" . }}-postgres + - name: DB_PORT + value: "5432" + - name: DB_NAME + value: control-plane + - name: BIND_ADDRESS + value: ":8080" + - name: LOG_LEVEL + value: info + - name: NATS_URL + value: "nats://{{ include "dcm.fullname" . }}-nats:4222" +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dcm.fullname" . }}-control-plane + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + selector: + {{- include "dcm.selectorLabels" (dict "context" . "component" "control-plane") | nindent 4 }} + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP +{{- if .Values.controlPlane.route.enabled }} +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: {{ include "dcm.fullname" . }}-control-plane + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + {{- if .Values.controlPlane.route.host }} + host: {{ .Values.controlPlane.route.host }} + {{- end }} + to: + kind: Service + name: {{ include "dcm.fullname" . }}-control-plane + port: + targetPort: 8080 + tls: + termination: edge + insecureEdgeTerminationPolicy: Redirect +{{- end }} +{{- if .Values.controlPlane.ingress.enabled }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "dcm.fullname" . }}-control-plane + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- with .Values.controlPlane.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.controlPlane.ingress.className }} + ingressClassName: {{ .Values.controlPlane.ingress.className }} + {{- end }} + rules: + - {{- if .Values.controlPlane.ingress.host }} + host: {{ .Values.controlPlane.ingress.host }} + {{- end }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ include "dcm.fullname" . }}-control-plane + port: + number: 8080 + {{- with .Values.controlPlane.ingress.tls }} + tls: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/deploy/helm/dcm/templates/dcm-ui.yaml b/deploy/helm/dcm/templates/dcm-ui.yaml new file mode 100644 index 0000000..8581d19 --- /dev/null +++ b/deploy/helm/dcm/templates/dcm-ui.yaml @@ -0,0 +1,99 @@ +{{- if .Values.dcmUi.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dcm.fullname" . }}-dcm-ui + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "dcm-ui") | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "dcm-ui") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "dcm-ui") | nindent 8 }} + spec: + containers: + - name: dcm-ui + image: "{{ .Values.dcmUi.image }}:{{ include "dcm.imageTag" (dict "tag" .Values.dcmUi.tag "global" .Values.global) }}" + ports: + - containerPort: 7007 + protocol: TCP + env: + - name: APP_BASE_URL + value: "http://localhost:7007" + - name: DCM_API_GATEWAY_URL + value: "http://{{ include "dcm.fullname" . }}-control-plane:8080" +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dcm.fullname" . }}-dcm-ui + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + selector: + {{- include "dcm.selectorLabels" (dict "context" . "component" "dcm-ui") | nindent 4 }} + ports: + - port: 7007 + targetPort: 7007 + protocol: TCP +{{- if .Values.dcmUi.route.enabled }} +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: {{ include "dcm.fullname" . }}-dcm-ui + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + {{- if .Values.dcmUi.route.host }} + host: {{ .Values.dcmUi.route.host }} + {{- end }} + to: + kind: Service + name: {{ include "dcm.fullname" . }}-dcm-ui + port: + targetPort: 7007 + tls: + termination: edge + insecureEdgeTerminationPolicy: Redirect +{{- end }} +{{- if .Values.dcmUi.ingress.enabled }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "dcm.fullname" . }}-dcm-ui + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- with .Values.dcmUi.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.dcmUi.ingress.className }} + ingressClassName: {{ .Values.dcmUi.ingress.className }} + {{- end }} + rules: + - {{- if .Values.dcmUi.ingress.host }} + host: {{ .Values.dcmUi.ingress.host }} + {{- end }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ include "dcm.fullname" . }}-dcm-ui + port: + number: 7007 + {{- with .Values.dcmUi.ingress.tls }} + tls: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +{{- end }} diff --git a/deploy/helm/dcm/templates/k8s-container-service-provider.yaml b/deploy/helm/dcm/templates/k8s-container-service-provider.yaml new file mode 100644 index 0000000..8929eac --- /dev/null +++ b/deploy/helm/dcm/templates/k8s-container-service-provider.yaml @@ -0,0 +1,125 @@ +{{- if .Values.k8sContainerServiceProvider.enabled }} +{{- if not .Values.k8sContainerServiceProvider.kubeconfig }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "dcm.fullname" . }}-k8s-container-sp + labels: + {{- include "dcm.labels" . | nindent 4 }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "dcm.fullname" . }}-k8s-container-sp + namespace: {{ .Values.k8sContainerServiceProvider.namespace }} + labels: + {{- include "dcm.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["pods", "services", "configmaps", "secrets", "persistentvolumeclaims"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["apps"] + resources: ["deployments", "statefulsets", "replicasets"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: [""] + resources: ["events"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "dcm.fullname" . }}-k8s-container-sp + namespace: {{ .Values.k8sContainerServiceProvider.namespace }} + labels: + {{- include "dcm.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "dcm.fullname" . }}-k8s-container-sp +subjects: + - kind: ServiceAccount + name: {{ include "dcm.fullname" . }}-k8s-container-sp + namespace: {{ .Release.Namespace }} +--- +{{- else }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "dcm.fullname" . }}-k8s-container-kubeconfig + labels: + {{- include "dcm.labels" . | nindent 4 }} +type: Opaque +data: + kubeconfig: {{ .Values.k8sContainerServiceProvider.kubeconfig | b64enc | quote }} +--- +{{- end }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dcm.fullname" . }}-k8s-container-service-provider + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "k8s-container-service-provider") | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "k8s-container-service-provider") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "k8s-container-service-provider") | nindent 8 }} + spec: + {{- if not .Values.k8sContainerServiceProvider.kubeconfig }} + serviceAccountName: {{ include "dcm.fullname" . }}-k8s-container-sp + {{- end }} + containers: + - name: k8s-container-service-provider + image: "{{ .Values.k8sContainerServiceProvider.image }}:{{ include "dcm.imageTag" (dict "tag" .Values.k8sContainerServiceProvider.tag "global" .Values.global) }}" + ports: + - containerPort: 8080 + protocol: TCP + env: + - name: SP_NAME + value: {{ .Values.k8sContainerServiceProvider.spName | quote }} + - name: SP_ENDPOINT + value: "http://{{ include "dcm.fullname" . }}-k8s-container-service-provider:8080" + - name: DCM_REGISTRATION_URL + value: "http://{{ include "dcm.fullname" . }}-control-plane:8080/api/v1alpha1" + - name: SP_NATS_URL + value: "nats://{{ include "dcm.fullname" . }}-nats:4222" + - name: SP_K8S_NAMESPACE + value: {{ .Values.k8sContainerServiceProvider.namespace | quote }} + {{- if .Values.k8sContainerServiceProvider.kubeconfig }} + - name: SP_K8S_KUBECONFIG + value: /kubeconfig/kubeconfig + {{- end }} + - name: SP_K8S_EXTERNAL_SVC_TYPE + value: {{ .Values.k8sContainerServiceProvider.externalSvcType | quote }} + {{- if .Values.k8sContainerServiceProvider.kubeconfig }} + volumeMounts: + - name: kubeconfig + mountPath: /kubeconfig + readOnly: true + {{- end }} + {{- if .Values.k8sContainerServiceProvider.kubeconfig }} + volumes: + - name: kubeconfig + secret: + secretName: {{ include "dcm.fullname" . }}-k8s-container-kubeconfig + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dcm.fullname" . }}-k8s-container-service-provider + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + selector: + {{- include "dcm.selectorLabels" (dict "context" . "component" "k8s-container-service-provider") | nindent 4 }} + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP +{{- end }} diff --git a/deploy/helm/dcm/templates/kubevirt-service-provider.yaml b/deploy/helm/dcm/templates/kubevirt-service-provider.yaml new file mode 100644 index 0000000..ba1acd4 --- /dev/null +++ b/deploy/helm/dcm/templates/kubevirt-service-provider.yaml @@ -0,0 +1,61 @@ +{{- if .Values.kubevirtServiceProvider.enabled }} +{{- if .Values.kubevirtServiceProvider.kubeconfig }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "dcm.fullname" . }}-kubevirt-kubeconfig + labels: + {{- include "dcm.labels" . | nindent 4 }} +type: Opaque +data: + kubeconfig: {{ .Values.kubevirtServiceProvider.kubeconfig | b64enc | quote }} +--- +{{- end }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dcm.fullname" . }}-kubevirt-service-provider + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "kubevirt-service-provider") | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "kubevirt-service-provider") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "kubevirt-service-provider") | nindent 8 }} + spec: + containers: + - name: kubevirt-service-provider + image: "{{ .Values.kubevirtServiceProvider.image }}:{{ include "dcm.imageTag" (dict "tag" .Values.kubevirtServiceProvider.tag "global" .Values.global) }}" + env: + - name: NATS_URL + value: "nats://{{ include "dcm.fullname" . }}-nats:4222" + - name: SERVICE_MANAGER_ENDPOINT + value: "http://{{ include "dcm.fullname" . }}-control-plane:8080/api/v1alpha1" + - name: PROVIDER_NAME + value: {{ .Values.kubevirtServiceProvider.providerName | quote }} + - name: PROVIDER_ENDPOINT + value: "http://{{ include "dcm.fullname" . }}-kubevirt-service-provider:8081/api/v1alpha1/vms" + - name: KUBERNETES_NAMESPACE + value: {{ .Values.kubevirtServiceProvider.namespace | quote }} + {{- if .Values.kubevirtServiceProvider.kubeconfig }} + - name: KUBERNETES_KUBECONFIG + value: /kubeconfig/kubeconfig + {{- end }} + {{- if .Values.kubevirtServiceProvider.kubeconfig }} + volumeMounts: + - name: kubeconfig + mountPath: /kubeconfig + readOnly: true + {{- end }} + {{- if .Values.kubevirtServiceProvider.kubeconfig }} + volumes: + - name: kubeconfig + secret: + secretName: {{ include "dcm.fullname" . }}-kubevirt-kubeconfig + {{- end }} +{{- end }} diff --git a/deploy/helm/dcm/templates/nats.yaml b/deploy/helm/dcm/templates/nats.yaml new file mode 100644 index 0000000..49ec225 --- /dev/null +++ b/deploy/helm/dcm/templates/nats.yaml @@ -0,0 +1,60 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "dcm.fullname" . }}-nats + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "nats") | nindent 4 }} +spec: + serviceName: {{ include "dcm.fullname" . }}-nats + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "nats") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "nats") | nindent 8 }} + spec: + containers: + - name: nats + image: {{ .Values.nats.image }} + args: ["--jetstream", "--store_dir=/data"] + ports: + - containerPort: 4222 + protocol: TCP + name: client + - containerPort: 8222 + protocol: TCP + name: monitoring + volumeMounts: + - name: data + mountPath: /data + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: {{ .Values.nats.storage }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dcm.fullname" . }}-nats + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + clusterIP: None + selector: + {{- include "dcm.selectorLabels" (dict "context" . "component" "nats") | nindent 4 }} + ports: + - port: 4222 + targetPort: 4222 + protocol: TCP + name: client + - port: 8222 + targetPort: 8222 + protocol: TCP + name: monitoring diff --git a/deploy/helm/dcm/templates/postgres.yaml b/deploy/helm/dcm/templates/postgres.yaml new file mode 100644 index 0000000..81b2387 --- /dev/null +++ b/deploy/helm/dcm/templates/postgres.yaml @@ -0,0 +1,96 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "dcm.fullname" . }}-postgres-init + labels: + {{- include "dcm.labels" . | nindent 4 }} +data: + 01-create-databases.sql: | + CREATE DATABASE "control-plane"; + CREATE DATABASE "three-tier-sp"; +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "dcm.fullname" . }}-postgres + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "postgres") | nindent 4 }} +spec: + serviceName: {{ include "dcm.fullname" . }}-postgres + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "postgres") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "postgres") | nindent 8 }} + spec: + containers: + - name: postgres + image: {{ .Values.postgres.image }} + ports: + - containerPort: 5432 + protocol: TCP + envFrom: + - secretRef: + name: {{ include "dcm.fullname" . }}-db + env: + - name: POSTGRES_DB + value: postgres + readinessProbe: + exec: + command: + - pg_isready + - -U + - {{ .Values.postgres.user | quote }} + - -d + - postgres + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 5 + failureThreshold: 5 + livenessProbe: + exec: + command: + - pg_isready + - -U + - {{ .Values.postgres.user | quote }} + - -d + - postgres + initialDelaySeconds: 15 + periodSeconds: 10 + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + - name: init-scripts + mountPath: /docker-entrypoint-initdb.d + readOnly: true + volumes: + - name: init-scripts + configMap: + name: {{ include "dcm.fullname" . }}-postgres-init + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: {{ .Values.postgres.storage }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dcm.fullname" . }}-postgres + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + clusterIP: None + selector: + {{- include "dcm.selectorLabels" (dict "context" . "component" "postgres") | nindent 4 }} + ports: + - port: 5432 + targetPort: 5432 + protocol: TCP diff --git a/deploy/helm/dcm/templates/secret-db.yaml b/deploy/helm/dcm/templates/secret-db.yaml new file mode 100644 index 0000000..a2f06a4 --- /dev/null +++ b/deploy/helm/dcm/templates/secret-db.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "dcm.fullname" . }}-db + labels: + {{- include "dcm.labels" . | nindent 4 }} +type: Opaque +stringData: + DB_USER: {{ .Values.postgres.user | quote }} + DB_PASS: {{ .Values.postgres.password | quote }} + DB_PASSWORD: {{ .Values.postgres.password | quote }} + POSTGRES_USER: {{ .Values.postgres.user | quote }} + POSTGRES_PASSWORD: {{ .Values.postgres.password | quote }} diff --git a/deploy/helm/dcm/templates/three-tier-demo-service-provider.yaml b/deploy/helm/dcm/templates/three-tier-demo-service-provider.yaml new file mode 100644 index 0000000..957df60 --- /dev/null +++ b/deploy/helm/dcm/templates/three-tier-demo-service-provider.yaml @@ -0,0 +1,93 @@ +{{- if .Values.threeTierDemoServiceProvider.enabled }} +{{- if .Values.threeTierDemoServiceProvider.kubeconfig }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "dcm.fullname" . }}-three-tier-kubeconfig + labels: + {{- include "dcm.labels" . | nindent 4 }} +type: Opaque +data: + kubeconfig: {{ .Values.threeTierDemoServiceProvider.kubeconfig | b64enc | quote }} +--- +{{- end }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dcm.fullname" . }}-three-tier-demo-sp + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "three-tier-demo-sp") | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "three-tier-demo-sp") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "three-tier-demo-sp") | nindent 8 }} + spec: + initContainers: + {{- include "dcm.waitForPostgres" . | nindent 8 }} + containers: + - name: three-tier-demo-service-provider + image: "{{ .Values.threeTierDemoServiceProvider.image }}:{{ include "dcm.imageTag" (dict "tag" .Values.threeTierDemoServiceProvider.tag "global" .Values.global) }}" + ports: + - containerPort: 8080 + protocol: TCP + envFrom: + - secretRef: + name: {{ include "dcm.fullname" . }}-db + env: + - name: DB_TYPE + value: pgsql + - name: DB_HOST + value: {{ include "dcm.fullname" . }}-postgres + - name: DB_PORT + value: "5432" + - name: DB_NAME + value: three-tier-sp + - name: CONTAINER_SP_URL + value: "http://{{ include "dcm.fullname" . }}-k8s-container-service-provider:8080" + - name: SP_NAME + value: {{ .Values.threeTierDemoServiceProvider.spName | quote }} + - name: SP_ENDPOINT + value: "http://{{ include "dcm.fullname" . }}-three-tier-demo-sp:8080" + - name: DCM_REGISTRATION_URL + value: "http://{{ include "dcm.fullname" . }}-control-plane:8080/api/v1alpha1" + - name: SP_NATS_URL + value: "nats://{{ include "dcm.fullname" . }}-nats:4222" + - name: SP_K8S_NAMESPACE + value: {{ .Values.threeTierDemoServiceProvider.namespace | quote }} + {{- if .Values.threeTierDemoServiceProvider.kubeconfig }} + - name: SP_K8S_KUBECONFIG + value: /kubeconfig/kubeconfig + {{- end }} + {{- if .Values.threeTierDemoServiceProvider.kubeconfig }} + volumeMounts: + - name: kubeconfig + mountPath: /kubeconfig + readOnly: true + {{- end }} + {{- if .Values.threeTierDemoServiceProvider.kubeconfig }} + volumes: + - name: kubeconfig + secret: + secretName: {{ include "dcm.fullname" . }}-three-tier-kubeconfig + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dcm.fullname" . }}-three-tier-demo-sp + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + selector: + {{- include "dcm.selectorLabels" (dict "context" . "component" "three-tier-demo-sp") | nindent 4 }} + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP +{{- end }} diff --git a/deploy/helm/dcm/values.yaml b/deploy/helm/dcm/values.yaml new file mode 100644 index 0000000..d3c26ad --- /dev/null +++ b/deploy/helm/dcm/values.yaml @@ -0,0 +1,82 @@ +# -- Global settings +global: + imageTag: main + +# -- PostgreSQL +postgres: + image: docker.io/library/postgres:16-alpine + user: admin + password: adminpass + storage: 1Gi + +# -- NATS +nats: + image: docker.io/library/nats:2-alpine + storage: 1Gi + +# -- Control-plane monolith (catalog, policy, placement, SP manager) +controlPlane: + image: quay.io/dcm-project/control-plane + tag: "" # defaults to global.imageTag + route: + enabled: true + host: "" # leave empty for auto-generated OpenShift hostname + ingress: + enabled: false + className: "" + host: "" + tls: [] + annotations: {} + +# -- DCM UI +dcmUi: + enabled: true + image: quay.io/dcm-project/dcm-ui + tag: "" + route: + enabled: true + host: "" + ingress: + enabled: false + className: "" + host: "" + tls: [] + annotations: {} + +# -- Optional service providers (disabled by default) +kubevirtServiceProvider: + enabled: false + image: quay.io/dcm-project/kubevirt-service-provider + tag: "" + providerName: kubevirt-service-provider + namespace: default + kubeconfig: "" # base64-encoded kubeconfig content for the Secret + +k8sContainerServiceProvider: + enabled: false + image: quay.io/dcm-project/k8s-container-service-provider + tag: "" + spName: k8s-container-provider + namespace: default + externalSvcType: NodePort + kubeconfig: "" + +acmClusterServiceProvider: + enabled: false + image: quay.io/dcm-project/acm-cluster-service-provider + tag: "" + spName: acm-cluster-sp + namespace: default + baseDomain: "" + pullSecret: "" + defaultInfraEnv: "" + agentNamespace: "" + kubeconfig: "" + +threeTierDemoServiceProvider: + enabled: false + image: quay.io/dcm-project/three-tier-app-demo-service-provider + tag: "" + spName: three-tier-provider + namespace: default + kubeconfig: "" diff --git a/deploy/postgres-init/01-create-database.sql b/deploy/postgres-init/01-create-databases.sql similarity index 50% rename from deploy/postgres-init/01-create-database.sql rename to deploy/postgres-init/01-create-databases.sql index 5fdb26f..640b1a9 100644 --- a/deploy/postgres-init/01-create-database.sql +++ b/deploy/postgres-init/01-create-databases.sql @@ -1 +1,2 @@ CREATE DATABASE "control-plane"; +CREATE DATABASE "three-tier-sp";