From 05b7684f3eced4d23091484e5e6fad2257c532af Mon Sep 17 00:00:00 2001 From: Hugo Brito Date: Mon, 17 Mar 2025 18:42:32 -0300 Subject: [PATCH] Create app-distributed-cloud prototype This commit introduces the prototype for the app-distributed-cloud All dcmanager services are being containerized, and the app will utilize Keystone, certmanager, and rabbitmq from the platform. The prototype is in its initial phase, and DC functionalities/services have not yet been thoroughly tested. In this first phase, the subcloud add command is functional. This commit includes the dcmanager and dc-vault helm charts, and a a structure of dcorch, that will be added in a following commit. Before testing the app, the platform must be configured. Refer to the README file for details. Test Plan: PASS: Execute a subcloud add successfully. Story: 2011312 Task: 51841 Change-Id: Ifa6dbbb39d5bdd48eedd06c732d24d26a48f6ae8 Co-Authored-By: Matt Peters Co-Authored-By: Enzo Candotti Co-Authored-By: Yuxing Jiang Signed-off-by: Hugo Brito --- HACKING.rst | 17 + README.md | 437 ++++++++++++++++ bindep.txt | 10 + debian_iso_image.inc | 1 + debian_pkg_dirs | 2 + debian_stable_docker_images.inc | 1 + .../debian/deb_folder/changelog | 5 + .../debian/deb_folder/control | 27 + .../debian/deb_folder/copyright | 41 ++ ...n3-k8sapp-distributed-cloud-wheels.install | 1 + .../python3-k8sapp-distributed-cloud.install | 1 + .../debian/deb_folder/rules | 31 ++ .../debian/deb_folder/source/format | 1 + .../debian/meta_data.yaml | 6 + .../k8sapp_distributed_cloud/.gitignore | 35 ++ .../k8sapp_distributed_cloud/.stestr.conf | 4 + .../k8sapp_distributed_cloud/LICENSE | 202 ++++++++ .../k8sapp_distributed_cloud/README.rst | 7 + .../k8sapp_distributed_cloud/__init__.py | 0 .../common/__init__.py | 0 .../common/constants.py | 29 ++ .../k8sapp_distributed_cloud/helm/__init__.py | 0 .../k8sapp_distributed_cloud/helm/base.py | 163 ++++++ .../helm/dcmanager.py | 20 + .../k8sapp_distributed_cloud/helm/dcorch.py | 20 + .../lifecycle/__init__.py | 0 .../lifecycle/lifecycle_distributed_cloud.py | 50 ++ .../tests/__init__.py | 0 .../tests/test_distributed_cloud.py | 28 + .../tests/test_plugins.py | 45 ++ .../k8sapp_distributed_cloud/pylint.rc | 234 +++++++++ .../k8sapp_distributed_cloud/requirements.txt | 2 + .../k8sapp_distributed_cloud/setup.cfg | 40 ++ .../k8sapp_distributed_cloud/setup.py | 12 + .../test-requirements.txt | 20 + .../k8sapp_distributed_cloud/tox.ini | 88 ++++ .../upper-constraints.txt | 1 + .../debian/deb_folder/changelog | 5 + .../debian/deb_folder/control | 21 + .../debian/deb_folder/copyright | 41 ++ .../debian/deb_folder/rules | 57 +++ .../debian/deb_folder/source/format | 1 + .../stx-distributed-cloud-helm.install | 1 + .../debian/meta_data.yaml | 6 + .../files/metadata.yaml | 23 + .../fluxcd-manifests/base/helmrepository.yaml | 13 + .../fluxcd-manifests/base/kustomization.yaml | 8 + .../fluxcd-manifests/base/namespace.yaml | 10 + .../dc-vault-nginx-static-overrides.yaml | 16 + .../dc-vault-nginx-system-overrides.yaml | 5 + .../dc-vault-nginx/helmrelease.yaml | 36 ++ .../dc-vault-nginx/kustomization.yaml | 18 + .../dcmanager/dcmanager-static-overrides.yaml | 33 ++ .../dcmanager/dcmanager-system-overrides.yaml | 5 + .../dcmanager/helmrelease.yaml | 36 ++ .../dcmanager/kustomization.yaml | 18 + .../dcorch/dcorch-static-overrides.yaml | 33 ++ .../dcorch/dcorch-system-overrides.yaml | 5 + .../fluxcd-manifests/dcorch/helmrelease.yaml | 36 ++ .../dcorch/kustomization.yaml | 18 + .../fluxcd-manifests/kustomization.yaml | 14 + .../helm-charts/.gitignore | 2 + .../helm-charts/Makefile | 42 ++ .../helm-charts/dc-vault-nginx/.helmignore | 23 + .../helm-charts/dc-vault-nginx/Chart.yaml | 9 + .../charts/helm-toolkit-0.2.59.tgz | Bin 0 -> 52002 bytes .../dc-vault-nginx/templates/_helpers.tpl | 20 + .../dc-vault-nginx/templates/configmap.yaml | 27 + .../dc-vault-nginx/templates/deployment.yaml | 61 +++ .../dc-vault-nginx/templates/ingress.yaml | 31 ++ .../dc-vault-nginx/templates/pvc.yaml | 62 +++ .../dc-vault-nginx/templates/service.yaml | 23 + .../helm-charts/dc-vault-nginx/values.yaml | 69 +++ .../helm-charts/dcmanager/.helmignore | 23 + .../helm-charts/dcmanager/Chart.yaml | 29 ++ .../dcmanager/charts/helm-toolkit-0.2.59.tgz | Bin 0 -> 52000 bytes .../dcmanager/templates/_helpers.tpl | 62 +++ .../dcmanager/templates/bin/_db-drop.sh.tpl | 11 + .../dcmanager/templates/bin/_db-sync.sh.tpl | 11 + .../templates/bin/_dcmanager-api.sh.tpl | 16 + .../bin/_dcmanager-audit-worker.sh.tpl | 16 + .../templates/bin/_dcmanager-audit.sh.tpl | 16 + .../templates/bin/_dcmanager-manager.sh.tpl | 17 + .../bin/_dcmanager-orchestrator.sh.tpl | 11 + .../templates/bin/_dcmanager-state.sh.tpl | 11 + .../dcmanager/templates/configmap-bin.yaml | 37 ++ .../dcmanager/templates/deployment-api.yaml | 156 ++++++ .../templates/deployment-audit-worker.yaml | 96 ++++ .../dcmanager/templates/deployment-audit.yaml | 138 +++++ .../templates/deployment-manager.yaml | 162 ++++++ .../templates/deployment-orchestrator.yaml | 84 +++ .../dcmanager/templates/deployment-state.yaml | 84 +++ .../dcmanager/templates/ingress.yaml | 61 +++ .../dcmanager/templates/job-db-drop.yaml | 13 + .../dcmanager/templates/job-db-init.yaml | 13 + .../dcmanager/templates/job-db-sync.yaml | 13 + .../dcmanager/templates/job-ks-endpoints.yaml | 16 + .../dcmanager/templates/job-ks-service.yaml | 16 + .../dcmanager/templates/job-ks-user.yaml | 16 + .../dcmanager/templates/pvc-backup.yaml | 19 + .../dcmanager/templates/pvc-vault.yaml | 19 + .../dcmanager/templates/secret-db.yaml | 21 + .../dcmanager/templates/secret-etc.yaml | 72 +++ .../dcmanager/templates/secret-keystone.yaml | 20 + .../dcmanager/templates/secret-rabbitmq.yaml | 20 + .../dcmanager/templates/service.yaml | 29 ++ .../helm-charts/dcmanager/values.yaml | 479 ++++++++++++++++++ .../helm-charts/dcorch/.helmignore | 23 + .../helm-charts/dcorch/Chart.yaml | 29 ++ .../dcorch/charts/helm-toolkit-0.2.59.tgz | Bin 0 -> 52000 bytes .../helm-charts/dcorch/templates/_helpers.tpl | 62 +++ .../helm-charts/dcorch/values.yaml | 96 ++++ .../stx-distributed-cloud.stable_docker_image | 62 +++ tox.ini | 10 - 114 files changed, 4488 insertions(+), 10 deletions(-) create mode 100644 HACKING.rst create mode 100644 README.md create mode 100644 bindep.txt create mode 100644 debian_iso_image.inc create mode 100644 debian_pkg_dirs create mode 100644 debian_stable_docker_images.inc create mode 100644 python3-k8sapp-distributed-cloud/debian/deb_folder/changelog create mode 100644 python3-k8sapp-distributed-cloud/debian/deb_folder/control create mode 100644 python3-k8sapp-distributed-cloud/debian/deb_folder/copyright create mode 100644 python3-k8sapp-distributed-cloud/debian/deb_folder/python3-k8sapp-distributed-cloud-wheels.install create mode 100644 python3-k8sapp-distributed-cloud/debian/deb_folder/python3-k8sapp-distributed-cloud.install create mode 100755 python3-k8sapp-distributed-cloud/debian/deb_folder/rules create mode 100644 python3-k8sapp-distributed-cloud/debian/deb_folder/source/format create mode 100644 python3-k8sapp-distributed-cloud/debian/meta_data.yaml create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/.gitignore create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/.stestr.conf create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/LICENSE create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/README.rst create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/__init__.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/common/__init__.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/common/constants.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/__init__.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/base.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/dcmanager.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/dcorch.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/lifecycle/__init__.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/lifecycle/lifecycle_distributed_cloud.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/tests/__init__.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/tests/test_distributed_cloud.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/tests/test_plugins.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/pylint.rc create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/requirements.txt create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/setup.cfg create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/setup.py create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/test-requirements.txt create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/tox.ini create mode 100644 python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/upper-constraints.txt create mode 100644 stx-distributed-cloud-helm/debian/deb_folder/changelog create mode 100644 stx-distributed-cloud-helm/debian/deb_folder/control create mode 100644 stx-distributed-cloud-helm/debian/deb_folder/copyright create mode 100644 stx-distributed-cloud-helm/debian/deb_folder/rules create mode 100644 stx-distributed-cloud-helm/debian/deb_folder/source/format create mode 100644 stx-distributed-cloud-helm/debian/deb_folder/stx-distributed-cloud-helm.install create mode 100644 stx-distributed-cloud-helm/debian/meta_data.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/files/metadata.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/base/helmrepository.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/base/kustomization.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/base/namespace.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/dc-vault-nginx-static-overrides.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/dc-vault-nginx-system-overrides.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/helmrelease.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/kustomization.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/dcmanager-static-overrides.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/dcmanager-system-overrides.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/helmrelease.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/kustomization.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/dcorch-static-overrides.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/dcorch-system-overrides.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/helmrelease.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/kustomization.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/kustomization.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/.gitignore create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/Makefile create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/.helmignore create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/Chart.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/charts/helm-toolkit-0.2.59.tgz create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/templates/_helpers.tpl create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/templates/configmap.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/templates/deployment.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/templates/ingress.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/templates/pvc.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/templates/service.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/values.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/.helmignore create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/Chart.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/charts/helm-toolkit-0.2.59.tgz create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/_helpers.tpl create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_db-drop.sh.tpl create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_db-sync.sh.tpl create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-api.sh.tpl create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-audit-worker.sh.tpl create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-audit.sh.tpl create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-manager.sh.tpl create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-orchestrator.sh.tpl create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-state.sh.tpl create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/configmap-bin.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-api.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-audit-worker.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-audit.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-manager.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-orchestrator.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-state.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/ingress.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-db-drop.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-db-init.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-db-sync.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-ks-endpoints.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-ks-service.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-ks-user.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/pvc-backup.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/pvc-vault.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-db.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-etc.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-keystone.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-rabbitmq.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/service.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/values.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/.helmignore create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/Chart.yaml create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/charts/helm-toolkit-0.2.59.tgz create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/templates/_helpers.tpl create mode 100644 stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/values.yaml create mode 100644 stx-distributed-cloud-images/debian/stx-distributed-cloud.stable_docker_image diff --git a/HACKING.rst b/HACKING.rst new file mode 100644 index 0000000..c4ad70e --- /dev/null +++ b/HACKING.rst @@ -0,0 +1,17 @@ +StarlingX app-distributed-cloud Style Commandments +================================================== + +- Step 1: Read the OpenStack style commandments + https://docs.openstack.org/hacking/latest/ +- Step 2: Read on + +app-distributed-cloud Specific Commandments +------------------------------------------- + +None so far + +Running tests +------------- +The approach to running tests is to simply run the command ``tox``. This will +create virtual environments, populate them with dependencies and run all of +the tests that OpenStack CI systems run. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9cc44fc --- /dev/null +++ b/README.md @@ -0,0 +1,437 @@ +# app-distributed-cloud (Prototype) + +This tutorial provides a step-by-step guide on containerizing DC Services using the +app-distributed-cloud prototype. + +> **Note:** All dcmanager operations are not fully tested or operational. + +## Disable Service Management + +Disable the dcmanager services on the platform + +```bash +source /etc/platform/openrc + +sudo sm-unmanage service dcmanager-manager +sudo sm-unmanage service dcmanager-api +sudo sm-unmanage service dcmanager-audit +sudo sm-unmanage service dcmanager-audit-worker +sudo sm-unmanage service dcmanager-orchestrator +sudo sm-unmanage service dcmanager-state + +sudo sm-unmanage service dcorch-engine +sudo sm-unmanage service dcorch-engine-worker +sudo sm-unmanage service dcorch-sysinv-api-proxy +sudo sm-unmanage service dcorch-patch-api-proxy +sudo sm-unmanage service dcorch-identity-api-proxy + +sudo sm-unmanage service dcdbsync-api + + +sudo pkill -f ^".*/bin/dcmanager.*" +sudo pkill -f ^".*/bin/dcorch.*" +sudo pkill -f ^".*/bin/dcdbsync.*" +``` + +## Platform Setup + +```bash +system host-label-assign controller-0 starlingx.io/distributed-cloud=enabled +system host-label-assign controller-1 starlingx.io/distributed-cloud=enabled +``` + +> **Note:** If you have issues with downloading the nginx image for dc-vault-nginx, + assign the distributed-cloud label just for the controller-0 + +## Create the namespace and root-ca secret + +```bash +# Create distributed-cloud namespace + +kubectl create namespace distributed-cloud + +# Create system-local-ca secret + +cp /etc/ssl/certs/dc-adminep-root-ca.pem /home/sysadmin/root-ca.pem + +kubectl -n distributed-cloud create secret generic root-ca --from-file=ca.crt=/home/sysadmin/root-ca.pem +``` + +## Distributed Cloud Application Deployment (development) + +```bash +# Configure Docker Image +# Create or download the docker image used for the dcmanager pods +DOCKER_IMAGE=registry.local:9001/docker.io/starlingx/stx-distributed-cloud:master-debian-stable-latest + +sudo docker login registry.local:9001 + +sudo docker image pull +sudo docker image tag ${DOCKER_IMAGE} +sudo docker image push ${DOCKER_IMAGE} + +# Upload the prototype +system application-upload /usr/local/share/applications/helm/distributed-cloud-25.09-0.tgz +``` + +```bash +# Set Password Variables +ADMIN_KS_PASSWORD=$(keyring get CGCS admin) +RABBITMQ_PASSWORD=$(keyring get amqp rabbit) +DCMANAGER_DB_PASSWORD=$(keyring get dcmanager database) +DCMANAGER_KS_PASSWORD=$(keyring get dcmanager services) +DCORCH_DB_PASSWORD=$(keyring get dcorch database) +DCORCH_KS_PASSWORD=$(keyring get dcorch services) + +# Create dcmanager and dcorch overrides +cat<dcmanager.yaml +images: + tags: + dcmanager: ${DOCKER_IMAGE} + ks_user: ${DOCKER_IMAGE} + ks_service: ${DOCKER_IMAGE} + ks_endpoints: ${DOCKER_IMAGE} + dcmanager_db_sync: ${DOCKER_IMAGE} + db_init: ${DOCKER_IMAGE} + db_drop: ${DOCKER_IMAGE} + pullPolicy: Always +pod: + image_pull_secrets: + default: + - name: default-registry-key + tolerations: + dcmanager: + enabled: true +conf: + dcmanager: + DEFAULT: + log_config_append: /etc/dcmanager/logging.conf + transport_url: rabbit://guest:${RABBITMQ_PASSWORD}@controller.internal:5672 + auth_strategy: keystone + playbook_timeout: 3600 + use_usm: False + workers: 1 + orch_workers: 1 + state_workers: 1 + audit_workers: 1 + audit_worker_workers: 1 + cache: + auth_uri: http://controller.internal:5000/v3 + admin_tenant: admin + admin_username: admin + admin_password: ${ADMIN_KS_PASSWORD} + endpoint_cache: + auth_uri: http://controller.internal:5000/v3 + auth_plugin: password + username: dcmanager + password: ${DCMANAGER_KS_PASSWORD} + project_name: services + user_domain_name: Default + project_domain_name: Default + http_connect_timeout: 15 + database: + connection_recycle_time: 3600 + max_pool_size: 105 + max_overflow: 100 + keystone_authtoken: + auth_version: v3 + auth_type: password +dependencies: + static: + api: + jobs: + - dcmanager-ks-user + - dcmanager-ks-service + - dcmanager-ks-endpoints + ks_endpoints: + jobs: + - dcmanager-ks-user + - dcmanager-ks-service +endpoints: + cluster_domain_suffix: cluster.local + oslo_db: + auth: + admin: + username: admin-dcmanager + password: ${DCMANAGER_DB_PASSWORD} + dcmanager: + username: admin-dcmanager + password: ${DCMANAGER_DB_PASSWORD} + hosts: + default: postgresql + host_fqdn_override: + default: controller.internal + port: + postgresql: + default: 5432 + path: /dcmanager + scheme: postgresql+psycopg2 + oslo_messaging: + auth: + admin: + username: guest + password: ${RABBITMQ_PASSWORD} + dcmanager: + username: guest + password: ${RABBITMQ_PASSWORD} + hosts: + default: rabbitmq + host_fqdn_override: + default: controller.internal + path: / + scheme: rabbit + port: + amqp: + default: 5672 + http: + default: 15672 + identity: + name: keystone + auth: + admin: + username: admin + password: ${ADMIN_KS_PASSWORD} + region_name: RegionOne + project_name: admin + user_domain_name: Default + project_domain_name: Default + dcmanager: + role: admin + username: dcmanager + password: ${DCMANAGER_KS_PASSWORD} + region_name: RegionOne + project_name: services + user_domain_name: Default + project_domain_name: Default + hosts: + default: keystone-api + public: keystone + host_fqdn_override: + default: controller.internal + path: + default: /v3 + scheme: + default: http + port: + api: + default: 80 + internal: 5000 + dcmanager: + name: dcmanager + hosts: + default: dcmanager-api + public: dcmanager + host_fqdn_override: + default: null + path: + default: /v1.0 + scheme: + default: 'http' + port: + api: + default: 8119 + public: 80 +EOF + +cat<dcorch.yaml +images: + tags: + dcorch: ${DOCKER_IMAGE} + ks_user: ${DOCKER_IMAGE} + ks_service: ${DOCKER_IMAGE} + ks_endpoints: ${DOCKER_IMAGE} + dcorch_db_sync: ${DOCKER_IMAGE} + db_init: ${DOCKER_IMAGE} + db_drop: ${DOCKER_IMAGE} + pullPolicy: Always +pod: + image_pull_secrets: + default: + - name: default-registry-key + tolerations: + dcorch: + enabled: true + replicas: + dcorch_engine_worker: 1 + dcorch_sysinv_api_proxy: 1 + keystone_api_proxy: 1 + dcorch_patch_api_proxy: 1 + dcorch_usm_api_proxy: 1 +conf: + dcorch: + DEFAULT: + log_config_append: /etc/dcorch/logging.conf + transport_url: rabbit://guest:${RABBITMQ_PASSWORD}@controller.internal:5672 + auth_strategy: keystone + playbook_timeout: 3600 + use_usm: False + endpoint_cache: + password: ${DCMANAGER_KS_PASSWORD} + database: + connection_recycle_time: 3600 + max_pool_size: 105 + max_overflow: 100 + keystone_authtoken: + auth_version: v3 + auth_type: password +dependencies: + static: + api: + jobs: + - dcorch-ks-user + - dcorch-ks-service + - dcorch-ks-endpoints + ks_endpoints: + jobs: + - dcorch-ks-user + - dcorch-ks-service + +endpoints: + cluster_domain_suffix: cluster.local + oslo_db: + auth: + admin: + username: admin-dcorch + password: ${DCORCH_DB_PASSWORD} + dcorch: + username: admin-dcorch + password: ${DCORCH_DB_PASSWORD} + dcmanager: + username: admin-dcmanager + password: ${DCMANAGER_DB_PASSWORD} + hosts: + default: postgresql + host_fqdn_override: + default: controller.internal + port: + postgresql: + default: 5432 + path: /dcorch + scheme: postgresql+psycopg2 + oslo_messaging: + auth: + admin: + username: guest + password: ${RABBITMQ_PASSWORD} + dcmanager: + username: guest + password: ${RABBITMQ_PASSWORD} + hosts: + default: rabbitmq + host_fqdn_override: + default: controller.internal + path: / + scheme: rabbit + port: + amqp: + default: 5672 + http: + default: 15672 + identity: + name: keystone + auth: + admin: + username: admin + password: ${ADMIN_KS_PASSWORD} + region_name: RegionOne + project_name: admin + user_domain_name: Default + project_domain_name: Default + dcorch: + role: admin + username: dcorch + password: ${DCORCH_KS_PASSWORD} + region_name: RegionOne + project_name: services + user_domain_name: Default + project_domain_name: Default + hosts: + default: keystone-api + public: keystone + host_fqdn_override: + default: controller.internal + path: + default: /v3 + scheme: + default: http + port: + api: + default: 80 + internal: 5000 + dcorch: + name: dcorch + hosts: + default: dcorch-api + public: dcorch + host_fqdn_override: + default: null + path: + default: /v1.0 + scheme: + default: 'http' + port: + api: + default: 8118 + public: 80 +EOF +``` + +```bash +system helm-override-update distributed-cloud dcmanager distributed-cloud --values dcmanager.yaml +system helm-override-update distributed-cloud dcorch distributed-cloud --values dcorch.yaml + +system helm-override-show distributed-cloud dcmanager distributed-cloud +system helm-override-show distributed-cloud dcorch distributed-cloud +``` + +## Apply app-distributed-cloud + +```bash +system application-apply distributed-cloud +system application-show distributed-cloud +``` + +## To remove + +```bash +system application-remove distributed-cloud +system application-delete distributed-cloud +``` + +## Check dcmanager endpoints + +```bash +openstack endpoint list | grep dcmanager +``` + +## Check if dcmanager-api endpoint works + +```bash +kubectl get svc dcmanager-api -n distributed-cloud +kubectl get endpoints dcmanager-api -n distributed-cloud + +# Get Token +openstack token issue + +curl -i http:///v1.0/subclouds -X GET -H "Content-Type: application/json" -H "Accept: application/json" -H "X-Auth-Token:${TOKEN}" +``` + +## Configure dcmanager-client + +Edit file: /usr/lib/python3/dist-packages/dcmanagerclient/api/v1/client.py + +```python +_DEFAULT_DCMANAGER_URL = ( + "http://dcmanager-api.distributed-cloud.svc.cluster.local:8119/v1.0" +) + +# delete if not dcmanager_url: to always set default +dcmanager_url = _DEFAULT_DCMANAGER_URL +``` + +## Check dcmanager-manager is working + +```bash +dcmanager subcloud-group add --name test +dcmanager subcloud update --group 2 subcloud2-stx-latest +``` diff --git a/bindep.txt b/bindep.txt new file mode 100644 index 0000000..3ffe69f --- /dev/null +++ b/bindep.txt @@ -0,0 +1,10 @@ +# This is a cross-platform list tracking distribution packages needed for install and tests; +# see https://docs.openstack.org/infra/bindep/ for additional information. + +libffi-dev [platform:dpkg] +libldap2-dev [platform:dpkg] +libxml2-dev [platform:dpkg] +libxslt1-dev [platform:dpkg] +libsasl2-dev [platform:dpkg] +libffi-devel [platform:rpm] +python3-all-dev [platform:dpkg] diff --git a/debian_iso_image.inc b/debian_iso_image.inc new file mode 100644 index 0000000..32ba25a --- /dev/null +++ b/debian_iso_image.inc @@ -0,0 +1 @@ +stx-distributed-cloud-helm diff --git a/debian_pkg_dirs b/debian_pkg_dirs new file mode 100644 index 0000000..1e8a802 --- /dev/null +++ b/debian_pkg_dirs @@ -0,0 +1,2 @@ +python3-k8sapp-distributed-cloud +stx-distributed-cloud-helm diff --git a/debian_stable_docker_images.inc b/debian_stable_docker_images.inc new file mode 100644 index 0000000..a3b3594 --- /dev/null +++ b/debian_stable_docker_images.inc @@ -0,0 +1 @@ +stx-distributed-cloud-images diff --git a/python3-k8sapp-distributed-cloud/debian/deb_folder/changelog b/python3-k8sapp-distributed-cloud/debian/deb_folder/changelog new file mode 100644 index 0000000..81eae65 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/debian/deb_folder/changelog @@ -0,0 +1,5 @@ +python3-k8sapp-distributed-cloud (1.0-0) unstable; urgency=medium + + * Initial release. + + -- Hugo Brito Tue, 25 Mar 2025 00:00:00 +0000 diff --git a/python3-k8sapp-distributed-cloud/debian/deb_folder/control b/python3-k8sapp-distributed-cloud/debian/deb_folder/control new file mode 100644 index 0000000..aa4e730 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/debian/deb_folder/control @@ -0,0 +1,27 @@ +Source: python3-k8sapp-distributed-cloud +Section: libs +Priority: optional +Maintainer: StarlingX Developers +Build-Depends: debhelper-compat (= 13), + dh-python, + python3-all, + python3-pbr, + python3-setuptools, + python3-wheel, + build-info +Standards-Version: 4.5.1 +Homepage: https://www.starlingx.io + +Package: python3-k8sapp-distributed-cloud +Section: libs +Architecture: any +Depends: ${misc:Depends}, ${python3:Depends} +Description: StarlingX Sysinv Distributed Cloud Extensions + This package contains sysinv plugins for the Distributed Cloud K8S app. + +Package: python3-k8sapp-distributed-cloud-wheels +Section: libs +Architecture: any +Depends: ${misc:Depends}, ${python3:Depends}, python3-wheel +Description: StarlingX Sysinv Distributed Cloud Extension Wheels + This package contains python wheels for the Distributed Cloud K8S app plugins. diff --git a/python3-k8sapp-distributed-cloud/debian/deb_folder/copyright b/python3-k8sapp-distributed-cloud/debian/deb_folder/copyright new file mode 100644 index 0000000..c6cf43a --- /dev/null +++ b/python3-k8sapp-distributed-cloud/debian/deb_folder/copyright @@ -0,0 +1,41 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: python3-k8sapp-distributed-cloud +Source: https://opendev.org/starlingx/app-distributed-cloud/ + +Files: * +Copyright: (c) 2025 Wind River Systems, Inc +License: Apache-2 + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + https://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + . + On Debian-based systems the full text of the Apache version 2.0 license + can be found in `/usr/share/common-licenses/Apache-2.0'. + +# If you want to use GPL v2 or later for the /debian/* files use +# the following clauses, or change it to suit. Delete these two lines +Files: debian/* +Copyright: 2025 Wind River Systems, Inc +License: Apache-2 + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + https://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + . + On Debian-based systems the full text of the Apache version 2.0 license + can be found in `/usr/share/common-licenses/Apache-2.0'. diff --git a/python3-k8sapp-distributed-cloud/debian/deb_folder/python3-k8sapp-distributed-cloud-wheels.install b/python3-k8sapp-distributed-cloud/debian/deb_folder/python3-k8sapp-distributed-cloud-wheels.install new file mode 100644 index 0000000..19a9e4c --- /dev/null +++ b/python3-k8sapp-distributed-cloud/debian/deb_folder/python3-k8sapp-distributed-cloud-wheels.install @@ -0,0 +1 @@ +plugins/*.whl diff --git a/python3-k8sapp-distributed-cloud/debian/deb_folder/python3-k8sapp-distributed-cloud.install b/python3-k8sapp-distributed-cloud/debian/deb_folder/python3-k8sapp-distributed-cloud.install new file mode 100644 index 0000000..91d1d9d --- /dev/null +++ b/python3-k8sapp-distributed-cloud/debian/deb_folder/python3-k8sapp-distributed-cloud.install @@ -0,0 +1 @@ +usr/lib/python3/dist-packages/k8sapp_* diff --git a/python3-k8sapp-distributed-cloud/debian/deb_folder/rules b/python3-k8sapp-distributed-cloud/debian/deb_folder/rules new file mode 100755 index 0000000..b094486 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/debian/deb_folder/rules @@ -0,0 +1,31 @@ +#!/usr/bin/make -f +# export DH_VERBOSE = 1 + +export APP_NAME = distributed-cloud +export PYBUILD_NAME = k8sapp-distributed-cloud + +export DEB_VERSION = $(shell dpkg-parsechangelog | egrep '^Version:' | cut -f 2 -d ' ') +export MAJOR = $(shell cat /etc/build.info | grep SW_VERSION | cut -d'"' -f2) +export MINOR_PATCH = $(shell echo $(DEB_VERSION) | cut -f 4 -d '.') +export PBR_VERSION = $(MAJOR).$(MINOR_PATCH) + +export ROOT = $(CURDIR)/debian/tmp +export SKIP_PIP_INSTALL = 1 + +%: + dh $@ --with=python3 --buildsystem=pybuild + +override_dh_auto_install: + python3 setup.py install \ + --install-layout=deb \ + --root $(ROOT) + + python3 setup.py bdist_wheel \ + --universal \ + -d $(ROOT)/plugins + +override_dh_python3: + dh_python3 --shebang=/usr/bin/python3 + +override_dh_auto_test: + PYTHONDIR=$(CURDIR) stestr run diff --git a/python3-k8sapp-distributed-cloud/debian/deb_folder/source/format b/python3-k8sapp-distributed-cloud/debian/deb_folder/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/debian/deb_folder/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/python3-k8sapp-distributed-cloud/debian/meta_data.yaml b/python3-k8sapp-distributed-cloud/debian/meta_data.yaml new file mode 100644 index 0000000..faabfc4 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/debian/meta_data.yaml @@ -0,0 +1,6 @@ +--- +debname: python3-k8sapp-distributed-cloud +debver: 1.0-0 +src_path: k8sapp_distributed_cloud +revision: + dist: $STX_DIST diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/.gitignore b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/.gitignore new file mode 100644 index 0000000..78c457c --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/.gitignore @@ -0,0 +1,35 @@ +# Compiled files +*.py[co] +*.a +*.o +*.so + +# Sphinx +_build +doc/source/api/ + +# Packages/installer info +*.egg +*.egg-info +dist +build +eggs +parts +var +sdist +develop-eggs +.installed.cfg + +# Other +*.DS_Store +.stestr +.testrepository +.tox +.venv +.*.swp +.coverage +bandit.xml +cover +AUTHORS +ChangeLog +*.sqlite diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/.stestr.conf b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/.stestr.conf new file mode 100644 index 0000000..464dc69 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/.stestr.conf @@ -0,0 +1,4 @@ +[DEFAULT] +test_path=./k8sapp_distributed_cloud/tests +top_dir=./k8sapp_distributed_cloud +#parallel_class=True diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/LICENSE b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/LICENSE new file mode 100644 index 0000000..d6e2801 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Wind River Systems, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/README.rst b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/README.rst new file mode 100644 index 0000000..6018cb6 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/README.rst @@ -0,0 +1,7 @@ +k8sapp-distributed-cloud +======================== + +This project contains StarlingX Kubernetes application specific python plugins +for Distributed Cloud. These plugins are required to integrate the Distributed Cloud +application into the StarlingX application framework and to support the +various StarlingX deployments. diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/__init__.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/common/__init__.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/common/constants.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/common/constants.py new file mode 100644 index 0000000..194a0ee --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/common/constants.py @@ -0,0 +1,29 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Helm: Supported charts: +# These values match the names in the chart package's Chart.yaml +HELM_CHART_DCMANAGER = 'dcmanager' +HELM_CHART_DCORCH = 'dcorch' + +# FluxCD +FLUXCD_HELM_RELEASE_DCMANAGER = 'dcmanager' +FLUXCD_HELM_RELEASE_DCORCH = 'dcorch' + +# Namespace to deploy the application +HELM_NS_DISTCLOUD = 'distributed-cloud' + +# Application Name +HELM_APP_DISTCLOUD = 'distributed-cloud' + +# Application Services +HELM_SERVICE_DCMANAGER_API = "dcmanager-api" + +# Application component label +HELM_LABEL_PARAMETER = 'labels' +HELM_COMPONENT_LABEL = 'app.starlingx.io/component' +HELM_COMPONENT_LABEL_VALUE_PLATFORM = 'platform' +HELM_COMPONENT_LABEL_VALUE_APPLICATION = 'application' diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/__init__.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/base.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/base.py new file mode 100644 index 0000000..9786a16 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/base.py @@ -0,0 +1,163 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import keyring +import yaml + +from oslo_log import log as logging + +from sysinv.common import exception +from sysinv.db import api as dbapi +from sysinv.helm import base + + +from k8sapp_distributed_cloud.common import constants as app_constants + +LOG = logging.getLogger(__name__) + + +class DistributedCloudHelm(base.FluxCDBaseHelm): + """Class to encapsulate helm operations for the Distributed Cloud charts""" + + SUPPORTED_NAMESPACES = base.FluxCDBaseHelm.SUPPORTED_NAMESPACES + \ + [app_constants.HELM_NS_DISTCLOUD] + + SUPPORTED_APP_NAMESPACES = { + app_constants.HELM_APP_DISTCLOUD: SUPPORTED_NAMESPACES, + } + + SERVICE_NAME = app_constants.HELM_APP_DISTCLOUD + + SUPPORTED_COMPONENT_OVERRIDES = [ + app_constants.HELM_COMPONENT_LABEL_VALUE_PLATFORM, + app_constants.HELM_COMPONENT_LABEL_VALUE_APPLICATION + ] + + DEFAULT_AFFINITY = app_constants.HELM_COMPONENT_LABEL_VALUE_PLATFORM + + KEYRING_SERVICE_ADMIN = 'CGCS' + KEYRING_SERVICE_AMQP = 'amqp' + + KEYRING_USER_DATABASE = 'database' + KEYRING_USER_SERVICES = 'services' + KEYRING_USER_ADMIN = 'admin' + KEYRING_USER_AMQP = 'rabbit' + + @property + def CHART(self): + raise NotImplemented("CHART property not implemented") + + @property + def HELM_RELEASE(self): + raise NotImplemented("HELM_RELEASE property not implemented") + + def get_namespaces(self): + return self.SUPPORTED_NAMESPACES + + def get_overrides(self, namespace=None): + dbapi_instance = dbapi.get_instance() + db_app = dbapi_instance.kube_app_get(app_constants.HELM_APP_DISTCLOUD) + + # User chart overrides + chart_overrides = self._get_helm_overrides( + dbapi_instance, + db_app, + self.CHART, + app_constants.HELM_NS_DISTCLOUD, + 'user_overrides') + + user_affinity = chart_overrides.get(app_constants.HELM_COMPONENT_LABEL, + self.DEFAULT_AFFINITY) + + if user_affinity in self.SUPPORTED_COMPONENT_OVERRIDES: + affinity = user_affinity + else: + LOG.warn(f"User override value {user_affinity} " + f"for {app_constants.HELM_COMPONENT_LABEL} is invalid, " + f"using default value {self.DEFAULT_AFFINITY}") + affinity = self.DEFAULT_AFFINITY + + overrides = { + app_constants.HELM_NS_DISTCLOUD: { + app_constants.HELM_LABEL_PARAMETER: { + app_constants.HELM_COMPONENT_LABEL: affinity + }, + "endpoints": self._get_endpoint_overrides() + } + } + + if namespace in self.SUPPORTED_NAMESPACES: + return overrides[namespace] + + if namespace: + raise exception.InvalidHelmNamespace(chart=self.CHART, + namespace=namespace) + return overrides + + @staticmethod + def _get_helm_overrides(dbapi_instance, app, chart, namespace, + type_of_overrides): + """Helper function for querying helm overrides from db.""" + helm_overrides = {} + try: + overrides = dbapi_instance.helm_override_get( + app_id=app.id, + name=chart, + namespace=namespace, + )[type_of_overrides] + + if isinstance(overrides, str): + helm_overrides = yaml.safe_load(overrides) + except exception.HelmOverrideNotFound: + LOG.debug("Overrides for this chart not found, nothing to be done.") + return helm_overrides + + def _get_endpoint_overrides(self): + """Get common endpoint helm overrides""" + + admin_ks_password=keyring.get_password(self.KEYRING_SERVICE_ADMIN, + self.KEYRING_USER_ADMIN) + rabbitmq_password=keyring.get_password(self.KEYRING_SERVICE_AMQP, + self.KEYRING_USER_AMQP) + service_db_password=keyring.get_password(self.CHART, + self.KEYRING_USER_DATABASE) + service_ks_password=keyring.get_password(self.CHART, + self.KEYRING_USER_SERVICES) + + endpoints = { + "oslo_db": { + "auth": { + "admin": { + "password": service_db_password, + }, + self.CHART: { + "password": service_db_password, + } + } + }, + "oslo_messaging": { + "auth": { + "admin": { + "password": rabbitmq_password, + }, + self.CHART: { + "password": rabbitmq_password, + } + } + }, + "identity": { + "auth": { + "admin": { + "password": admin_ks_password, + }, + self.CHART: { + "password": service_ks_password, + } + } + } + } + + return endpoints \ No newline at end of file diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/dcmanager.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/dcmanager.py new file mode 100644 index 0000000..6531d21 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/dcmanager.py @@ -0,0 +1,20 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +from . import base + +from k8sapp_distributed_cloud.common import constants as app_constants + + +class DCManagerHelm(base.DistributedCloudHelm): + + @property + def CHART(self): + return app_constants.HELM_CHART_DCMANAGER + + @property + def HELM_RELEASE(self): + return app_constants.FLUXCD_HELM_RELEASE_DCMANAGER diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/dcorch.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/dcorch.py new file mode 100644 index 0000000..0c7aa0b --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/helm/dcorch.py @@ -0,0 +1,20 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +from . import base + +from k8sapp_distributed_cloud.common import constants as app_constants + + +class DCOrchHelm(base.DistributedCloudHelm): + + @property + def CHART(self): + return app_constants.HELM_CHART_DCORCH + + @property + def HELM_RELEASE(self): + return app_constants.FLUXCD_HELM_RELEASE_DCORCH diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/lifecycle/__init__.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/lifecycle/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/lifecycle/lifecycle_distributed_cloud.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/lifecycle/lifecycle_distributed_cloud.py new file mode 100644 index 0000000..6e61252 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/lifecycle/lifecycle_distributed_cloud.py @@ -0,0 +1,50 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# All Rights Reserved. +# + +""" System Inventory App lifecycle operator.""" + +from oslo_log import log as logging + +from sysinv.common import constants as c +from sysinv.helm import lifecycle_base as base +from sysinv.helm import lifecycle_utils + +from k8sapp_distributed_cloud.common import constants as app_constants + +LOG = logging.getLogger(__name__) + + +class DistributedCloudAppLifecycleOperator(base.AppLifecycleOperator): + + def app_lifecycle_actions(self, context, conductor_obj, + app_op, app, hook_info): + """Perform lifecycle actions for an operation + + :param context: request context, can be None + :param conductor_obj: conductor object, can be None + :param app_op: AppOperator object + :param app: AppOperator.Application object + :param hook_info: LifecycleHookInfo object + + """ + + if hook_info.lifecycle_type == c.APP_LIFECYCLE_TYPE_OPERATION: + if hook_info.operation == c.APP_REMOVE_OP: + if hook_info.relative_timing == c.APP_LIFECYCLE_TIMING_POST: + self._post_remove(app_op) + + super().app_lifecycle_actions(context, conductor_obj, + app_op, app, hook_info) + + @staticmethod + def _post_remove(app_op): + # Helm doesn't delete the namespace. To clean up after + # application-remove, we need to explicitly delete it. + + LOG.debug(f"Executing post_remove for {app_constants.HELM_APP_DISTCLOUD} app") + lifecycle_utils.delete_namespace(app_op, app_constants.HELM_NS_DISTCLOUD) diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/tests/__init__.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/tests/test_distributed_cloud.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/tests/test_distributed_cloud.py new file mode 100644 index 0000000..0047d0a --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/tests/test_distributed_cloud.py @@ -0,0 +1,28 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +from sysinv.db import api as dbapi +from sysinv.tests.db import base as dbbase +from sysinv.tests.db import utils as dbutils +from sysinv.tests.helm import base + +from k8sapp_distributed_cloud.tests import test_plugins + + +class DistributedCloudTestCase(test_plugins.K8SAppDistributedCloudAppMixin, + base.HelmTestCaseMixin): + + def setUp(self): + super().setUp() + self.app = dbutils.create_test_app(name='distributed-cloud') + self.dbapi = dbapi.get_instance() + + +class DistributedCloudTestCaseDummy(DistributedCloudTestCase, + dbbase.ProvisionedControllerHostTestCase): + # without a test zuul will fail + def test_dummy(self): + pass diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/tests/test_plugins.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/tests/test_plugins.py new file mode 100644 index 0000000..788ab0f --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/k8sapp_distributed_cloud/tests/test_plugins.py @@ -0,0 +1,45 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +from sysinv.tests.db import base as dbbase + +from k8sapp_distributed_cloud.common import constants as app_constants + + +class K8SAppDistributedCloudAppMixin(object): + app_name = app_constants.HELM_APP_DISTCLOUD + path_name = app_name + '.tgz' + + # pylint: disable=invalid-name,useless-parent-delegation + def setUp(self): + super().setUp() + + def test_stub(self): + # Replace this with a real unit test. + pass + + +# Test Configuration: +# - Controller +# - IPv6 +# - Ceph Storage +# - distributed-cloud app +class K8sAppDistributedCloudControllerTestCase(K8SAppDistributedCloudAppMixin, + dbbase.BaseIPv6Mixin, + dbbase.BaseCephStorageBackendMixin, + dbbase.ControllerHostTestCase): + pass + + +# Test Configuration: +# - AIO +# - IPv4 +# - Ceph Storage +# - distributed-cloud app +class K8SAppDistributedCloudAIOTestCase(K8SAppDistributedCloudAppMixin, + dbbase.BaseCephStorageBackendMixin, + dbbase.AIOSimplexHostTestCase): + pass diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/pylint.rc b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/pylint.rc new file mode 100644 index 0000000..13b0acd --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/pylint.rc @@ -0,0 +1,234 @@ +[MASTER] +# Specify a configuration file. +rcfile=pylint.rc + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Add files or directories to the blacklist. Should be base names, not paths. +ignore= + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins=pylint.extensions.bad_builtin + +# Use multiple processes to speed up Pylint. +jobs=4 + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist=lxml.etree,greenlet + + + +[MESSAGES CONTROL] +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). +# See "Messages Control" section of +# https://pylint.readthedocs.io/en/latest/user_guide +disable= + # C codes refer to Convention + C0114, # missing-module-docstring + C0115, # missing-class-docstring + C0116, # missing-function-docstring + # R codes refer to refactoring + R0205, # useless-object-inheritance + R0901, # too-many-ancestors + R0903, # too-few-public-methods + R0913, # too-many-arguments + # W codes are warnings + W0212, # protected-access + +[REPORTS] +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + + +[SIMILARITIES] +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + + +[FORMAT] +# Maximum number of characters on a single line. +max-line-length=85 + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually 4 spaces or "\t" (1 tab). +indent-string=' ' + + +[TYPECHECK] +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis +ignored-modules=distutils,eventlet.green.subprocess,six,six.moves + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +# pylint is confused by sqlalchemy Table, as well as sqlalchemy Enum types +# ie: (unprovisioned, identity) +# LookupDict in requests library confuses pylint +ignored-classes=SQLObject, optparse.Values, thread._local, _thread._local, + Table, unprovisioned, identity, LookupDict + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. Python regular +# expressions are accepted. +generated-members=REQUEST,acl_users,aq_parent + + +[BASIC] +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression which should only match correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Regular expression which should only match functions or classes name which do +# not require a docstring +no-docstring-rgx=__.*__ + + +[MISCELLANEOUS] +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[VARIABLES] +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the beginning of the name of dummy variables +# (i.e. not used). +dummy-variables-rgx=_|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +[IMPORTS] +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[DESIGN] +# Maximum number of arguments for function / method +max-args=5 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +[CLASSES] +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + + +[EXCEPTIONS] +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=builtins.BaseException,builtins.Exception diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/requirements.txt b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/requirements.txt new file mode 100644 index 0000000..8f225d8 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/requirements.txt @@ -0,0 +1,2 @@ +pbr>=2.0.0 +PyYAML>=3.10.0 diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/setup.cfg b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/setup.cfg new file mode 100644 index 0000000..abaa301 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/setup.cfg @@ -0,0 +1,40 @@ +[metadata] +name = k8sapp-distributed-cloud +summary = StarlingX sysinv extensions for Distributed Cloud +long_description = file: README.rst +long_description_content_type = text/x-rst +license = Apache 2.0 +author = StarlingX +author-email = starlingx-discuss@lists.starlingx.io +home-page = https://www.starlingx.io/ +classifier = + Environment :: OpenStack + Intended Audience :: Information Technology + Intended Audience :: System Administrators + License :: OSI Approved :: Apache Software License + Operating System :: POSIX :: Linux + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.9 + +[files] +packages = + k8sapp_distributed_cloud + +[global] +setup-hooks = + pbr.hooks.setup_hook + +[entry_points] +systemconfig.helm_applications = + distributed-cloud = systemconfig.helm_plugins.distributed_cloud + +systemconfig.helm_plugins.distributed_cloud = + 001_dcmanager = k8sapp_distributed_cloud.helm.dcmanager:DCManagerHelm + 002_dcorch = k8sapp_distributed_cloud.helm.dcorch:DCOrchHelm + +systemconfig.app_lifecycle = + distributed-cloud = k8sapp_distributed_cloud.lifecycle.lifecycle_distributed_cloud:DistributedCloudAppLifecycleOperator + +[bdist_wheel] +universal = 1 diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/setup.py b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/setup.py new file mode 100644 index 0000000..a8c0b77 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/setup.py @@ -0,0 +1,12 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import setuptools + + +setuptools.setup( + setup_requires=['pbr>=2.0.0'], + pbr=True) diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/test-requirements.txt b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/test-requirements.txt new file mode 100644 index 0000000..1191b51 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/test-requirements.txt @@ -0,0 +1,20 @@ +# The order of packages is significant, because pip processes them in the order +# of appearance. Changing the order has an impact on the overall integration +# process, which may cause wedges in the gate later. +hacking>=1.1.0,<=2.0.0 # Apache-2.0 +astroid +bandit<1.7.2;python_version>="3.0" +coverage>=3.6 +fixtures>=3.0.0 # Apache-2.0/BSD +mock>=2.0.0 # BSD +python-subunit>=0.0.18 +requests-mock>=0.6.0 # Apache-2.0 +sphinx +oslosphinx +oslotest>=3.2.0 # Apache-2.0 +stestr>=1.0.0 # Apache-2.0 +testrepository>=0.0.18 +testtools!=1.2.0,>=0.9.36 +isort<5;python_version>="3.0" +pylint +pycryptodomex \ No newline at end of file diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/tox.ini b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/tox.ini new file mode 100644 index 0000000..62994b4 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/tox.ini @@ -0,0 +1,88 @@ +[tox] +envlist = flake8,py39,pylint,bandit +minversion = 2.9 +skipsdist = True + +# tox does not work if the path to the workdir is too long, so move it to /tmp +toxworkdir = /tmp/{env:USER}_k8sdistributedcloudtox +stxdir = {toxinidir}/../../.. +distshare={toxworkdir}/.tox/distshare + +[testenv] +allowlist_externals = bash + find +basepython = python3.9 +sitepackages = False + +install_command = pip install -v -v -v \ + -c{toxinidir}/upper-constraints.txt \ + -c{env:UPPER_CONSTRAINTS_FILE:https://opendev.org/starlingx/root/raw/branch/master/build-tools/requirements/debian/upper-constraints.txt} \ + {opts} {packages} + +# Note the hash seed is set to 0 until can be tested with a +# random hash seed successfully. +setenv = VIRTUAL_ENV={envdir} + PYTHONHASHSEED=0 + PYTHONDONTWRITEBYTECODE=1 + OS_TEST_PATH=./k8sapp_distributed_cloud/tests + LANG=en_US.UTF-8 + LANGUAGE=en_US:en + LC_ALL=C + SYSINV_TEST_ENV=True + TOX_WORK_DIR={toxworkdir} + PYLINTHOME={toxworkdir} + +deps = -r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt + -e{[tox]stxdir}/config/sysinv/sysinv/sysinv + -e{[tox]stxdir}/config/tsconfig/tsconfig + -e{[tox]stxdir}/fault/fm-api/source + -e{[tox]stxdir}/fault/python-fmclient/fmclient + -e{[tox]stxdir}/utilities/ceph/python-cephclient/python-cephclient + -e{[tox]stxdir}/update/sw-patch/cgcs-patch + + +commands = + find . -type f -name "*.pyc" -delete + +[flake8] +exclude = build,dist,tools,.eggs +max-line-length=80 + +[testenv:flake8] +deps = -r{toxinidir}/test-requirements.txt +commands = + flake8 {posargs} . + +[testenv:py39] +commands = + {[testenv]commands} + stestr run {posargs} + stestr slowest + +[testenv:pep8] +deps = {[testenv:flake8]deps} +commands = {[testenv:flake8]commands} + +[testenv:venv] +commands = {posargs} + +[bandit] +# Add bandit configuration here + +[testenv:bandit] +deps = -r{toxinidir}/test-requirements.txt +commands = bandit --ini tox.ini -n 5 -r k8sapp_distributed_cloud + +[testenv:pylint] +commands = + pylint {posargs} k8sapp_distributed_cloud --rcfile=./pylint.rc + +[testenv:pip-missing-reqs] +# do not install test-requirements as that will pollute the virtualenv for +# determining missing packages +# this also means that pip-missing-reqs must be installed separately, outside +# of the requirements.txt files +deps = pip_missing_reqs + -rrequirements.txt +commands=pip-missing-reqs -d --ignore-file=/k8sapp_distributed_cloud/tests k8sapp_distributed_cloud diff --git a/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/upper-constraints.txt b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/upper-constraints.txt new file mode 100644 index 0000000..9c30188 --- /dev/null +++ b/python3-k8sapp-distributed-cloud/k8sapp_distributed_cloud/upper-constraints.txt @@ -0,0 +1 @@ +# Override upstream constraints based on StarlingX load diff --git a/stx-distributed-cloud-helm/debian/deb_folder/changelog b/stx-distributed-cloud-helm/debian/deb_folder/changelog new file mode 100644 index 0000000..0aa8ba7 --- /dev/null +++ b/stx-distributed-cloud-helm/debian/deb_folder/changelog @@ -0,0 +1,5 @@ +stx-distributed-cloud-helm (1.0-1) unstable; urgency=medium + + * Initial release. + + -- Hugo Brito Tue, 25 Mar 2025 13:30:15 +0000 diff --git a/stx-distributed-cloud-helm/debian/deb_folder/control b/stx-distributed-cloud-helm/debian/deb_folder/control new file mode 100644 index 0000000..ffb669e --- /dev/null +++ b/stx-distributed-cloud-helm/debian/deb_folder/control @@ -0,0 +1,21 @@ +Source: stx-distributed-cloud-helm +Section: libs +Priority: optional +Maintainer: StarlingX Developers +Build-Depends: debhelper-compat (= 13), + chartmuseum, + helm, + procps, + python3-k8sapp-distributed-cloud, + python3-k8sapp-distributed-cloud-wheels, + build-info +Standards-Version: 4.5.1 +Homepage: https://www.starlingx.io + +Package: stx-distributed-cloud-helm +Section: libs +Architecture: any +Depends: ${misc:Depends} +Description: StarlingX Distributed Cloud FluxCD Helm Charts + This package contains FluxCD helm charts for the Distributed Cloud + application. diff --git a/stx-distributed-cloud-helm/debian/deb_folder/copyright b/stx-distributed-cloud-helm/debian/deb_folder/copyright new file mode 100644 index 0000000..7d40db5 --- /dev/null +++ b/stx-distributed-cloud-helm/debian/deb_folder/copyright @@ -0,0 +1,41 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: stx-distributed-cloud-helm +Source: https://opendev.org/starlingx/app-distributed-cloud/ + +Files: * +Copyright: (c) 2025 Wind River Systems, Inc +License: Apache-2 + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + https://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + . + On Debian-based systems the full text of the Apache version 2.0 license + can be found in `/usr/share/common-licenses/Apache-2.0'. + +# If you want to use GPL v2 or later for the /debian/* files use +# the following clauses, or change it to suit. Delete these two lines +Files: debian/* +Copyright: 2025 Wind River Systems, Inc +License: Apache-2 + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + https://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + . + On Debian-based systems the full text of the Apache version 2.0 license + can be found in `/usr/share/common-licenses/Apache-2.0'. diff --git a/stx-distributed-cloud-helm/debian/deb_folder/rules b/stx-distributed-cloud-helm/debian/deb_folder/rules new file mode 100644 index 0000000..bbb9e58 --- /dev/null +++ b/stx-distributed-cloud-helm/debian/deb_folder/rules @@ -0,0 +1,57 @@ +#!/usr/bin/make -f +# export DH_VERBOSE = 1 + +export ROOT = debian/tmp +export APP_FOLDER = $(ROOT)/usr/local/share/applications/helm + +export DEB_VERSION = $(shell dpkg-parsechangelog | egrep '^Version:' | cut -f 2 -d ' ') +export RELEASE = $(shell cat /etc/build.info | grep SW_VERSION | cut -d'"' -f2) +export REVISION = $(shell echo $(DEB_VERSION) | cut -f 4 -d '.') + +export APP_NAME = distributed-cloud +export APP_VERSION = $(RELEASE)-$(REVISION) +export APP_TARBALL = $(APP_NAME)-$(APP_VERSION).tgz +export HELM_REPO = stx-platform +export HELM_FOLDER = /usr/lib/helm +export STAGING = staging + +%: + dh $@ + +override_dh_auto_build: + # Create the TGZ file + cd helm-charts && $(MAKE) + + # Setup the staging directory + mkdir -p $(STAGING) + cp files/metadata.yaml $(STAGING) + mkdir -p $(STAGING)/charts + cp helm-charts/*.tgz $(STAGING)/charts + + # Populate metadata + sed -i 's/APP_REPLACE_NAME/$(APP_NAME)/g' $(STAGING)/metadata.yaml + sed -i 's/APP_REPLACE_VERSION/$(APP_VERSION)/g' $(STAGING)/metadata.yaml + sed -i 's/HELM_REPLACE_REPO/$(HELM_REPO)/g' $(STAGING)/metadata.yaml + + # Copy the plugins: installed in the buildroot + mkdir -p $(STAGING)/plugins + cp /plugins/*.whl $(STAGING)/plugins + + # Prepare staging for fluxcd package + cp -R fluxcd-manifests $(STAGING)/ + + # Calculate checksum of all files in staging for the fluxcd app + cd $(STAGING) && find . -type f ! -name '*.md5' -print0 | xargs -0 md5sum > checksum.md5 + + # Package fluxcd app + tar cfz $(APP_TARBALL) -C $(STAGING)/ . + + # Cleanup staging + rm -rf $(STAGING) + +override_dh_auto_install: + # Install the app tar file. + install -d -m 755 $(APP_FOLDER) + install -p -D -m 755 $(APP_TARBALL) $(APP_FOLDER) + +override_dh_usrlocal: diff --git a/stx-distributed-cloud-helm/debian/deb_folder/source/format b/stx-distributed-cloud-helm/debian/deb_folder/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/stx-distributed-cloud-helm/debian/deb_folder/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/stx-distributed-cloud-helm/debian/deb_folder/stx-distributed-cloud-helm.install b/stx-distributed-cloud-helm/debian/deb_folder/stx-distributed-cloud-helm.install new file mode 100644 index 0000000..1b47c6e --- /dev/null +++ b/stx-distributed-cloud-helm/debian/deb_folder/stx-distributed-cloud-helm.install @@ -0,0 +1 @@ +usr/local/share/applications/helm/* diff --git a/stx-distributed-cloud-helm/debian/meta_data.yaml b/stx-distributed-cloud-helm/debian/meta_data.yaml new file mode 100644 index 0000000..f5b6129 --- /dev/null +++ b/stx-distributed-cloud-helm/debian/meta_data.yaml @@ -0,0 +1,6 @@ +--- +debname: stx-distributed-cloud-helm +debver: 1.0-0 +src_path: stx-distributed-cloud-helm +revision: + dist: $STX_DIST diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/files/metadata.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/files/metadata.yaml new file mode 100644 index 0000000..876e6aa --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/files/metadata.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2024 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +app_name: APP_REPLACE_NAME +app_version: APP_REPLACE_VERSION +helm_repo: HELM_REPLACE_REPO + +maintain_user_overrides: true + +upgrades: + auto_update: true + +supported_k8s_version: + minimum: 1.24.4 + +behavior: + platform_managed_app: yes + evaluate_reapply: + triggers: + - type: host-label-assign + - type: host-modify diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/base/helmrepository.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/base/helmrepository.yaml new file mode 100644 index 0000000..7aee2a4 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/base/helmrepository.yaml @@ -0,0 +1,13 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: HelmRepository +metadata: + name: stx-platform +spec: + url: http://192.168.206.1:8080/helm_charts/stx-platform + interval: 1m diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/base/kustomization.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/base/kustomization.yaml new file mode 100644 index 0000000..6d8ae79 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/base/kustomization.yaml @@ -0,0 +1,8 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +resources: + - helmrepository.yaml diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/base/namespace.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/base/namespace.yaml new file mode 100644 index 0000000..434bd27 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/base/namespace.yaml @@ -0,0 +1,10 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +apiVersion: v1 +kind: Namespace +metadata: + name: distributed-cloud diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/dc-vault-nginx-static-overrides.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/dc-vault-nginx-static-overrides.yaml new file mode 100644 index 0000000..a1da073 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/dc-vault-nginx-static-overrides.yaml @@ -0,0 +1,16 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +nginx: + replicas: 1 + node_selector_key: starlingx.io/distributed-cloud + node_selector_value: enabled + +volume: + vault: + size: 20Gi + backup: + size: 15Gi diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/dc-vault-nginx-system-overrides.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/dc-vault-nginx-system-overrides.yaml new file mode 100644 index 0000000..e493726 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/dc-vault-nginx-system-overrides.yaml @@ -0,0 +1,5 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/helmrelease.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/helmrelease.yaml new file mode 100644 index 0000000..13d8911 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/helmrelease.yaml @@ -0,0 +1,36 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +apiVersion: "helm.toolkit.fluxcd.io/v2beta1" +kind: HelmRelease +metadata: + name: dc-vault-nginx + labels: + chart_group: dc-vault-nginx +spec: + releaseName: dc-vault-nginx + chart: + spec: + chart: dc-vault-nginx + version: 1.0.0 + sourceRef: + kind: HelmRepository + name: stx-platform + interval: 1m + timeout: 30m + test: + enable: false + install: + disableHooks: false + upgrade: + disableHooks: false + valuesFrom: + - kind: Secret + name: dc-vault-nginx-static-overrides + valuesKey: dc-vault-nginx-static-overrides.yaml + - kind: Secret + name: dc-vault-nginx-system-overrides + valuesKey: dc-vault-nginx-system-overrides.yaml diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/kustomization.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/kustomization.yaml new file mode 100644 index 0000000..532eb90 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dc-vault-nginx/kustomization.yaml @@ -0,0 +1,18 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +namespace: distributed-cloud +resources: + - helmrelease.yaml +secretGenerator: + - name: dc-vault-nginx-static-overrides + files: + - dc-vault-nginx-static-overrides.yaml + - name: dc-vault-nginx-system-overrides + files: + - dc-vault-nginx-system-overrides.yaml +generatorOptions: + disableNameSuffixHash: true diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/dcmanager-static-overrides.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/dcmanager-static-overrides.yaml new file mode 100644 index 0000000..bf45446 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/dcmanager-static-overrides.yaml @@ -0,0 +1,33 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +pod: + image_pull_secrets: + default: + - name: default-registry-key + tolerations: + dcmanager: + enabled: true + +endpoints: + oslo_db: + auth: + admin: + username: admin-dcmanager + dcmanager: + username: admin-dcmanager + oslo_messaging: + auth: + admin: + username: guest + dcmanager: + username: guest + identity: + auth: + admin: + username: admin + dcmanager: + username: dcmanager diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/dcmanager-system-overrides.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/dcmanager-system-overrides.yaml new file mode 100644 index 0000000..e493726 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/dcmanager-system-overrides.yaml @@ -0,0 +1,5 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/helmrelease.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/helmrelease.yaml new file mode 100644 index 0000000..cf41c52 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/helmrelease.yaml @@ -0,0 +1,36 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +apiVersion: "helm.toolkit.fluxcd.io/v2beta1" +kind: HelmRelease +metadata: + name: dcmanager + labels: + chart_group: dcmanager +spec: + releaseName: dcmanager + chart: + spec: + chart: dcmanager + version: 0.1.0 + sourceRef: + kind: HelmRepository + name: stx-platform + interval: 1m + timeout: 30m + test: + enable: false + install: + disableHooks: false + upgrade: + disableHooks: false + valuesFrom: + - kind: Secret + name: dcmanager-static-overrides + valuesKey: dcmanager-static-overrides.yaml + - kind: Secret + name: dcmanager-system-overrides + valuesKey: dcmanager-system-overrides.yaml diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/kustomization.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/kustomization.yaml new file mode 100644 index 0000000..5e804b4 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcmanager/kustomization.yaml @@ -0,0 +1,18 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +namespace: distributed-cloud +resources: + - helmrelease.yaml +secretGenerator: + - name: dcmanager-static-overrides + files: + - dcmanager-static-overrides.yaml + - name: dcmanager-system-overrides + files: + - dcmanager-system-overrides.yaml +generatorOptions: + disableNameSuffixHash: true diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/dcorch-static-overrides.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/dcorch-static-overrides.yaml new file mode 100644 index 0000000..8d7de0b --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/dcorch-static-overrides.yaml @@ -0,0 +1,33 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +pod: + image_pull_secrets: + default: + - name: default-registry-key + tolerations: + dcorch: + enabled: true + +endpoints: + oslo_db: + auth: + admin: + username: admin-dcorch + dcorch: + username: admin-dcorch + oslo_messaging: + auth: + admin: + username: guest + dcorch: + username: guest + identity: + auth: + admin: + username: admin + dcorch: + username: dcorch diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/dcorch-system-overrides.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/dcorch-system-overrides.yaml new file mode 100644 index 0000000..e493726 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/dcorch-system-overrides.yaml @@ -0,0 +1,5 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/helmrelease.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/helmrelease.yaml new file mode 100644 index 0000000..16971e7 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/helmrelease.yaml @@ -0,0 +1,36 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +apiVersion: "helm.toolkit.fluxcd.io/v2beta1" +kind: HelmRelease +metadata: + name: dcorch + labels: + chart_group: dcorch +spec: + releaseName: dcorch + chart: + spec: + chart: dcorch + version: 0.1.0 + sourceRef: + kind: HelmRepository + name: stx-platform + interval: 1m + timeout: 30m + test: + enable: false + install: + disableHooks: false + upgrade: + disableHooks: false + valuesFrom: + - kind: Secret + name: dcorch-static-overrides + valuesKey: dcorch-static-overrides.yaml + - kind: Secret + name: dcorch-system-overrides + valuesKey: dcorch-system-overrides.yaml diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/kustomization.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/kustomization.yaml new file mode 100644 index 0000000..64d679b --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/dcorch/kustomization.yaml @@ -0,0 +1,18 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +namespace: distributed-cloud +resources: + - helmrelease.yaml +secretGenerator: + - name: dcorch-static-overrides + files: + - dcorch-static-overrides.yaml + - name: dcorch-system-overrides + files: + - dcorch-system-overrides.yaml +generatorOptions: + disableNameSuffixHash: true diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/kustomization.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/kustomization.yaml new file mode 100644 index 0000000..1cde988 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/fluxcd-manifests/kustomization.yaml @@ -0,0 +1,14 @@ +# +# Copyright (c) 2025 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: distributed-cloud +resources: + - base + - dcmanager + - dcorch + - dc-vault-nginx diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/.gitignore b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/.gitignore new file mode 100644 index 0000000..bab3504 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/.gitignore @@ -0,0 +1,2 @@ +*.tgz +**/Chart.lock \ No newline at end of file diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/Makefile b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/Makefile new file mode 100644 index 0000000..24bbbfc --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/Makefile @@ -0,0 +1,42 @@ +# +# Copyright 2017 The Openstack-Helm Authors. +# +# Copyright (c) 2024 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# It's necessary to set this because some environments don't link sh -> bash. +SHELL := /bin/bash +TASK := build + +EXCLUDES := helm-toolkit doc tests tools logs tmp +CHARTS := $(filter-out $(EXCLUDES), $(patsubst %/.,%,$(wildcard */.))) + +.PHONY: $(EXCLUDES) $(CHARTS) + +all: $(CHARTS) + +$(CHARTS): + @if [ -d $@ ]; then \ + echo; \ + echo "===== Processing [$@] chart ====="; \ + $(MAKE) $(TASK)-$@; \ + fi + +init-%: + if [ -f $*/Makefile ]; then make -C $*; fi + +lint-%: init-% + if [ -d $* ]; then helm lint $*; fi + +build-%: lint-% + if [ -d $* ]; then helm package $*; fi + +clean: + @echo "Clean all build artifacts" + rm -f */templates/_partials.tpl */templates/_globals.tpl + rm -f *tgz */charts/*tgz */requirements.lock + rm -rf */charts */tmpcharts + +%: + @: diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/.helmignore b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/Chart.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/Chart.yaml new file mode 100644 index 0000000..d8c2c65 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +name: dc-vault-nginx +description: A Helm chart for DC Vault NGINX +version: 1.0.0 +appVersion: "1.0.0" +dependencies: + - name: helm-toolkit + version: ">= 0.1.0" + repository: file://../helm-toolkit diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/charts/helm-toolkit-0.2.59.tgz b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dc-vault-nginx/charts/helm-toolkit-0.2.59.tgz new file mode 100644 index 0000000000000000000000000000000000000000..67ff2479690bfde66e8310c93233fd13cff7231b GIT binary patch literal 52002 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 K>= 0.1.0" + repository: file://../helm-toolkit diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/charts/helm-toolkit-0.2.59.tgz b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/charts/helm-toolkit-0.2.59.tgz new file mode 100644 index 0000000000000000000000000000000000000000..33a6600dfedd538cec59ae23175253285ea057cd GIT binary patch literal 52000 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

