diff --git a/.github/workflows/helm-freezer.yaml b/.github/workflows/helm-freezer.yaml new file mode 100644 index 00000000..086543e0 --- /dev/null +++ b/.github/workflows/helm-freezer.yaml @@ -0,0 +1,51 @@ +--- +name: Helm GitHub Actions for Freezer + +on: + pull_request: + paths: + - base-helm-configs/freezer/** + - base-kustomize/freezer/** + - .github/workflows/helm-freezer.yaml +jobs: + helm: + strategy: + matrix: + overlays: + - base + - aio + name: Helm + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: azure/setup-helm@v3 + with: + version: latest + token: "${{ secrets.GITHUB_TOKEN }}" + id: helm + - name: Kubectl Install + working-directory: /usr/local/bin/ + run: | + if [ ! -f /usr/local/bin/kubectl ]; then + curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x ./kubectl + fi + - name: Pull OSH repositories + run: | + helm repo add openstack-helm https://tarballs.opendev.org/openstack/openstack-helm + helm repo update + - name: Run Helm Template + run: | + ${{ steps.helm.outputs.helm-path }} template freezer openstack-helm/freezer \ + --namespace=openstack \ + --wait \ + --timeout 120m \ + -f ${{ github.workspace }}/base-helm-configs/freezer/freezer-helm-overrides.yaml \ + --post-renderer ${{ github.workspace }}/base-kustomize/kustomize.sh \ + --post-renderer-args freezer/${{ matrix.overlays }} > /tmp/rendered.yaml + - name: Return helm Build + uses: actions/upload-artifact@v4 + with: + name: helm-freezer-artifact-${{ matrix.overlays }} + path: /tmp/rendered.yaml diff --git a/base-helm-configs/freezer/freezer-helm-overrides.yaml b/base-helm-configs/freezer/freezer-helm-overrides.yaml new file mode 100644 index 00000000..7f82f7dd --- /dev/null +++ b/base-helm-configs/freezer/freezer-helm-overrides.yaml @@ -0,0 +1,64 @@ +--- +endpoints: + backup: + hosts: + public: freezer-api + oslo_db: + host_fqdn_override: + default: mariadb-cluster-primary.openstack.svc.cluster.local + hosts: + default: mariadb-cluster-primary + oslo_messaging: + hosts: + default: rabbitmq-nodes + host_fqdn_override: + default: rabbitmq.openstack.svc.cluster.local + oslo_cache: + hosts: + default: memcached + host_fqdn_override: + default: memcached.openstack.svc.cluster.local + fluentd: + namespace: fluentbit + +dependencies: + static: + api: + jobs: + - freezer-db-sync + - freezer-ks-user + - freezer-ks-endpoints + db_sync: + jobs: null + +conf: + freezer: + DEFAULT: + host_href: "http://freezer-api.openstack.svc.cluster.local:9090" + database: + connection_debug: 0 + connection_recycle_time: 600 + connection_trace: true + idle_timeout: 3600 + mysql_sql_mode: {} + use_db_reconnect: true + pool_timeout: 60 + max_retries: -1 + keystone_authtoken: + service_token_roles: service + service_token_roles_required: true + auth_type: password + auth_version: v3 + memcache_security_strategy: ENCRYPT + service_type: backup + logging: + logger_root: + handlers: + - stdout + level: INFO + +manifests: + ingress_api: false + job_rabbit_init: false + service_ingress_api: false + job_db_init: false diff --git a/base-kustomize/freezer/aio/kustomization.yaml b/base-kustomize/freezer/aio/kustomization.yaml new file mode 100644 index 00000000..67ffe3cd --- /dev/null +++ b/base-kustomize/freezer/aio/kustomization.yaml @@ -0,0 +1,5 @@ +--- +sortOptions: + order: fifo +resources: + - ../base diff --git a/base-kustomize/freezer/base/freezer-mariadb-database.yaml b/base-kustomize/freezer/base/freezer-mariadb-database.yaml new file mode 100644 index 00000000..60b8a8ef --- /dev/null +++ b/base-kustomize/freezer/base/freezer-mariadb-database.yaml @@ -0,0 +1,62 @@ +--- +apiVersion: k8s.mariadb.com/v1alpha1 +kind: Database +metadata: + name: freezer + namespace: openstack + labels: + app.kubernetes.io/managed-by: "Helm" + annotations: + helm.sh/resource-policy: keep + meta.helm.sh/release-name: "freezer" + meta.helm.sh/release-namespace: "openstack" +spec: + mariaDbRef: + name: mariadb-cluster + characterSet: utf8 + collate: utf8_general_ci + retryInterval: 5s +--- +apiVersion: k8s.mariadb.com/v1alpha1 +kind: User +metadata: + name: freezer + namespace: openstack + labels: + app.kubernetes.io/managed-by: "Helm" + annotations: + helm.sh/resource-policy: keep + meta.helm.sh/release-name: "freezer" + meta.helm.sh/release-namespace: "openstack" +spec: + mariaDbRef: + name: mariadb-cluster + passwordSecretKeyRef: + name: freezer-db-password + key: password + maxUserConnections: 0 + host: "%" + retryInterval: 5s +--- +apiVersion: k8s.mariadb.com/v1alpha1 +kind: Grant +metadata: + name: freezer-grant + namespace: openstack + labels: + app.kubernetes.io/managed-by: "Helm" + annotations: + helm.sh/resource-policy: keep + meta.helm.sh/release-name: "freezer" + meta.helm.sh/release-namespace: "openstack" +spec: + mariaDbRef: + name: mariadb-cluster + privileges: + - "ALL" + database: "freezer" + table: "*" + username: freezer + grantOption: true + host: "%" + retryInterval: 5s diff --git a/base-kustomize/freezer/base/hpa-freezer-api.yaml b/base-kustomize/freezer/base/hpa-freezer-api.yaml new file mode 100644 index 00000000..58f91958 --- /dev/null +++ b/base-kustomize/freezer/base/hpa-freezer-api.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: freezer-api + namespace: openstack +spec: + maxReplicas: 9 + minReplicas: 2 + metrics: + - resource: + name: cpu + target: + averageUtilization: 80 + type: Utilization + type: Resource + - resource: + name: memory + target: + averageUtilization: 80 + type: Utilization + type: Resource + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: freezer-api diff --git a/base-kustomize/freezer/base/kustomization.yaml b/base-kustomize/freezer/base/kustomization.yaml new file mode 100644 index 00000000..6c566f47 --- /dev/null +++ b/base-kustomize/freezer/base/kustomization.yaml @@ -0,0 +1,7 @@ +--- +sortOptions: + order: fifo +resources: + - freezer-mariadb-database.yaml + - hpa-freezer-api.yaml + - all.yaml diff --git a/bin/create-secrets.sh b/bin/create-secrets.sh index 5b77a4fa..6532b691 100755 --- a/bin/create-secrets.sh +++ b/bin/create-secrets.sh @@ -103,6 +103,9 @@ blazar_rabbitmq_password=$(generate_password 64) blazar_db_password=$(generate_password 32) blazar_admin_password=$(generate_password 32) blazar_keystone_test_password=$(generate_password 32) +freezer_db_password=$(generate_password 32) +freezer_admin_password=$(generate_password 32) +freezer_keystone_test_password=$(generate_password 32) OUTPUT_FILE="/etc/genestack/kubesecrets.yaml" @@ -731,6 +734,33 @@ metadata: type: Opaque data: password: $(echo -n $blazar_keystone_test_password | base64 -w0) +--- +apiVersion: v1 +kind: Secret +metadata: + name: freezer-db-password + namespace: openstack +type: Opaque +data: + password: $(echo -n $freezer_db_password | base64 -w0) +--- +apiVersion: v1 +kind: Secret +metadata: + name: freezer-admin + namespace: openstack +type: Opaque +data: + password: $(echo -n $freezer_admin_password | base64 -w0) +--- +apiVersion: v1 +kind: Secret +metadata: + name: freezer-keystone-test-password + namespace: openstack +type: Opaque +data: + password: $(echo -n $freezer_keystone_test_password | base64 -w0) EOF rm nova_ssh_key nova_ssh_key.pub diff --git a/bin/install-freezer.sh b/bin/install-freezer.sh new file mode 100755 index 00000000..a1fa72f0 --- /dev/null +++ b/bin/install-freezer.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +GLOBAL_OVERRIDES_DIR="/etc/genestack/helm-configs/global_overrides" +SERVICE_CONFIG_DIR="/etc/genestack/helm-configs/freezer" +BASE_OVERRIDES="/opt/genestack/base-helm-configs/freezer/freezer-helm-overrides.yaml" + +# Read freezer version from helm-chart-versions.yaml +VERSION_FILE="/etc/genestack/helm-chart-versions.yaml" +if [ ! -f "$VERSION_FILE" ]; then + echo "Error: helm-chart-versions.yaml not found at $VERSION_FILE" + exit 1 +fi + +# Extract freezer version using grep and sed +FREEZER_VERSION=$(grep 'freezer:' "$VERSION_FILE" | sed 's/.*freezer: *//') + +if [ -z "$FREEZER_VERSION" ]; then + echo "Error: Could not extract freezer version from $VERSION_FILE" + exit 1 +fi + +HELM_CMD="helm upgrade --install freezer openstack-helm/freezer --version ${FREEZER_VERSION} \ + --namespace=openstack \ + --timeout 120m" + +HELM_CMD+=" -f ${BASE_OVERRIDES}" + +# Append YAML files from the directories +for dir in "$GLOBAL_OVERRIDES_DIR" "$SERVICE_CONFIG_DIR"; do + if compgen -G "${dir}/*.yaml" > /dev/null; then + for yaml_file in "${dir}"/*.yaml; do + HELM_CMD+=" -f ${yaml_file}" + done + fi +done + +HELM_CMD+=" --set endpoints.identity.auth.admin.password=\"$(kubectl --namespace openstack get secret keystone-admin -o jsonpath='{.data.password}' | base64 -d)\"" +HELM_CMD+=" --set endpoints.identity.auth.freezer.password=\"$(kubectl --namespace openstack get secret freezer-admin -o jsonpath='{.data.password}' | base64 -d)\"" +HELM_CMD+=" --set endpoints.identity.auth.test.password=\"$(kubectl --namespace openstack get secret freezer-keystone-test-password -o jsonpath='{.data.password}' | base64 -d)\"" +HELM_CMD+=" --set endpoints.oslo_db.auth.admin.password=\"$(kubectl --namespace openstack get secret mariadb -o jsonpath='{.data.root-password}' | base64 -d)\"" +HELM_CMD+=" --set endpoints.oslo_db.auth.freezer.password=\"$(kubectl --namespace openstack get secret freezer-db-password -o jsonpath='{.data.password}' | base64 -d)\"" +HELM_CMD+=" --set endpoints.oslo_cache.auth.memcache_secret_key=\"$(kubectl --namespace openstack get secret os-memcached -o jsonpath='{.data.memcache_secret_key}' | base64 -d)\"" +HELM_CMD+=" --set conf.freezer.keystone_authtoken.memcache_secret_key=\"$(kubectl --namespace openstack get secret os-memcached -o jsonpath='{.data.memcache_secret_key}' | base64 -d)\"" + + +HELM_CMD+=" --post-renderer /etc/genestack/kustomize/kustomize.sh" +HELM_CMD+=" --post-renderer-args freezer/overlay" + +helm repo add openstack-helm https://tarballs.opendev.org/openstack/openstack-helm +helm repo update + +HELM_CMD+=" $@" + +echo "Executing Helm command:" +echo "${HELM_CMD}" +eval "${HELM_CMD}" diff --git a/bin/setup-openstack.sh b/bin/setup-openstack.sh index 4016e3ee..45967f05 100755 --- a/bin/setup-openstack.sh +++ b/bin/setup-openstack.sh @@ -61,6 +61,7 @@ EOF prompt_component "ceilometer" "Ceilometer (Telemetry)" prompt_component "gnocchi" "Gnocchi (Time Series Database)" prompt_component "skyline" "Skyline (Dashboard)" + prompt_component "freezer" "Freezer (Backup Restore)" fi # Block on Keystone @@ -80,6 +81,7 @@ is_component_enabled "octavia" && runTrackErator /opt/genestack/bin/install-octa is_component_enabled "masakari" && runTrackErator /opt/genestack/bin/install-masakari.sh is_component_enabled "ceilometer" && runTrackErator /opt/genestack/bin/install-ceilometer.sh is_component_enabled "gnocchi" && runTrackErator /opt/genestack/bin/install-gnocchi.sh +is_component_enabled "freezer" && runTrackErator /opt/genestack/bin/install-freezer.sh waitErator diff --git a/docs/genestack-components.md b/docs/genestack-components.md index 2b25135f..b03d3986 100644 --- a/docs/genestack-components.md +++ b/docs/genestack-components.md @@ -41,6 +41,7 @@ and largely deployed with Helm+Kustomize against the K8s API (v1.28 and up). | OpenStack | Magnum (Helm) | Optional | | OpenStack | Masakari (Helm) | Optional | | OpenStack | Blazar (Helm) | Optional | +| OpenStack | Freezer (Helm) | Optional | | OpenStack | metal3.io | Planned | | OpenStack | PostgreSQL (Operator) | Included | | OpenStack | Consul | Planned | diff --git a/docs/openstack-freezer.md b/docs/openstack-freezer.md new file mode 100644 index 00000000..dc26b0fb --- /dev/null +++ b/docs/openstack-freezer.md @@ -0,0 +1,51 @@ +# Deploy Freezer + +Freezer is a disaster recovery and backup-as-a-service component for OpenStack. +It provides a way to back up various resources, such as virtual machine instances, +databases, and file systems. + +It allows users to schedule backups, restore data, and manage the lifecycle of their +backups to ensure data protection and business continuity within an OpenStack cloud. + +This document outlines the deployment of OpenStack Freezer using Genestack. + +## Create secrets + +!!! note "Information about the secrets used" + + Manual secret generation is only required if you haven't run the + `create-secrets.sh` script located in `/opt/genestack/bin`. + + ??? example "Example secret generation" + + ``` shell + kubectl --namespace openstack \ + create secret generic freezer-db-password \ + --type Opaque \ + --from-literal=password="$(< /dev/urandom tr -dc _A-Za-z0-9 | head -c${1:-32};echo;)" + kubectl --namespace openstack \ + create secret generic freezer-admin \ + --type Opaque \ + --from-literal=password="$(< /dev/urandom tr -dc _A-Za-z0-9 | head -c${1:-32};echo;)" + ``` + +## Run the package deployment + +!!! example "Run the Freezer deployment Script `/opt/genestack/bin/install-freezer.sh`" + + ``` shell + --8<-- "bin/install-freezer.sh" + ``` + +!!! tip + + You may need to provide custom values to configure your OpenStack services. + For a simple single region or lab deployment you can supply an additional + overrides flag using the example found at + `base-helm-configs/aio-example-openstack-overrides.yaml`. + +## Validate functionality + +``` shell +kubectl --namespace openstack exec -ti openstack-admin-client -- freezer host-list +``` diff --git a/etc/gateway-api/listeners/freezer-https.json b/etc/gateway-api/listeners/freezer-https.json new file mode 100644 index 00000000..c823f255 --- /dev/null +++ b/etc/gateway-api/listeners/freezer-https.json @@ -0,0 +1,27 @@ +[ + { + "op": "add", + "path": "/spec/listeners/-", + "value": { + "name": "freezer-https", + "port": 443, + "protocol": "HTTPS", + "hostname": "freezer.your.domain.tld", + "allowedRoutes": { + "namespaces": { + "from": "All" + } + }, + "tls": { + "certificateRefs": [ + { + "group": "", + "kind": "Secret", + "name": "freezer-gw-tls-secret" + } + ], + "mode": "Terminate" + } + } + } +] diff --git a/etc/gateway-api/routes/custom-freezer-gateway-route.yaml b/etc/gateway-api/routes/custom-freezer-gateway-route.yaml new file mode 100644 index 00000000..6de7a0da --- /dev/null +++ b/etc/gateway-api/routes/custom-freezer-gateway-route.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: custom-freezer-gateway-route + namespace: openstack +spec: + parentRefs: + - name: flex-gateway + sectionName: freezer-https + namespace: nginx-gateway + hostnames: + - "freezer.your.domain.tld" + rules: + - backendRefs: + - name: freezer-api + port: 9090 diff --git a/helm-chart-versions.yaml b/helm-chart-versions.yaml index 34c54a15..21131f81 100644 --- a/helm-chart-versions.yaml +++ b/helm-chart-versions.yaml @@ -5,6 +5,7 @@ charts: cinder: 2024.2.409+13651f45-628a320c envoy: v1.4.2 fluentbit: 0.52.0 + freezer: 2025.1.1+a4df9c709 glance: 2024.2.396+13651f45-628a320c gnocchi: 2024.2.50+628a320c grafana: 9.2.2 diff --git a/mkdocs.yml b/mkdocs.yml index da6e2924..6544553e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -223,6 +223,7 @@ nav: - Gnocchi: openstack-gnocchi.md - Ceilometer: openstack-ceilometer.md - Blazar: openstack-blazar.md + - Freezer: openstack-freezer.md - Monitoring: - Monitoring Overview: prometheus-monitoring-overview.md - Getting Started: monitoring-getting-started.md @@ -321,6 +322,8 @@ nav: - Resource and Project Lookups: openstack-resource-lookups.md - Reservation: - Blazar Reservations Creation: openstack-blazar.md + - Backup Restore: + - Freezer Backup Restore Creation: openstack-freezer.md - Working locally With Docs: mkdocs-howto.md - Cloud Onboarding: diff --git a/scripts/hyperconverged-lab.sh b/scripts/hyperconverged-lab.sh index 7770249b..dcc426cf 100755 --- a/scripts/hyperconverged-lab.sh +++ b/scripts/hyperconverged-lab.sh @@ -31,6 +31,7 @@ components: barbican: false blazar: false cinder: true + freezer: true placement: true nova: true neutron: true @@ -874,10 +875,24 @@ endpoints: public: 443 scheme: public: https + backup: + host_fqdn_override: + public: + tls: {} + host: freezer.${GATEWAY_DOMAIN} + port: + api: + public: 443 + scheme: + public: https identity: auth: admin: region_name: *region + service: + region_name: *region + test: + region_name: *region barbican: region_name: *region blazar: @@ -886,6 +901,8 @@ endpoints: region_name: *region ceilometer: region_name: *region + freezer: + region_name: *region glance: region_name: *region gnocchi: diff --git a/testing/deploy.yaml b/testing/deploy.yaml index 328f709c..7a5eabfa 100644 --- a/testing/deploy.yaml +++ b/testing/deploy.yaml @@ -315,6 +315,9 @@ - name: Install cinder command: /opt/genestack/bin/install-cinder.sh + - name: Install freezer + command: /opt/genestack/bin/install-freezer.sh + - name: Install placement command: /opt/genestack/bin/install-placement.sh