diff --git a/helm/dcm/Chart.yaml b/helm/dcm/Chart.yaml new file mode 100644 index 0000000..28f7536 --- /dev/null +++ b/helm/dcm/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +name: dcm +description: DCM API Gateway and managers for Kubernetes and OpenShift +type: application +version: 0.1.0 +appVersion: "main" +keywords: + - dcm + - api-gateway diff --git a/helm/dcm/README.md b/helm/dcm/README.md new file mode 100644 index 0000000..fb900ff --- /dev/null +++ b/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 helm/dcm \ + --set k8sContainerServiceProvider.enabled=true \ + --set k8sContainerServiceProvider.namespace=default +``` + +OpenShift Routes are enabled by default for the API gateway and DCM UI. + +### Kubernetes + +```bash +helm install dcm helm/dcm \ + --set gateway.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-gateway 9080:9080 +kubectl port-forward svc/dcm-dcm-ui 7007:7007 +``` + +Then open: +- API Gateway: http://localhost:9080 +- DCM UI: http://localhost:7007 + +## Enabling Service Providers + +### KubeVirt Service Provider + +Manages virtual machines via KubeVirt. + +```bash +helm upgrade dcm 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 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 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/helm/dcm/templates/_helpers.tpl b/helm/dcm/templates/_helpers.tpl new file mode 100644 index 0000000..af786db --- /dev/null +++ b/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" "gateway") }} +*/}} +{{- 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.serviceProviderManager.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/helm/dcm/templates/acm-cluster-service-provider.yaml b/helm/dcm/templates/acm-cluster-service-provider.yaml new file mode 100644 index 0000000..4370723 --- /dev/null +++ b/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" . }}-service-provider-manager: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/helm/dcm/templates/catalog-manager.yaml b/helm/dcm/templates/catalog-manager.yaml new file mode 100644 index 0000000..1a911a2 --- /dev/null +++ b/helm/dcm/templates/catalog-manager.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dcm.fullname" . }}-catalog-manager + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "catalog-manager") | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "catalog-manager") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "catalog-manager") | nindent 8 }} + spec: + initContainers: + {{- include "dcm.waitForPostgres" . | nindent 8 }} + containers: + - name: catalog-manager + image: "{{ .Values.catalogManager.image }}:{{ include "dcm.imageTag" (dict "tag" .Values.catalogManager.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: catalog-manager + - name: BIND_ADDRESS + value: ":8080" + - name: PLACEMENT_MANAGER_URL + value: "http://{{ include "dcm.fullname" . }}-placement-manager:8080" +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dcm.fullname" . }}-catalog-manager + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + selector: + {{- include "dcm.selectorLabels" (dict "context" . "component" "catalog-manager") | nindent 4 }} + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP diff --git a/helm/dcm/templates/dcm-ui.yaml b/helm/dcm/templates/dcm-ui.yaml new file mode 100644 index 0000000..13ec000 --- /dev/null +++ b/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" . }}-gateway:{{ .Values.gateway.port }}" +--- +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/helm/dcm/templates/gateway.yaml b/helm/dcm/templates/gateway.yaml new file mode 100644 index 0000000..d56c8d1 --- /dev/null +++ b/helm/dcm/templates/gateway.yaml @@ -0,0 +1,243 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "dcm.fullname" . }}-traefik-static + labels: + {{- include "dcm.labels" . | nindent 4 }} +data: + traefik.yml: | + entryPoints: + web: + address: ":{{ .Values.gateway.port }}" + providers: + file: + directory: /etc/traefik/dynamic + watch: true + ping: + entryPoint: web + log: + level: INFO + accessLog: {} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "dcm.fullname" . }}-traefik-routes + labels: + {{- include "dcm.labels" . | nindent 4 }} +data: + routes.yml: | + http: + routers: + # -- Health endpoints (GET only) + health-providers: + rule: "Path(`/api/v1alpha1/health/providers`) && Method(`GET`)" + service: service-provider-manager + entryPoints: [web] + middlewares: [strip-health-suffix] + health-catalog: + rule: "Path(`/api/v1alpha1/health/catalog`) && Method(`GET`)" + service: catalog-manager + entryPoints: [web] + middlewares: [strip-health-suffix] + health-policies: + rule: "Path(`/api/v1alpha1/health/policies`) && Method(`GET`)" + service: policy-manager + entryPoints: [web] + middlewares: [strip-health-suffix] + health-placement: + rule: "Path(`/api/v1alpha1/health/placement`) && Method(`GET`)" + service: placement-manager + entryPoints: [web] + middlewares: [strip-health-suffix] + + # -- ServiceProviderManager + providers-collection: + rule: "Path(`/api/v1alpha1/providers`) && (Method(`GET`) || Method(`POST`))" + service: service-provider-manager + entryPoints: [web] + providers-resource: + rule: "PathRegexp(`^/api/v1alpha1/providers/[^/:]+$`) && (Method(`GET`) || Method(`PUT`) || Method(`DELETE`))" + service: service-provider-manager + entryPoints: [web] + service-type-instances-collection: + rule: "Path(`/api/v1alpha1/service-type-instances`) && Method(`GET`)" + service: service-provider-manager + entryPoints: [web] + service-type-instances-resource: + rule: "PathRegexp(`^/api/v1alpha1/service-type-instances/[^/:]+$`) && Method(`GET`)" + service: service-provider-manager + entryPoints: [web] + + # -- CatalogManager + service-types-collection: + rule: "Path(`/api/v1alpha1/service-types`) && Method(`GET`)" + service: catalog-manager + entryPoints: [web] + service-types-resource: + rule: "PathRegexp(`^/api/v1alpha1/service-types/[^/:]+$`) && Method(`GET`)" + service: catalog-manager + entryPoints: [web] + catalog-items-collection: + rule: "Path(`/api/v1alpha1/catalog-items`) && (Method(`GET`) || Method(`POST`))" + service: catalog-manager + entryPoints: [web] + catalog-items-resource: + rule: "PathRegexp(`^/api/v1alpha1/catalog-items/[^/:]+$`) && (Method(`GET`) || Method(`PATCH`) || Method(`DELETE`))" + service: catalog-manager + entryPoints: [web] + catalog-item-instances-collection: + rule: "Path(`/api/v1alpha1/catalog-item-instances`) && (Method(`GET`) || Method(`POST`))" + service: catalog-manager + entryPoints: [web] + catalog-item-instances-resource: + rule: "PathRegexp(`^/api/v1alpha1/catalog-item-instances/[^/:]+$`) && (Method(`GET`) || Method(`DELETE`))" + service: catalog-manager + entryPoints: [web] + catalog-item-instances-rehydrate: + rule: "PathRegexp(`^/api/v1alpha1/catalog-item-instances/[^/]+:rehydrate$`) && Method(`POST`)" + service: catalog-manager + entryPoints: [web] + + # -- PolicyManager + policies-collection: + rule: "Path(`/api/v1alpha1/policies`) && (Method(`GET`) || Method(`POST`))" + service: policy-manager + entryPoints: [web] + policies-resource: + rule: "PathRegexp(`^/api/v1alpha1/policies/[^/:]+$`) && (Method(`GET`) || Method(`PATCH`) || Method(`DELETE`))" + service: policy-manager + entryPoints: [web] + + middlewares: + strip-health-suffix: + replacePathRegex: + regex: "^/api/v1alpha1/health/.*" + replacement: "/api/v1alpha1/health" + + services: + service-provider-manager: + loadBalancer: + servers: + - url: "http://{{ include "dcm.fullname" .}}-service-provider-manager:8080" + catalog-manager: + loadBalancer: + servers: + - url: "http://{{ include "dcm.fullname" .}}-catalog-manager:8080" + policy-manager: + loadBalancer: + servers: + - url: "http://{{ include "dcm.fullname" .}}-policy-manager:8080" + placement-manager: + loadBalancer: + servers: + - url: "http://{{ include "dcm.fullname" .}}-placement-manager:8080" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dcm.fullname" . }}-gateway + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "gateway") | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "gateway") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "gateway") | nindent 8 }} + spec: + containers: + - name: traefik + image: {{ .Values.gateway.image }} + args: ["--configFile=/etc/traefik/traefik.yml"] + ports: + - containerPort: {{ .Values.gateway.port }} + protocol: TCP + volumeMounts: + - name: static-config + mountPath: /etc/traefik/traefik.yml + subPath: traefik.yml + readOnly: true + - name: dynamic-config + mountPath: /etc/traefik/dynamic + readOnly: true + volumes: + - name: static-config + configMap: + name: {{ include "dcm.fullname" . }}-traefik-static + - name: dynamic-config + configMap: + name: {{ include "dcm.fullname" . }}-traefik-routes +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dcm.fullname" . }}-gateway + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + selector: + {{- include "dcm.selectorLabels" (dict "context" . "component" "gateway") | nindent 4 }} + ports: + - port: {{ .Values.gateway.port }} + targetPort: {{ .Values.gateway.port }} + protocol: TCP +{{- if .Values.gateway.route.enabled }} +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: {{ include "dcm.fullname" . }}-gateway + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + {{- if .Values.gateway.route.host }} + host: {{ .Values.gateway.route.host }} + {{- end }} + to: + kind: Service + name: {{ include "dcm.fullname" . }}-gateway + port: + targetPort: {{ .Values.gateway.port }} + tls: + termination: edge + insecureEdgeTerminationPolicy: Redirect +{{- end }} +{{- if .Values.gateway.ingress.enabled }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "dcm.fullname" . }}-gateway + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- with .Values.gateway.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.gateway.ingress.className }} + ingressClassName: {{ .Values.gateway.ingress.className }} + {{- end }} + rules: + - {{- if .Values.gateway.ingress.host }} + host: {{ .Values.gateway.ingress.host }} + {{- end }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ include "dcm.fullname" . }}-gateway + port: + number: {{ .Values.gateway.port }} + {{- with .Values.gateway.ingress.tls }} + tls: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/dcm/templates/k8s-container-service-provider.yaml b/helm/dcm/templates/k8s-container-service-provider.yaml new file mode 100644 index 0000000..0e53acb --- /dev/null +++ b/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" . }}-service-provider-manager: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/helm/dcm/templates/kubevirt-service-provider.yaml b/helm/dcm/templates/kubevirt-service-provider.yaml new file mode 100644 index 0000000..fd14a53 --- /dev/null +++ b/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" . }}-service-provider-manager: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/helm/dcm/templates/nats.yaml b/helm/dcm/templates/nats.yaml new file mode 100644 index 0000000..49ec225 --- /dev/null +++ b/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/helm/dcm/templates/placement-manager.yaml b/helm/dcm/templates/placement-manager.yaml new file mode 100644 index 0000000..9002a8b --- /dev/null +++ b/helm/dcm/templates/placement-manager.yaml @@ -0,0 +1,57 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dcm.fullname" . }}-placement-manager + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "placement-manager") | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "placement-manager") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "placement-manager") | nindent 8 }} + spec: + initContainers: + {{- include "dcm.waitForPostgres" . | nindent 8 }} + containers: + - name: placement-manager + image: "{{ .Values.placementManager.image }}:{{ include "dcm.imageTag" (dict "tag" .Values.placementManager.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: placement-manager + - name: BIND_ADDRESS + value: ":8080" + - name: POLICY_MANAGER_EVALUATION_URL + value: "http://{{ include "dcm.fullname" . }}-policy-manager:8081" + - name: SP_RESOURCE_MANAGER_URL + value: "http://{{ include "dcm.fullname" . }}-service-provider-manager:8080" +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dcm.fullname" . }}-placement-manager + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + selector: + {{- include "dcm.selectorLabels" (dict "context" . "component" "placement-manager") | nindent 4 }} + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP diff --git a/helm/dcm/templates/policy-manager.yaml b/helm/dcm/templates/policy-manager.yaml new file mode 100644 index 0000000..fd4e13a --- /dev/null +++ b/helm/dcm/templates/policy-manager.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dcm.fullname" . }}-policy-manager + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "policy-manager") | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "policy-manager") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "policy-manager") | nindent 8 }} + spec: + initContainers: + {{- include "dcm.waitForPostgres" . | nindent 8 }} + containers: + - name: policy-manager + image: "{{ .Values.policyManager.image }}:{{ include "dcm.imageTag" (dict "tag" .Values.policyManager.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: policy-manager + - name: BIND_ADDRESS + value: ":8080" + - name: LOG_LEVEL + value: info +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dcm.fullname" . }}-policy-manager + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + selector: + {{- include "dcm.selectorLabels" (dict "context" . "component" "policy-manager") | nindent 4 }} + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP diff --git a/helm/dcm/templates/postgres.yaml b/helm/dcm/templates/postgres.yaml new file mode 100644 index 0000000..4e18d68 --- /dev/null +++ b/helm/dcm/templates/postgres.yaml @@ -0,0 +1,99 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "dcm.fullname" . }}-postgres-init + labels: + {{- include "dcm.labels" . | nindent 4 }} +data: + 01-create-databases.sql: | + CREATE DATABASE "service-provider"; + CREATE DATABASE "policy-manager"; + CREATE DATABASE "catalog-manager"; + CREATE DATABASE "placement-manager"; + 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 + - $(POSTGRES_USER) + - -d + - postgres + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 5 + failureThreshold: 5 + livenessProbe: + exec: + command: + - pg_isready + - -U + - $(POSTGRES_USER) + - -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/helm/dcm/templates/secret-db.yaml b/helm/dcm/templates/secret-db.yaml new file mode 100644 index 0000000..a2f06a4 --- /dev/null +++ b/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/helm/dcm/templates/service-provider-manager.yaml b/helm/dcm/templates/service-provider-manager.yaml new file mode 100644 index 0000000..f226b53 --- /dev/null +++ b/helm/dcm/templates/service-provider-manager.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dcm.fullname" . }}-service-provider-manager + labels: + {{- include "dcm.labels" . | nindent 4 }} + {{- include "dcm.selectorLabels" (dict "context" . "component" "service-provider-manager") | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "service-provider-manager") | nindent 6 }} + template: + metadata: + labels: + {{- include "dcm.selectorLabels" (dict "context" . "component" "service-provider-manager") | nindent 8 }} + spec: + initContainers: + {{- include "dcm.waitForPostgres" . | nindent 8 }} + containers: + - name: service-provider-manager + image: "{{ .Values.serviceProviderManager.image }}:{{ include "dcm.imageTag" (dict "tag" .Values.serviceProviderManager.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: service-provider + - name: SVC_ADDRESS + value: ":8080" + - name: NATS_URL + value: "nats://{{ include "dcm.fullname" . }}-nats:4222" +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dcm.fullname" . }}-service-provider-manager + labels: + {{- include "dcm.labels" . | nindent 4 }} +spec: + selector: + {{- include "dcm.selectorLabels" (dict "context" . "component" "service-provider-manager") | nindent 4 }} + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP diff --git a/helm/dcm/templates/three-tier-demo-service-provider.yaml b/helm/dcm/templates/three-tier-demo-service-provider.yaml new file mode 100644 index 0000000..6c4e9e7 --- /dev/null +++ b/helm/dcm/templates/three-tier-demo-service-provider.yaml @@ -0,0 +1,81 @@ +{{- if .Values.threeTierDemoServiceProvider.enabled }} +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" . }}-service-provider-manager: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" . }}-k8s-container-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/helm/dcm/values.yaml b/helm/dcm/values.yaml new file mode 100644 index 0000000..d24d5cb --- /dev/null +++ b/helm/dcm/values.yaml @@ -0,0 +1,102 @@ +# -- 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 + +# -- Traefik API gateway +gateway: + image: docker.io/traefik:v3.4 + port: 9080 + route: + enabled: true + host: "" # leave empty for auto-generated OpenShift hostname + ingress: + enabled: false + className: "" + host: "" + tls: [] + # - secretName: gateway-tls + # hosts: + # - gateway.example.com + annotations: {} + +# -- Core managers +serviceProviderManager: + image: quay.io/dcm-project/service-provider-manager + tag: "" # defaults to global.imageTag + +catalogManager: + image: quay.io/dcm-project/catalog-manager + tag: "" + +policyManager: + image: quay.io/dcm-project/policy-manager + tag: "" + +placementManager: + image: quay.io/dcm-project/placement-manager + tag: "" + +# -- 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: ""