qGK%`?WBaso{IT6`o?U6i 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 JKWhMx1^@t&TnPXG literal 0 HcmV?d00001 diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/_helpers.tpl b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/_helpers.tpl new file mode 100644 index 0000000..15a7f60 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "dcmanager.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "dcmanager.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 }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "dcmanager.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "dcmanager.labels" -}} +helm.sh/chart: {{ include "dcmanager.chart" . }} +{{ include "dcmanager.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "dcmanager.selectorLabels" -}} +app.kubernetes.io/name: {{ include "dcmanager.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "dcmanager.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "dcmanager.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_db-drop.sh.tpl b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_db-drop.sh.tpl new file mode 100644 index 0000000..eeb61c0 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_db-drop.sh.tpl @@ -0,0 +1,11 @@ +#!/bin/bash + +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +set -ex + +dropdb -h 127.0.0.1 -Uroot dcmanager diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_db-sync.sh.tpl b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_db-sync.sh.tpl new file mode 100644 index 0000000..9f2d65c --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_db-sync.sh.tpl @@ -0,0 +1,11 @@ +#!/bin/bash + +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +set -ex + +dcmanager-manage db_sync diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-api.sh.tpl b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-api.sh.tpl new file mode 100644 index 0000000..e43e047 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-api.sh.tpl @@ -0,0 +1,16 @@ +#!/bin/bash + +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +set -ex + +if ! update-ca-certificates; then + echo "Failed to update CA certificates!" >&2 + exit 1 +fi + +python /var/lib/openstack/bin/dcmanager-api --config-file=/etc/dcmanager/dcmanager.conf diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-audit-worker.sh.tpl b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-audit-worker.sh.tpl new file mode 100644 index 0000000..85c3743 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-audit-worker.sh.tpl @@ -0,0 +1,16 @@ +#!/bin/bash + +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +set -ex + +if ! update-ca-certificates; then + echo "Failed to update CA certificates!" >&2 + exit 1 +fi + +python /var/lib/openstack/bin/dcmanager-audit-worker --config-file=/etc/dcmanager/dcmanager.conf diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-audit.sh.tpl b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-audit.sh.tpl new file mode 100644 index 0000000..6ffa57c --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-audit.sh.tpl @@ -0,0 +1,16 @@ +#!/bin/bash + +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +set -ex + +if ! update-ca-certificates; then + echo "Failed to update CA certificates!" >&2 + exit 1 +fi + +python /var/lib/openstack/bin/dcmanager-audit --config-file=/etc/dcmanager/dcmanager.conf diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-manager.sh.tpl b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-manager.sh.tpl new file mode 100644 index 0000000..8ef1f02 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-manager.sh.tpl @@ -0,0 +1,17 @@ +#!/bin/bash + +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +set -ex + + +if ! update-ca-certificates; then + echo "Failed to update CA certificates!" >&2 + exit 1 +fi + +python /var/lib/openstack/bin/dcmanager-manager --config-file=/etc/dcmanager/dcmanager.conf diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-orchestrator.sh.tpl b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-orchestrator.sh.tpl new file mode 100644 index 0000000..b3f2f1a --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-orchestrator.sh.tpl @@ -0,0 +1,11 @@ +#!/bin/bash + +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +set -ex + +python /var/lib/openstack/bin/dcmanager-orchestrator --config-file=/etc/dcmanager/dcmanager.conf diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-state.sh.tpl b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-state.sh.tpl new file mode 100644 index 0000000..6a609ca --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/bin/_dcmanager-state.sh.tpl @@ -0,0 +1,11 @@ +#!/bin/bash + +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +set -ex + +python /var/lib/openstack/bin/dcmanager-state --config-file=/etc/dcmanager/dcmanager.conf diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/configmap-bin.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/configmap-bin.yaml new file mode 100644 index 0000000..9771ba2 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/configmap-bin.yaml @@ -0,0 +1,37 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: dcmanager-bin +data: + dcmanager-api.sh: | +{{ tuple "bin/_dcmanager-api.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} + dcmanager-manager.sh: | +{{ tuple "bin/_dcmanager-manager.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} + dcmanager-state.sh: | +{{ tuple "bin/_dcmanager-state.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} + dcmanager-orchestrator.sh: | +{{ tuple "bin/_dcmanager-orchestrator.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} + dcmanager-audit.sh: | +{{ tuple "bin/_dcmanager-audit.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} + dcmanager-audit-worker.sh: | +{{ tuple "bin/_dcmanager-audit-worker.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} + db-sync.sh: | +{{ tuple "bin/_db-sync.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} + db-init.py: | +{{- include "helm-toolkit.scripts.db_init" . | indent 4 }} + db-drop.sh: | +{{ tuple "bin/_db-drop.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} + db-drop.py: | +{{- include "helm-toolkit.scripts.db_drop" . | indent 4 }} + ks-service.sh: | +{{- include "helm-toolkit.scripts.keystone_service" . | indent 4 }} + ks-endpoints.sh: | +{{- include "helm-toolkit.scripts.keystone_endpoints" . | indent 4 }} + ks-user.sh: | +{{- include "helm-toolkit.scripts.keystone_user" . | indent 4 }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-api.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-api.yaml new file mode 100644 index 0000000..c772843 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-api.yaml @@ -0,0 +1,156 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- define "dcManagerApiLivenessProbeTemplate" }} +tcpSocket: + port: {{ tuple "dcmanager" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }} +{{- end }} + +{{- if .Values.manifests.deployment_api }} +{{- $envAll := . }} + +{{- $mounts_dcmanager_api := .Values.pod.mounts.api.dcmanager }} +{{- $mounts_dcmanager_api_init := .Values.pod.mounts.api.init_container }} + +{{- $serviceAccountName := "dcmanager" }} +{{ tuple $envAll "api" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dcmanager-api + labels: +{{ tuple $envAll "dcmanager" "api" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }} +spec: + {{- if not .Values.pod.autoscaling.enabled }} + replicas: {{ .Values.pod.replicas.api }} + {{- end }} + selector: + matchLabels: +{{ tuple $envAll "dcmanager" "api" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }} +{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }} + template: + metadata: + {{- with .Values.pod.annotations.api }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: +{{ tuple $envAll "dcmanager" "api" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }} + spec: + serviceAccountName: {{ $serviceAccountName }} + initContainers: +{{ tuple $envAll "api" $mounts_dcmanager_api_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }} + containers: + - name: dcmanager +{{ tuple $envAll $envAll.Values.pod.resources.api | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }} + env: + - name: REQUESTS_CA_BUNDLE + value: /etc/ssl/certs/ca-certificates.crt + volumeMounts: + - name: dcmanager-bin + mountPath: /tmp/dcmanager-api.sh + subPath: dcmanager-api.sh + readOnly: true + - name: dcmanager-etc + mountPath: /etc/dcmanager/dcmanager.conf + subPath: dcmanager.conf + readOnly: true + - name: dcmanager-etc + mountPath: /etc/dcmanager/logging.conf + subPath: logging.conf + readOnly: true + - name: buildinfo + mountPath: /etc/build.info + readOnly: true + - name: platformconf + mountPath: /etc/platform/platform.conf + readOnly: true + - name: applications + mountPath: /usr/local/share/applications/ + readOnly: true + - name: dc-vault-dir + mountPath: {{ .Values.conf.dcmanager.vault.base_path }} + - name: dc-backup-dir + mountPath: {{ .Values.conf.dcmanager.backup.base_path }} + - name: dc-deploy-dir + mountPath: {{ .Values.conf.dcmanager.deploy.base_path }}/{{ .Values.conf.dcmanager.deploy.version }} +{{- if .Values.ca_certificates.root_ca }} + - name: root-ca + mountPath: /usr/local/share/ca-certificates/root-ca.crt + subPath: ca.crt + readOnly: true +{{- end }} +{{ if $mounts_dcmanager_api.volumeMounts }}{{ toYaml $mounts_dcmanager_api.volumeMounts | indent 12 }}{{ end }} +{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.dcmanager.api.public | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }} +{{ dict "envAll" . "component" "api" "container" "default" "type" "liveness" "probeTemplate" (include "dcManagerApiLivenessProbeTemplate" . | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }} + command: + - /tmp/dcmanager-api.sh + image: "{{ .Values.images.tags.dcmanager }}" + imagePullPolicy: {{ .Values.images.pullPolicy }} + ports: + - name: http + containerPort: {{ tuple "dcmanager" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }} + protocol: TCP +{{ tuple $envAll "dcmanager" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }} + nodeSelector: + {{ .Values.labels.dcmanager.node_selector_key }}: {{ .Values.labels.dcmanager.node_selector_value }} +{{ if $envAll.Values.pod.tolerations.dcmanager.enabled }} +{{ tuple $envAll "dcmanager" | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }} +{{ end }} + affinity: + {{ tuple $envAll "dcmanager" "api" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }} + volumes: + - name: dcmanager-etc + secret: + secretName: dcmanager-etc + defaultMode: 0644 + - name: dcmanager-bin + configMap: + name: dcmanager-bin + defaultMode: 0755 + - name: buildinfo + hostPath: + path: /etc/build.info + - name: platformconf + hostPath: + path: /etc/platform/platform.conf + - name: applications + hostPath: + path: /usr/local/share/applications + type: Directory + - name: dc-deploy-dir + hostPath: + path: /opt/dc-vault/deploy/{{ .Values.conf.dcmanager.deploy.version }} +{{- if .Values.ca_certificates.root_ca }} + - name: root-ca + secret: + secretName: {{ .Values.ca_certificates.root_ca }} + defaultMode: 0644 +{{- end }} + {{- if and .Values.volume.vault.enabled .Values.manifests.pvc_vault }} + - name: dc-vault-dir + persistentVolumeClaim: + claimName: dc-vault-pvc + {{- else }} + - name: dc-vault-dir + hostPath: + path: {{ .Values.conf.dcmanager.vault.base_path }} + type: DirectoryOrCreate + {{- end }} + {{- if and .Values.volume.backup.enabled .Values.manifests.pvc_backup }} + - name: dc-backup-dir + persistentVolumeClaim: + claimName: dc-backup-pvc + {{- else }} + - name: dc-backup-dir + hostPath: + path: {{ .Values.conf.dcmanager.backup.base_path }} + type: DirectoryOrCreate + {{- end }} +{{ if $mounts_dcmanager_api.volumes }}{{ toYaml $mounts_dcmanager_api.volumes | indent 8 }}{{ end }} +{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.dcmanager.api.public | include "helm-toolkit.snippets.tls_volume" | indent 8 }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-audit-worker.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-audit-worker.yaml new file mode 100644 index 0000000..2ccd11b --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-audit-worker.yaml @@ -0,0 +1,96 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.deployment_audit }} +{{- $envAll := . }} + +{{- $mounts_dcmanager_audit := .Values.pod.mounts.audit.dcmanager }} +{{- $mounts_dcmanager_audit_init := .Values.pod.mounts.audit.init_container }} + +{{- $serviceAccountName := "dcmanager-audit-worker" }} +{{ tuple $envAll "audit" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dcmanager-audit-worker + labels: +{{ tuple $envAll "dcmanager" "audit" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }} +spec: + {{- if not .Values.pod.autoscaling.enabled }} + replicas: {{ .Values.pod.replicas.audit_worker }} + {{- end }} + selector: + matchLabels: +{{ tuple $envAll "dcmanager" "audit" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }} +{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }} + template: + metadata: + {{- with .Values.pod.annotations.audit }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: +{{ tuple $envAll "dcmanager" "audit" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }} + spec: + serviceAccountName: {{ $serviceAccountName }} + initContainers: +{{ tuple $envAll "audit" $mounts_dcmanager_audit_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }} + containers: + - name: dcmanager +{{ tuple $envAll $envAll.Values.pod.resources.audit_worker | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }} + env: + - name: REQUESTS_CA_BUNDLE + value: /etc/ssl/certs/ca-certificates.crt + volumeMounts: + - name: dcmanager-bin + mountPath: /tmp/dcmanager-audit-worker.sh + subPath: dcmanager-audit-worker.sh + readOnly: true + - name: dcmanager-etc + mountPath: /etc/dcmanager/dcmanager.conf + subPath: dcmanager.conf + readOnly: true + - name: dcmanager-etc + mountPath: /etc/dcmanager/logging.conf + subPath: logging.conf + readOnly: true +{{- if .Values.ca_certificates.root_ca }} + - name: root-ca + mountPath: /usr/local/share/ca-certificates/root-ca.crt + subPath: ca.crt + readOnly: true +{{- end }} +{{ if $mounts_dcmanager_audit.volumeMounts }}{{ toYaml $mounts_dcmanager_audit.volumeMounts | indent 12 }}{{ end }} + command: + - /tmp/dcmanager-audit-worker.sh + image: "{{ .Values.images.tags.dcmanager }}" + imagePullPolicy: {{ .Values.images.pullPolicy }} +{{ tuple $envAll "dcmanager" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }} + nodeSelector: + {{ .Values.labels.dcmanager.node_selector_key }}: {{ .Values.labels.dcmanager.node_selector_value }} +{{ if $envAll.Values.pod.tolerations.dcmanager.enabled }} +{{ tuple $envAll "dcmanager" | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }} +{{ end }} + affinity: + {{ tuple $envAll "dcmanager" "audit" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }} + volumes: +{{- if .Values.ca_certificates.root_ca }} + - name: root-ca + secret: + secretName: {{ .Values.ca_certificates.root_ca }} + defaultMode: 0644 +{{- end }} + - name: dcmanager-etc + secret: + secretName: dcmanager-etc + defaultMode: 0644 + - name: dcmanager-bin + configMap: + name: dcmanager-bin + defaultMode: 0755 +{{ if $mounts_dcmanager_audit.volumes }}{{ toYaml $mounts_dcmanager_audit.volumes | indent 8 }}{{ end }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-audit.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-audit.yaml new file mode 100644 index 0000000..abeeb8e --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-audit.yaml @@ -0,0 +1,138 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.deployment_audit }} +{{- $envAll := . }} + +{{- $mounts_dcmanager_audit := .Values.pod.mounts.audit.dcmanager }} +{{- $mounts_dcmanager_audit_init := .Values.pod.mounts.audit.init_container }} + +{{- $serviceAccountName := "dcmanager-audit" }} +{{ tuple $envAll "audit" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dcmanager-audit + labels: +{{ tuple $envAll "dcmanager" "audit" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }} +spec: + {{- if not .Values.pod.autoscaling.enabled }} + replicas: {{ .Values.pod.replicas.audit }} + {{- end }} + selector: + matchLabels: +{{ tuple $envAll "dcmanager" "audit" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }} +{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }} + template: + metadata: + {{- with .Values.pod.annotations.audit }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: +{{ tuple $envAll "dcmanager" "audit" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }} + spec: + serviceAccountName: {{ $serviceAccountName }} + initContainers: +{{ tuple $envAll "audit" $mounts_dcmanager_audit_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }} + containers: + - name: dcmanager +{{ tuple $envAll $envAll.Values.pod.resources.audit | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }} + env: + - name: REQUESTS_CA_BUNDLE + value: /etc/ssl/certs/ca-certificates.crt + volumeMounts: + - name: dcmanager-bin + mountPath: /tmp/dcmanager-audit.sh + subPath: dcmanager-audit.sh + readOnly: true + - name: dcmanager-etc + mountPath: /etc/dcmanager/dcmanager.conf + subPath: dcmanager.conf + readOnly: true + - name: dcmanager-etc + mountPath: /etc/dcmanager/logging.conf + subPath: logging.conf + readOnly: true + - name: platform-volume + mountPath: /opt/platform/ + - name: buildinfo + mountPath: /etc/build.info + readOnly: true + - name: platformconf + mountPath: /etc/platform/platform.conf + readOnly: true + - name: dc-vault-dir + mountPath: {{ .Values.conf.dcmanager.vault.base_path }} + - name: dc-backup-dir + mountPath: {{ .Values.conf.dcmanager.backup.base_path }} +{{- if .Values.ca_certificates.root_ca }} + - name: root-ca + mountPath: /usr/local/share/ca-certificates/root-ca.crt + subPath: ca.crt + readOnly: true +{{- end }} +{{ if $mounts_dcmanager_audit.volumeMounts }}{{ toYaml $mounts_dcmanager_audit.volumeMounts | indent 12 }}{{ end }} + command: + - /tmp/dcmanager-audit.sh + image: "{{ .Values.images.tags.dcmanager }}" + imagePullPolicy: {{ .Values.images.pullPolicy }} +{{ tuple $envAll "dcmanager" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }} + nodeSelector: + {{ .Values.labels.dcmanager.node_selector_key }}: {{ .Values.labels.dcmanager.node_selector_value }} +{{ if $envAll.Values.pod.tolerations.dcmanager.enabled }} +{{ tuple $envAll "dcmanager" | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }} +{{ end }} + affinity: + {{ tuple $envAll "dcmanager" "audit" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }} + volumes: + - name: dcmanager-etc + secret: + secretName: dcmanager-etc + defaultMode: 0644 + - name: dcmanager-bin + configMap: + name: dcmanager-bin + defaultMode: 0755 + - name: platform-volume + hostPath: + path: /opt/platform/ + type: DirectoryOrCreate + - name: buildinfo + hostPath: + path: /etc/build.info + - name: platformconf + hostPath: + path: /etc/platform/platform.conf +{{- if .Values.ca_certificates.root_ca }} + - name: root-ca + secret: + secretName: {{ .Values.ca_certificates.root_ca }} + defaultMode: 0644 +{{- end }} +{{- if and .Values.volume.vault.enabled .Values.manifests.pvc_vault }} + - name: dc-vault-dir + persistentVolumeClaim: + claimName: dc-vault-pvc + {{- else }} + - name: dc-vault-dir + hostPath: + path: {{ .Values.conf.dcmanager.vault.base_path }} + type: DirectoryOrCreate + {{- end }} + {{- if and .Values.volume.backup.enabled .Values.manifests.pvc_backup }} + - name: dc-backup-dir + persistentVolumeClaim: + claimName: dc-backup-pvc + {{- else }} + - name: dc-backup-dir + hostPath: + path: {{ .Values.conf.dcmanager.backup.base_path }} + type: DirectoryOrCreate + {{- end }} +{{ if $mounts_dcmanager_audit.volumes }}{{ toYaml $mounts_dcmanager_audit.volumes | indent 8 }}{{ end }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-manager.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-manager.yaml new file mode 100644 index 0000000..59ea3c6 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-manager.yaml @@ -0,0 +1,162 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.deployment_manager }} +{{- $envAll := . }} + +{{- $mounts_dcmanager_manager := .Values.pod.mounts.manager.dcmanager }} +{{- $mounts_dcmanager_manager_init := .Values.pod.mounts.manager.init_container }} + +{{- $serviceAccountName := "dcmanager-manager" }} +{{ tuple $envAll "manager" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dcmanager-manager + labels: +{{ tuple $envAll "dcmanager" "manager" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }} +spec: + {{- if not .Values.pod.autoscaling.enabled }} + replicas: {{ .Values.pod.replicas.manager }} + {{- end }} + selector: + matchLabels: +{{ tuple $envAll "dcmanager" "manager" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }} +{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }} + template: + metadata: + {{- with .Values.pod.annotations.manager }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: +{{ tuple $envAll "dcmanager" "manager" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }} + spec: + serviceAccountName: {{ $serviceAccountName }} + initContainers: +{{ tuple $envAll "manager" $mounts_dcmanager_manager_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }} + containers: + - name: dcmanager +{{ tuple $envAll $envAll.Values.pod.resources.manager | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }} + env: + - name: REQUESTS_CA_BUNDLE + value: /etc/ssl/certs/ca-certificates.crt + volumeMounts: + - name: dcmanager-bin + mountPath: /tmp/dcmanager-manager.sh + subPath: dcmanager-manager.sh + readOnly: true + - name: dcmanager-etc + mountPath: /etc/dcmanager/dcmanager.conf + subPath: dcmanager.conf + readOnly: true + - name: dcmanager-etc + mountPath: /etc/dcmanager/logging.conf + subPath: logging.conf + readOnly: true + - name: dcmanager-etc + mountPath: /etc/ansible/ansible.cfg + subPath: ansible.cfg + readOnly: true + - name: platform-volume + mountPath: /opt/platform + - name: buildinfo + mountPath: /etc/build.info + readOnly: true + - name: platformconf + mountPath: /etc/platform/platform.conf + readOnly: true + - name: pki-volume + mountPath: /etc/kubernetes/pki + readOnly: true + - name: registry-cert-volume + mountPath: /etc/docker/certs.d/registry.local:9001/registry-cert.crt + readOnly: true + - name: kube-config + mountPath: /etc/kubernetes/admin.conf + readOnly: true + - name: dc-vault-dir + mountPath: {{ .Values.conf.dcmanager.vault.base_path }} + - name: dc-backup-dir + mountPath: {{ .Values.conf.dcmanager.backup.base_path }} +{{- if .Values.ca_certificates.root_ca }} + - name: root-ca + mountPath: /usr/local/share/ca-certificates/root-ca.crt + subPath: ca.crt + readOnly: true +{{- end }} +{{ if $mounts_dcmanager_manager.volumeMounts }}{{ toYaml $mounts_dcmanager_manager.volumeMounts | indent 12 }}{{ end }} + command: + - /tmp/dcmanager-manager.sh + image: "{{ .Values.images.tags.dcmanager }}" + imagePullPolicy: {{ .Values.images.pullPolicy }} +{{ tuple $envAll "dcmanager" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }} + nodeSelector: + {{ .Values.labels.dcmanager.node_selector_key }}: {{ .Values.labels.dcmanager.node_selector_value }} +{{ if $envAll.Values.pod.tolerations.dcmanager.enabled }} +{{ tuple $envAll "dcmanager" | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }} +{{ end }} + affinity: + {{ tuple $envAll "dcmanager" "manager" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }} + volumes: + - name: dcmanager-etc + secret: + secretName: dcmanager-etc + defaultMode: 0644 + - name: dcmanager-bin + configMap: + name: dcmanager-bin + defaultMode: 0755 + - name: platform-volume + hostPath: + path: /opt/platform/ + type: DirectoryOrCreate + - name: kube-config + hostPath: + path: /etc/kubernetes/admin.conf + - name: buildinfo + hostPath: + path: /etc/build.info + - name: platformconf + hostPath: + path: /etc/platform/platform.conf + - name: pki-volume + hostPath: + path: /etc/kubernetes/pki + defaultMode: 0644 + - name: registry-cert-volume + hostPath: + path: /etc/docker/certs.d/registry.local:9001/registry-cert.crt + type: File +{{- if .Values.ca_certificates.root_ca }} + - name: root-ca + secret: + secretName: {{ .Values.ca_certificates.root_ca }} + defaultMode: 0644 +{{- end }} + {{- if and .Values.volume.vault.enabled .Values.manifests.pvc_vault }} + - name: dc-vault-dir + persistentVolumeClaim: + claimName: dc-vault-pvc + {{- else }} + - name: dc-vault-dir + hostPath: + path: {{ .Values.conf.dcmanager.vault.base_path }} + type: DirectoryOrCreate + {{- end }} + {{- if and .Values.volume.backup.enabled .Values.manifests.pvc_backup }} + - name: dc-backup-dir + persistentVolumeClaim: + claimName: dc-backup-pvc + {{- else }} + - name: dc-backup-dir + hostPath: + path: {{ .Values.conf.dcmanager.backup.base_path }} + type: DirectoryOrCreate + {{- end }} +{{ if $mounts_dcmanager_manager.volumes }}{{ toYaml $mounts_dcmanager_manager.volumes | indent 8 }}{{ end }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-orchestrator.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-orchestrator.yaml new file mode 100644 index 0000000..36df04f --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-orchestrator.yaml @@ -0,0 +1,84 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.deployment_orchestrator }} +{{- $envAll := . }} + +{{- $mounts_dcmanager_orchestrator := .Values.pod.mounts.orchestrator.dcmanager }} +{{- $mounts_dcmanager_orchestrator_init := .Values.pod.mounts.orchestrator.init_container }} + +{{- $serviceAccountName := "dcmanager-orchestrator" }} +{{ tuple $envAll "orchestrator" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dcmanager-orchestrator + labels: +{{ tuple $envAll "dcmanager" "orchestrator" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }} +spec: + {{- if not .Values.pod.autoscaling.enabled }} + replicas: {{ .Values.pod.replicas.orchestrator }} + {{- end }} + selector: + matchLabels: +{{ tuple $envAll "dcmanager" "orchestrator" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }} +{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }} + template: + metadata: + {{- with .Values.pod.annotations.orchestrator }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: +{{ tuple $envAll "dcmanager" "orchestrator" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }} + spec: + serviceAccountName: {{ $serviceAccountName }} + initContainers: +{{ tuple $envAll "orchestrator" $mounts_dcmanager_orchestrator_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }} + containers: + - name: dcmanager +{{ tuple $envAll $envAll.Values.pod.resources.orchestrator | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }} + envFrom: + - secretRef: + name: dcmanager-keystone-admin + volumeMounts: + - name: dcmanager-bin + mountPath: /tmp/dcmanager-orchestrator.sh + subPath: dcmanager-orchestrator.sh + readOnly: true + - name: dcmanager-etc + mountPath: /etc/dcmanager/dcmanager.conf + subPath: dcmanager.conf + readOnly: true + - name: dcmanager-etc + mountPath: /etc/dcmanager/logging.conf + subPath: logging.conf + readOnly: true +{{ if $mounts_dcmanager_orchestrator.volumeMounts }}{{ toYaml $mounts_dcmanager_orchestrator.volumeMounts | indent 12 }}{{ end }} + command: + - /tmp/dcmanager-orchestrator.sh + image: "{{ .Values.images.tags.dcmanager }}" + imagePullPolicy: {{ .Values.images.pullPolicy }} +{{ tuple $envAll "dcmanager" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }} + nodeSelector: + {{ .Values.labels.dcmanager.node_selector_key }}: {{ .Values.labels.dcmanager.node_selector_value }} +{{ if $envAll.Values.pod.tolerations.dcmanager.enabled }} +{{ tuple $envAll "dcmanager" | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }} +{{ end }} + affinity: + {{ tuple $envAll "dcmanager" "orchestrator" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }} + volumes: + - name: dcmanager-etc + secret: + secretName: dcmanager-etc + defaultMode: 0644 + - name: dcmanager-bin + configMap: + name: dcmanager-bin + defaultMode: 0755 +{{ if $mounts_dcmanager_orchestrator.volumes }}{{ toYaml $mounts_dcmanager_orchestrator.volumes | indent 8 }}{{ end }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-state.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-state.yaml new file mode 100644 index 0000000..88d9ce4 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/deployment-state.yaml @@ -0,0 +1,84 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.deployment_state }} +{{- $envAll := . }} + +{{- $mounts_dcmanager_state := .Values.pod.mounts.state.dcmanager }} +{{- $mounts_dcmanager_state_init := .Values.pod.mounts.state.init_container }} + +{{- $serviceAccountName := "dcmanager-state" }} +{{ tuple $envAll "state" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dcmanager-state + labels: +{{ tuple $envAll "dcmanager" "state" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }} +spec: + {{- if not .Values.pod.autoscaling.enabled }} + replicas: {{ .Values.pod.replicas.state }} + {{- end }} + selector: + matchLabels: +{{ tuple $envAll "dcmanager" "state" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }} +{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }} + template: + metadata: + {{- with .Values.pod.annotations.state }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: +{{ tuple $envAll "dcmanager" "state" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }} + spec: + serviceAccountName: {{ $serviceAccountName }} + initContainers: +{{ tuple $envAll "state" $mounts_dcmanager_state_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }} + containers: + - name: dcmanager +{{ tuple $envAll $envAll.Values.pod.resources.state | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }} + envFrom: + - secretRef: + name: dcmanager-keystone-admin + volumeMounts: + - name: dcmanager-bin + mountPath: /tmp/dcmanager-state.sh + subPath: dcmanager-state.sh + readOnly: true + - name: dcmanager-etc + mountPath: /etc/dcmanager/dcmanager.conf + subPath: dcmanager.conf + readOnly: true + - name: dcmanager-etc + mountPath: /etc/dcmanager/logging.conf + subPath: logging.conf + readOnly: true +{{ if $mounts_dcmanager_state.volumeMounts }}{{ toYaml $mounts_dcmanager_state.volumeMounts | indent 12 }}{{ end }} + command: + - /tmp/dcmanager-state.sh + image: "{{ .Values.images.tags.dcmanager }}" + imagePullPolicy: {{ .Values.images.pullPolicy }} +{{ tuple $envAll "dcmanager" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }} + nodeSelector: + {{ .Values.labels.dcmanager.node_selector_key }}: {{ .Values.labels.dcmanager.node_selector_value }} +{{ if $envAll.Values.pod.tolerations.dcmanager.enabled }} +{{ tuple $envAll "dcmanager" | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }} +{{ end }} + affinity: + {{ tuple $envAll "dcmanager" "state" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }} + volumes: + - name: dcmanager-etc + secret: + secretName: dcmanager-etc + defaultMode: 0644 + - name: dcmanager-bin + configMap: + name: dcmanager-bin + defaultMode: 0755 +{{ if $mounts_dcmanager_state.volumes }}{{ toYaml $mounts_dcmanager_state.volumes | indent 8 }}{{ end }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/ingress.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/ingress.yaml new file mode 100644 index 0000000..4e221b8 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "dcmanager.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "dcmanager.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-db-drop.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-db-drop.yaml new file mode 100644 index 0000000..8dc2bde --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-db-drop.yaml @@ -0,0 +1,13 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.job_db_drop }} +{{- $dbDropJob := dict "envAll" . "serviceName" "dcmanager" -}} +{{- if .Values.pod.tolerations.dcmanager.enabled -}} +{{- $_ := set $dbDropJob "tolerationsEnabled" true -}} +{{- end -}} +{{ $dbDropJob | include "helm-toolkit.manifests.job_db_drop_mysql" }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-db-init.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-db-init.yaml new file mode 100644 index 0000000..cbaf6ef --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-db-init.yaml @@ -0,0 +1,13 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.job_db_init }} +{{- $dbInitJob := dict "envAll" . "serviceName" "dcmanager" -}} +{{- if .Values.pod.tolerations.dcmanager.enabled -}} +{{- $_ := set $dbInitJob "tolerationsEnabled" true -}} +{{- end -}} +{{ $dbInitJob | include "helm-toolkit.manifests.job_db_init_mysql" }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-db-sync.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-db-sync.yaml new file mode 100644 index 0000000..15b0dc6 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-db-sync.yaml @@ -0,0 +1,13 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.job_db_sync }} +{{- $dbSyncJob := dict "envAll" . "serviceName" "dcmanager" -}} +{{- if .Values.pod.tolerations.dcmanager.enabled -}} +{{- $_ := set $dbSyncJob "tolerationsEnabled" true -}} +{{- end -}} +{{ $dbSyncJob | include "helm-toolkit.manifests.job_db_sync" }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-ks-endpoints.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-ks-endpoints.yaml new file mode 100644 index 0000000..347beb2 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-ks-endpoints.yaml @@ -0,0 +1,16 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.job_ks_endpoints }} +{{- $ksServiceJob := dict "envAll" . "serviceName" "dcmanager" "serviceTypes" ( tuple "dcmanager" ) -}} +{{- if .Values.manifests.certificates -}} +{{- $_ := set $ksServiceJob "tlsSecret" .Values.secrets.tls.dcmanager.api.public -}} +{{- end -}} +{{- if .Values.pod.tolerations.dcmanager.enabled -}} +{{- $_ := set $ksServiceJob "tolerationsEnabled" true -}} +{{- end -}} +{{ $ksServiceJob | include "helm-toolkit.manifests.job_ks_endpoints" }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-ks-service.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-ks-service.yaml new file mode 100644 index 0000000..ea4e512 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-ks-service.yaml @@ -0,0 +1,16 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.job_ks_service }} +{{- $ksServiceJob := dict "envAll" . "serviceName" "dcmanager" "serviceTypes" ( tuple "dcmanager" ) -}} +{{- if .Values.manifests.certificates -}} +{{- $_ := set $ksServiceJob "tlsSecret" .Values.secrets.tls.dcmanager.api.public -}} +{{- end -}} +{{- if .Values.pod.tolerations.dcmanager.enabled -}} +{{- $_ := set $ksServiceJob "tolerationsEnabled" true -}} +{{- end -}} +{{ $ksServiceJob | include "helm-toolkit.manifests.job_ks_service" }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-ks-user.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-ks-user.yaml new file mode 100644 index 0000000..ff44a75 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/job-ks-user.yaml @@ -0,0 +1,16 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.job_ks_user }} +{{- $ksUserJob := dict "envAll" . "serviceName" "dcmanager" -}} +{{- if .Values.pod.tolerations.dcmanager.enabled -}} +{{- $_ := set $ksUserJob "tolerationsEnabled" true -}} +{{- end -}} +{{- if .Values.manifests.certificates -}} +{{- $_ := set $ksUserJob "tlsSecret" .Values.secrets.tls.dcmanager.api.public -}} +{{- end -}} +{{ $ksUserJob | include "helm-toolkit.manifests.job_ks_user" }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/pvc-backup.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/pvc-backup.yaml new file mode 100644 index 0000000..2e37d9f --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/pvc-backup.yaml @@ -0,0 +1,19 @@ +# {{/* +# # +# # SPDX-License-Identifier: Apache-2.0 +# # +# */}} + +# {{- if and .Values.volume.backup.enabled .Values.manifests.pvc_backup }} +# --- +# kind: PersistentVolumeClaim +# apiVersion: v1 +# metadata: +# name: dc-backup-pvc +# spec: +# accessModes: {{ .Values.volume.backup.accessModes }} +# resources: +# requests: +# storage: {{ .Values.volume.backup.size }} +# storageClassName: {{ .Values.volume.backup.class_name }} +# {{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/pvc-vault.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/pvc-vault.yaml new file mode 100644 index 0000000..47f3dae --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/pvc-vault.yaml @@ -0,0 +1,19 @@ +# {{/* +# # +# # SPDX-License-Identifier: Apache-2.0 +# # +# */}} + +# {{- if and .Values.volume.vault.enabled .Values.manifests.pvc_vault }} +# --- +# kind: PersistentVolumeClaim +# apiVersion: v1 +# metadata: +# name: dc-vault-pvc +# spec: +# accessModes: {{ .Values.volume.vault.accessModes }} +# resources: +# requests: +# storage: {{ .Values.volume.vault.size }} +# storageClassName: {{ .Values.volume.vault.class_name }} +# {{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-db.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-db.yaml new file mode 100644 index 0000000..3502d91 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-db.yaml @@ -0,0 +1,21 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.secret_db }} +{{- $envAll := . }} +{{- range $key1, $userClass := tuple "admin" "dcmanager" }} +{{- $secretName := index $envAll.Values.secrets.oslo_db $userClass }} +{{- $connection := tuple "oslo_db" "internal" $userClass "postgresql" $envAll | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ $secretName }} +type: Opaque +data: + DB_CONNECTION: {{ $connection | b64enc -}} +{{- end }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-etc.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-etc.yaml new file mode 100644 index 0000000..7f03f47 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-etc.yaml @@ -0,0 +1,72 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if empty .Values.conf.dcmanager.database.connection -}} +{{- $connection := tuple "oslo_db" "internal" "dcmanager" "postgresql" . | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" -}} +{{- $_ := set .Values.conf.dcmanager.database "connection" $connection -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.DEFAULT.sql_connection -}} +{{- $_ := tuple "oslo_db" "internal" "dcmanager" "postgresql" . | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup"| set .Values.conf.dcmanager.DEFAULT "sql_connection" -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.keystone_authtoken.auth_uri -}} +{{- $_ := tuple "identity" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup"| set .Values.conf.dcmanager.keystone_authtoken "auth_uri" -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.keystone_authtoken.auth_url -}} +{{- $_ := tuple "identity" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup"| set .Values.conf.dcmanager.keystone_authtoken "auth_url" -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.keystone_authtoken.region_name -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "region_name" .Values.endpoints.identity.auth.dcmanager.region_name -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.keystone_authtoken.project_name -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "project_name" .Values.endpoints.identity.auth.dcmanager.project_name -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.keystone_authtoken.project_domain_name -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "project_domain_name" .Values.endpoints.identity.auth.dcmanager.project_domain_name -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.keystone_authtoken.user_domain_name -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "user_domain_name" .Values.endpoints.identity.auth.dcmanager.user_domain_name -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.keystone_authtoken.username -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "username" .Values.endpoints.identity.auth.dcmanager.username -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.keystone_authtoken.password -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "password" .Values.endpoints.identity.auth.dcmanager.password -}} +{{- end -}} + +{{- if empty .Values.conf.dcmanager.keystone_authtoken.interface -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "interface" (default "internal" .Values.endpoints.identity.auth.dcmanager.interface) -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.endpoint_cache.auth_uri -}} +{{- $_ := tuple "identity" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup"| set .Values.conf.dcmanager.keystone_authtoken "auth_uri" -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.endpoint_cache.region_name -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "region_name" .Values.endpoints.identity.auth.dcmanager.region_name -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.endpoint_cache.project_name -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "project_name" .Values.endpoints.identity.auth.dcmanager.project_name -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.endpoint_cache.project_domain_name -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "project_domain_name" .Values.endpoints.identity.auth.dcmanager.project_domain_name -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.endpoint_cache.user_domain_name -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "user_domain_name" .Values.endpoints.identity.auth.dcmanager.user_domain_name -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.endpoint_cache.username -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "username" .Values.endpoints.identity.auth.dcmanager.username -}} +{{- end -}} +{{- if empty .Values.conf.dcmanager.endpoint_cache.password -}} +{{- $_ := set .Values.conf.dcmanager.keystone_authtoken "password" .Values.endpoints.identity.auth.dcmanager.password -}} +{{- end -}} + +apiVersion: v1 +kind: Secret +metadata: + name: dcmanager-etc +type: Opaque +data: + dcmanager.conf: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.dcmanager | b64enc }} + logging.conf: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.logging | b64enc }} + ansible.cfg: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.ansible | b64enc }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-keystone.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-keystone.yaml new file mode 100644 index 0000000..7206f73 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-keystone.yaml @@ -0,0 +1,20 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.secret_keystone }} +{{- $envAll := . }} +{{- range $key1, $userClass := tuple "admin" "dcmanager" }} +{{- $secretName := index $envAll.Values.secrets.identity $userClass }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ $secretName }} +type: Opaque +data: +{{- tuple $userClass "internal" $envAll | include "helm-toolkit.snippets.keystone_secret_openrc" | indent 2 -}} +{{- end }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-rabbitmq.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-rabbitmq.yaml new file mode 100644 index 0000000..f2ecfc1 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/secret-rabbitmq.yaml @@ -0,0 +1,20 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.secret_rabbitmq }} +{{- $envAll := . }} +{{- range $key1, $userClass := tuple "admin" "dcmanager" }} +{{- $secretName := index $envAll.Values.secrets.oslo_messaging $userClass }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ $secretName }} +type: Opaque +data: + RABBITMQ_CONNECTION: {{ tuple "oslo_messaging" "internal" $userClass "amqp" $envAll | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" | b64enc }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/service.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/service.yaml new file mode 100644 index 0000000..0a8047f --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/templates/service.yaml @@ -0,0 +1,29 @@ +{{/* +# +# SPDX-License-Identifier: Apache-2.0 +# +*/}} + +{{- if .Values.manifests.service_dcmanager }} +{{- $envAll := . }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ tuple "dcmanager" "internal" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }} +spec: + ports: + - name: dcmanger-port + port: {{ .Values.network.dcmanager.port }} + {{ if .Values.network.dcmanager.node_port.enabled }} + nodePort: {{ .Values.network.dcmanager.node_port.port }} + {{ end }} + selector: +{{ tuple $envAll "dcmanager" "api" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }} + {{ if .Values.network.dcmanager.node_port.enabled }} + type: NodePort + {{ if .Values.network.dcmanager.external_policy_local }} + externalTrafficPolicy: Local + {{ end }} + {{ end }} +{{- end }} diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/values.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/values.yaml new file mode 100644 index 0000000..dcbd2f3 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcmanager/values.yaml @@ -0,0 +1,479 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Default values for dcmanager. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +nameOverride: "" +fullnameOverride: "" + +images: + tags: + dcmanager: docker.io/starlingx/stx-distributed-cloud:master-debian-stable-latest + ks_user: docker.io/starlingx/stx-distributed-cloud:master-debian-stable-latest + ks_service: docker.io/starlingx/stx-distributed-cloud:master-debian-stable-latest + ks_endpoints: docker.io/starlingx/stx-distributed-cloud:master-debian-stable-latest + dcmanager_db_sync: docker.io/starlingx/stx-distributed-cloud:master-debian-stable-latest + db_init: docker.io/starlingx/stx-distributed-cloud:master-debian-stable-latest + db_drop: docker.io/starlingx/stx-distributed-cloud:master-debian-stable-latest + rabbit_init: docker.io/rabbitmq:3.7-management + dep_check: quay.io/stackanetes/kubernetes-entrypoint:v0.3.1 + pullPolicy: IfNotPresent + local_registry: + active: false + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +labels: + dcmanager: + node_selector_key: starlingx.io/distributed-cloud + node_selector_value: enabled + job: + node_selector_key: starlingx.io/distributed-cloud + node_selector_value: enabled + +network: + dcmanager: + ingress: + public: true + classes: + namespace: "nginx" + cluster: "nginx-cluster" + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / + port: 8119 + node_port: + enabled: false + port: 30119 + external_policy_local: false + +ingress: + enabled: false + annotations: {} + paths: [] + hosts: + - dcmanager-api + tls: [] + +volume: + vault: + enabled: true + accessModes: + - ReadWriteMany + class_name: cephfs + size: 15Gi + backup: + enabled: false + accessModes: + - ReadWriteMany + class_name: cephfs + size: 10Gi + +conf: + dcmanager: + DEFAULT: + log_config_append: /etc/dcmanager/logging.conf + auth_strategy: keystone + playbook_timeout: 3600 + use_usm: False + workers: 1 + orch_workers: 1 + state_workers: 1 + audit_workers: 1 + audit_worker_workers: 1 + database: + connection_recycle_time: 3600 + max_pool_size: 105 + max_overflow: 100 + keystone_authtoken: + interface: internal + auth_uri: http://controller.internal:5000 + auth_version: v3 + auth_type: password + http_connect_timeout: 15 + http_request_max_retries: 3 + region_name: RegionOne + auth_url: http://controller.internal:5000 + project_name: services + user_domain_name: Default + project_domain_name: Default + cache: + auth_uri: http://controller.internal:5000/v3 + admin_tenant: admin + endpoint_cache: + region_name: RegionOne + auth_uri: http://controller.internal:5000/v3 + auth_plugin: password + project_name: services + user_domain_name: Default + project_domain_name: Default + http_connect_timeout: 15 + vault: + base_path: /opt/dc-vault + backup: + base_path: /opt/dc-vault/backups + deploy: + version: 25.09 + base_path: /opt/dc-vault/deploy/ + logging: + loggers: + keys: + - root + - dcmanager + handlers: + keys: + - stdout + - stderr + - "null" + formatters: + keys: + - context + - default + logger_root: + level: WARNING + handlers: 'null' + logger_dcmanager: + level: INFO + handlers: + - stdout + qualname: dcmanager + logger_eventletwsgi: + level: WARNING + handlers: stderr + qualname: eventlet.wsgi.server + logger_keystoneauth: + level: ERROR + handlers: stderr + qualname: keystoneauth + logger_sqlalchemy: + level: WARNING + handlers: stderr + qualname: sqlalchemy + handler_null: + class: logging.NullHandler + formatter: default + args: () + handler_stdout: + class: StreamHandler + args: (sys.stdout,) + formatter: context + handler_stderr: + class: StreamHandler + args: (sys.stderr,) + formatter: context + formatter_context: + class: oslo_log.formatters.ContextFormatter + formatter_default: + format: "%(message)s" + ansible: + defaults: + interpreter_python: auto_silent + +dependencies: + static: + api: + jobs: + - dcmanager-ks-user + - dcmanager-ks-service + - dcmanager-ks-endpoints + ks_endpoints: + jobs: + - dcmanager-ks-user + - dcmanager-ks-service + +manifests: + certificates: false + configmap_bin: true + deployment_api: true + deployment_manager: true + deployment_audit: true + deployment_state: true + deployment_orchestrator: true + ingress: true + job_ks_user: true + job_ks_service: true + job_ks_endpoints: true + job_db_init: false + job_db_sync: false + job_db_drop: false + job_rabbit_init: false + secret_etc: true + secret_db: true + secret_ingress_tls: false + secret_rabbitmq: true + secret_keystone: true + service_dcmanager: true + service_ingress: true + pvc_vault: true + pvc_backup: false + +endpoints: + cluster_domain_suffix: cluster.local + oslo_db: + auth: + admin: + username: admin + password: password + dcmanager: + username: dcmanager + password: password + hosts: + default: postgresql + host_fqdn_override: + default: controller.internal + port: + postgresql: + default: 5432 + path: /dcmanager + scheme: postgresql+psycopg2 + oslo_messaging: + auth: + admin: + username: admin + password: password + dcmanager: + username: dcmanager + password: password + hosts: + default: rabbitmq + host_fqdn_override: + default: controller.internal + path: / + scheme: rabbit + port: + amqp: + default: 5672 + http: + default: 15672 + identity: + name: keystone + auth: + admin: + username: admin + password: password + region_name: SystemController + project_name: admin + user_domain_name: Default + project_domain_name: Default + dcmanager: + role: admin + username: dcmanager + password: password + region_name: SystemController + project_name: services + user_domain_name: Default + project_domain_name: Default + hosts: + default: keystone-api + public: keystone + host_fqdn_override: + default: controller.internal + path: + default: /v3 + scheme: + default: http + port: + api: + default: 5000 + internal: 5000 + dcmanager: + name: dcmanager + hosts: + default: dcmanager-api + public: dcmanager + host_fqdn_override: + default: null + path: + default: /v1.0 + scheme: + default: 'http' + port: + api: + default: 8119 + public: 80 + +ca_certificates: + root_ca: root-ca + +pod: + probes: + api: + default: + liveness: + enabled: True + params: + initialDelaySeconds: 120 + periodSeconds: 90 + timeoutSeconds: 70 + user: + api: + uid: 0 + affinity: + anti: + type: + default: preferredDuringSchedulingIgnoredDuringExecution + topologyKey: + default: kubernetes.io/hostname + annotations: {} + tolerations: + dcmanager: + enabled: false + tolerations: + - key: node-role.kubernetes.io/master + operator: Exists + effect: NoSchedule + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: NoSchedule + mounts: + api: + init_container: null + dcmanager: + manager: + init_container: null + dcmanager: + audit: + init_container: null + dcmanager: + state: + init_container: null + dcmanager: + orchestrator: + init_container: null + dcmanager: + autoscaling: + enabled: false + replicas: + api: 1 + manager: 1 + audit: 1 + audit_worker: 5 + state: 5 + orchestrator: 1 + lifecycle: + upgrades: + deployments: + revision_history: 3 + pod_replacement_strategy: RollingUpdate + rolling_update: + max_unavailable: 1 + max_surge: 3 + daemonsets: + pod_replacement_strategy: RollingUpdate + compute: + enabled: true + min_ready_seconds: 0 + max_unavailable: 1 + disruption_budget: + dcmanager: + min_available: 0 + termination_grace_period: + dcmanager: + timeout: 30 + resources: + enabled: false + api: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + manager: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + state: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + orchestrator: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + audit: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + audit_worker: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + jobs: + ks_endpoints: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + db_init: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + db_sync: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + db_drop: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + rabbit_init: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1024Mi" + cpu: "2000m" + +secrets: + identity: + admin: dcmanager-keystone-admin + dcmanager: dcmanager-keystone-user + oslo_db: + admin: dcmanager-db-admin + dcmanager: dcmanager-db-user + oslo_messaging: + admin: dcmanager-rabbitmq-admin + dcmanager: dcmanager-rabbitmq-user + tls: + dcmanager: + api: + public: dcmanager-api-tls-public + internal: dcmanager-api-tls-internal diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/.helmignore b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/Chart.yaml b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/Chart.yaml new file mode 100644 index 0000000..d26e019 --- /dev/null +++ b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/Chart.yaml @@ -0,0 +1,29 @@ +apiVersion: v2 +name: dcorch +description: StarlingX Distributed Cloud Orchestrator Service + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.0" + +dependencies: + - name: helm-toolkit + version: ">= 0.1.0" + repository: file://../helm-toolkit diff --git a/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/charts/helm-toolkit-0.2.59.tgz b/stx-distributed-cloud-helm/stx-distributed-cloud-helm/helm-charts/dcorch/charts/helm-toolkit-0.2.59.tgz new file mode 100644 index 0000000000000000000000000000000000000000..9dcfef6acfe94e7c81e71ae63102460a6cb99c04 GIT binary patch literal 52000 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