├── .ci-operator.yaml ├── .dockerignore ├── .github └── workflows │ ├── build-nova-operator.yaml │ ├── build-operator-dont-publish.yaml │ ├── force-bump-pr-manual.yaml │ ├── force-bump-pr-scheduled.yaml │ ├── lints.yaml │ ├── release-branch-sync.yaml │ └── release-nova-operator.yaml ├── .gitignore ├── .gitleaks.toml ├── .golangci.yaml ├── .pre-commit-config.yaml ├── .prow_ci.env ├── .yamllint ├── .zuul.yaml ├── Dockerfile ├── LICENSE.txt ├── Makefile ├── OWNERS ├── OWNERS_ALIASES ├── PROJECT ├── README.md ├── api ├── bases │ ├── nova.openstack.org_nova.yaml │ ├── nova.openstack.org_novaapis.yaml │ ├── nova.openstack.org_novacells.yaml │ ├── nova.openstack.org_novacomputes.yaml │ ├── nova.openstack.org_novaconductors.yaml │ ├── nova.openstack.org_novametadata.yaml │ ├── nova.openstack.org_novanovncproxies.yaml │ └── nova.openstack.org_novaschedulers.yaml ├── go.mod ├── go.sum └── v1beta1 │ ├── common_types.go │ ├── common_webhook.go │ ├── conditions.go │ ├── groupversion_info.go │ ├── nova_types.go │ ├── nova_webhook.go │ ├── novaapi_types.go │ ├── novaapi_webhook.go │ ├── novacell_types.go │ ├── novacell_webhook.go │ ├── novacompute_types.go │ ├── novacompute_webhook.go │ ├── novaconductor_types.go │ ├── novaconductor_webhook.go │ ├── novametadata_types.go │ ├── novametadata_webhook.go │ ├── novanovncproxy_types.go │ ├── novanovncproxy_webhook.go │ ├── novascheduler_types.go │ ├── novascheduler_webhook.go │ └── zz_generated.deepcopy.go ├── ci ├── nova-operator-base │ └── playbooks │ │ └── collect-logs.yaml ├── nova-operator-kuttl │ └── deploy_webhooks.yaml ├── nova-operator-tempest-multinode-ceph │ ├── ci_fw_vars.yaml │ └── control_plane_hook.yaml ├── nova-operator-tempest-multinode │ ├── ci_fw_vars.yaml │ ├── control_plane_hook.yaml │ └── pre_deploy_hook.yml └── olm.sh ├── config ├── certmanager │ ├── certificate.yaml │ ├── kustomization.yaml │ └── kustomizeconfig.yaml ├── crd │ ├── bases │ │ ├── nova.openstack.org_nova.yaml │ │ ├── nova.openstack.org_novaapis.yaml │ │ ├── nova.openstack.org_novacells.yaml │ │ ├── nova.openstack.org_novacomputes.yaml │ │ ├── nova.openstack.org_novaconductors.yaml │ │ ├── nova.openstack.org_novametadata.yaml │ │ ├── nova.openstack.org_novanovncproxies.yaml │ │ └── nova.openstack.org_novaschedulers.yaml │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ └── patches │ │ ├── cainjection_in_nova.yaml │ │ ├── cainjection_in_novaapis.yaml │ │ ├── cainjection_in_novacells.yaml │ │ ├── cainjection_in_novacomputes.yaml │ │ ├── cainjection_in_novaconductors.yaml │ │ ├── cainjection_in_novametadata.yaml │ │ ├── cainjection_in_novanovncproxies.yaml │ │ ├── cainjection_in_novaschedulers.yaml │ │ ├── webhook_in_nova.yaml │ │ ├── webhook_in_novaapis.yaml │ │ ├── webhook_in_novacells.yaml │ │ ├── webhook_in_novacomputes.yaml │ │ ├── webhook_in_novaconductors.yaml │ │ ├── webhook_in_novametadata.yaml │ │ ├── webhook_in_novanovncproxies.yaml │ │ └── webhook_in_novaschedulers.yaml ├── default │ ├── kustomization.yaml │ ├── manager_auth_proxy_patch.yaml │ ├── manager_config_patch.yaml │ ├── manager_default_images.yaml │ ├── manager_webhook_patch.yaml │ └── webhookcainjection_patch.yaml ├── manager │ ├── controller_manager_config.yaml │ ├── kustomization.yaml │ └── manager.yaml ├── manifests │ ├── bases │ │ └── nova-operator.clusterserviceversion.yaml │ └── kustomization.yaml ├── prometheus │ ├── kustomization.yaml │ └── monitor.yaml ├── rbac │ ├── auth_proxy_client_clusterrole.yaml │ ├── auth_proxy_role.yaml │ ├── auth_proxy_role_binding.yaml │ ├── auth_proxy_service.yaml │ ├── kustomization.yaml │ ├── leader_election_role.yaml │ ├── leader_election_role_binding.yaml │ ├── nova_editor_role.yaml │ ├── nova_viewer_role.yaml │ ├── novaapi_editor_role.yaml │ ├── novaapi_viewer_role.yaml │ ├── novacell_editor_role.yaml │ ├── novacell_viewer_role.yaml │ ├── novacompute_editor_role.yaml │ ├── novacompute_viewer_role.yaml │ ├── novaconductor_editor_role.yaml │ ├── novaconductor_viewer_role.yaml │ ├── novametadata_editor_role.yaml │ ├── novametadata_viewer_role.yaml │ ├── novanovncproxy_editor_role.yaml │ ├── novanovncproxy_viewer_role.yaml │ ├── novascheduler_editor_role.yaml │ ├── novascheduler_viewer_role.yaml │ ├── role.yaml │ ├── role_binding.yaml │ └── service_account.yaml ├── samples │ ├── api_db.yaml │ ├── cell0_db.yaml │ ├── kustomization.yaml │ ├── nova_v1beta1_nova-compute-fake.yaml │ ├── nova_v1beta1_nova-compute-ironic.yaml │ ├── nova_v1beta1_nova-multi-cell-metadata.yaml │ ├── nova_v1beta1_nova-multi-cell-metadata_tls.yaml │ ├── nova_v1beta1_nova-multi-cell-tls.yaml │ ├── nova_v1beta1_nova-multi-cell.yaml │ ├── nova_v1beta1_nova.yaml │ ├── nova_v1beta1_nova_collapsed_cell.yaml │ ├── nova_v1beta1_novaapi.yaml │ ├── nova_v1beta1_novacell0.yaml │ ├── nova_v1beta1_novacell1-upcall.yaml │ ├── nova_v1beta1_novacell2-without-upcall.yaml │ ├── nova_v1beta1_novacompute-ironic.yaml │ ├── nova_v1beta1_novaconductor-cell.yaml │ ├── nova_v1beta1_novaconductor-super.yaml │ ├── nova_v1beta1_novametadata.yaml │ ├── nova_v1beta1_novanovncproxy.yaml │ └── nova_v1beta1_novascheduler.yaml ├── scorecard │ ├── bases │ │ └── config.yaml │ ├── kustomization.yaml │ └── patches │ │ ├── basic.config.yaml │ │ └── olm.config.yaml └── webhook │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ ├── manifests.yaml │ └── service.yaml ├── controllers ├── common.go ├── nova_controller.go ├── novaapi_controller.go ├── novacell_controller.go ├── novacompute_controller.go ├── novaconductor_controller.go ├── novametadata_controller.go ├── novanovncproxy_controller.go └── novascheduler_controller.go ├── doc ├── design.md ├── developer.md └── testing_with_nova.md ├── go.mod ├── go.sum ├── hack ├── boilerplate.go.txt ├── build-crd-schema-checker.sh ├── clean_local_webhook.sh ├── crd-schema-checker.sh ├── install-krew.sh └── run_with_local_webhook.sh ├── main.go ├── pkg ├── nova │ ├── celldelete.go │ ├── cellmapping.go │ ├── common.go │ ├── host_discover.go │ └── volumes.go ├── novaapi │ ├── const.go │ └── deployment.go ├── novacompute │ └── deployment.go ├── novaconductor │ ├── dbpurge.go │ ├── dbsync.go │ └── deployment.go ├── novametadata │ ├── const.go │ └── deployment.go ├── novascheduler │ └── deployment.go └── novncproxy │ ├── const.go │ └── deployment.go ├── renovate.json ├── templates ├── firewall.goyaml ├── neutron-metadata.conf ├── nova-blank.conf ├── nova-manage │ ├── bin │ │ ├── delete_cell.sh │ │ ├── ensure_cell_mapping.sh │ │ └── host_discover.sh │ └── config │ │ ├── cell-delete-config.json │ │ ├── cell-mapping-config.json │ │ └── host-discover-config.json ├── nova.conf ├── novaapi │ ├── bin │ │ └── .keep │ └── config │ │ ├── httpd.conf │ │ ├── nova-api-config.json │ │ └── ssl.conf ├── novacompute │ ├── bin │ │ └── .keep │ └── config │ │ └── nova-compute-config.json ├── novaconductor │ ├── bin │ │ ├── dbpurge.sh │ │ └── dbsync.sh │ └── config │ │ ├── nova-conductor-config.json │ │ ├── nova-conductor-dbpurge-config.json │ │ └── nova-conductor-dbsync-config.json ├── novametadata │ ├── bin │ │ └── .keep │ └── config │ │ ├── httpd.conf │ │ ├── nova-metadata-config.json │ │ └── ssl.conf ├── novanovncproxy │ ├── bin │ │ └── .keep │ └── config │ │ └── nova-novncproxy-config.json └── novascheduler │ ├── bin │ └── .keep │ └── config │ └── nova-scheduler-config.json └── test ├── functional ├── api_fixture.go ├── base_test.go ├── nova_compute_ironic_controller_test.go ├── nova_controller_test.go ├── nova_metadata_controller_test.go ├── nova_multicell_test.go ├── nova_novncproxy_test.go ├── nova_reconfiguration_test.go ├── nova_scheduler_test.go ├── novaapi_controller_test.go ├── novacell_controller_test.go ├── novaconductor_controller_test.go ├── sample_test.go ├── suite_test.go └── validation_webhook_test.go └── kuttl └── test-suites └── default ├── cell-tests ├── 00-cleanup-nova.yaml ├── 01-assert.yaml ├── 01-deploy.yaml ├── 02-assert.yaml ├── 02-delete-cell-nova.yaml └── 03-cleanup-nova.yaml ├── common └── cleanup-nova.yaml ├── config-tests ├── 00-cleanup-nova.yaml ├── 01-assert.yaml ├── 01-deploy-with-default-config-overwrite.yaml └── 02-cleanup-nova.yaml ├── config.yaml ├── deps ├── OpenStackControlPlane.yaml ├── infra.yaml ├── keystone.yaml ├── kustomization.yaml ├── namespace.yaml ├── nova.yaml └── placement.yaml ├── output └── .keep └── scale-tests ├── 00-cleanup-nova.yaml ├── 01-assert.yaml ├── 01-deploy.yaml ├── 02-assert.yaml ├── 02-scale-up-nova.yaml ├── 03-assert.yaml ├── 03-scale-down-nova.yaml ├── 04-assert.yaml ├── 04-scale-down-zero-nova.yaml └── 05-cleanup-nova.yaml /.ci-operator.yaml: -------------------------------------------------------------------------------- 1 | build_root_image: 2 | name: tools 3 | namespace: openstack-k8s-operators 4 | tag: ci-build-root-golang-1.21-sdk-1.31 5 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file 2 | # Ignore build and test binaries. 3 | bin/ 4 | testbin/ 5 | -------------------------------------------------------------------------------- /.github/workflows/build-nova-operator.yaml: -------------------------------------------------------------------------------- 1 | name: nova operator image builder 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | 8 | env: 9 | imageregistry: 'quay.io' 10 | imagenamespace: ${{ secrets.IMAGENAMESPACE || secrets.QUAY_USERNAME }} 11 | latesttag: latest 12 | 13 | jobs: 14 | call-build-workflow: 15 | uses: openstack-k8s-operators/openstack-k8s-operators-ci/.github/workflows/reusable-build-operator.yaml@main 16 | with: 17 | operator_name: nova 18 | go_version: 1.21.x 19 | operator_sdk_version: 1.31.0 20 | secrets: 21 | IMAGENAMESPACE: ${{ secrets.IMAGENAMESPACE }} 22 | QUAY_USERNAME: ${{ secrets.QUAY_USERNAME }} 23 | QUAY_PASSWORD: ${{ secrets.QUAY_PASSWORD }} 24 | REDHATIO_USERNAME: ${{ secrets.REDHATIO_USERNAME }} 25 | REDHATIO_PASSWORD: ${{ secrets.REDHATIO_PASSWORD }} 26 | -------------------------------------------------------------------------------- /.github/workflows/build-operator-dont-publish.yaml: -------------------------------------------------------------------------------- 1 | name: Build operator without publishing it 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - '*' 7 | 8 | jobs: 9 | build-nova-operator-with-bunlde-and-index: 10 | name: Build 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Install Go 15 | uses: actions/setup-go@v2 16 | with: 17 | go-version: 1.21.x 18 | 19 | - name: Checkout nova-operator repository 20 | uses: actions/checkout@v3 21 | 22 | - name: Build 23 | env: 24 | # By not providing any remote repository here the build artifact will not be pushed 25 | IMAGE_TAG_BASE: nova-operator 26 | # To avoid getting rate limited during kustomize install 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | 29 | # Ideally we would add catalog-build target at the end but that requires 30 | # the bundle to be pushed to a registry due to opm limitations: 31 | # https://github.com/operator-framework/operator-registry/issues/933 32 | # Having a local registry for the catalog-build is would require a 33 | # registry with TLS support or we would need to modify the catalog-build 34 | # target to add flags to the opm call. None of which worth the effort 35 | # since right now I don't how a change of this repo could break that 36 | # step. 37 | run: make manifests generate build docker-build bundle bundle-build 38 | -------------------------------------------------------------------------------- /.github/workflows/force-bump-pr-manual.yaml: -------------------------------------------------------------------------------- 1 | name: Manually Trigger a Force Bump PR 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | call-build-workflow: 8 | uses: openstack-k8s-operators/openstack-k8s-operators-ci/.github/workflows/force-bump-pull-request.yaml@main 9 | with: 10 | operator_name: nova 11 | branch_name: ${{ github.ref_name }} 12 | secrets: 13 | FORCE_BUMP_PULL_REQUEST_PAT: ${{ secrets.FORCE_BUMP_PULL_REQUEST_PAT }} 14 | -------------------------------------------------------------------------------- /.github/workflows/force-bump-pr-scheduled.yaml: -------------------------------------------------------------------------------- 1 | name: Scheduled Force Bump PR 2 | 3 | on: 4 | schedule: 5 | - cron: '0 5 * * 6' # 5AM UTC Saturday 6 | 7 | jobs: 8 | call-build-workflow: 9 | if: github.ref == 'refs/heads/main' && github.repository_owner == 'openstack-k8s-operators' 10 | uses: openstack-k8s-operators/openstack-k8s-operators-ci/.github/workflows/force-bump-branches.yaml@main 11 | with: 12 | operator_name: nova 13 | secrets: 14 | FORCE_BUMP_PULL_REQUEST_PAT: ${{ secrets.FORCE_BUMP_PULL_REQUEST_PAT }} 15 | -------------------------------------------------------------------------------- /.github/workflows/lints.yaml: -------------------------------------------------------------------------------- 1 | name: Lints 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | check-go-mod-replace-lines: 7 | name: check for replace lines in go.mod files 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout project code 11 | uses: actions/checkout@v2 12 | - name: check for replace lines in go.mod files 13 | run: | 14 | ! egrep --invert-match -e '^replace.*/api => \./api|^replace.*//allow-merging$' `find . -name 'go.mod'` | egrep -e 'go.mod:replace' 15 | -------------------------------------------------------------------------------- /.github/workflows/release-branch-sync.yaml: -------------------------------------------------------------------------------- 1 | name: Release Branch sync 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | schedule: 8 | - cron: '0 * * * *' 9 | 10 | jobs: 11 | call-build-workflow: 12 | uses: openstack-k8s-operators/openstack-k8s-operators-ci/.github/workflows/release-branch-sync.yaml@main 13 | -------------------------------------------------------------------------------- /.github/workflows/release-nova-operator.yaml: -------------------------------------------------------------------------------- 1 | name: Release Nova Operator 2 | 3 | on: 4 | release: 5 | types: 6 | - released 7 | - prereleased 8 | 9 | env: 10 | imageregistry: 'quay.io' 11 | imagenamespace: ${{ secrets.IMAGENAMESPACE || secrets.QUAY_USERNAME }} 12 | 13 | jobs: 14 | release: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | 20 | - name: Tag image 21 | uses: tinact/docker.image-retag@1.0.2 22 | with: 23 | image_name: ${{ env.imagenamespace }}/ 24 | image_old_tag: ${{ github.sha }} 25 | image_new_tag: ${{ github.event.release.tag_name }} 26 | registry: ${{ env.imageregistry }} 27 | registry_username: ${{ secrets.QUAY_USERNAME }} 28 | registry_password: ${{ secrets.QUAY_PASSWORD }} 29 | 30 | - name: Tag -bundle image 31 | uses: tinact/docker.image-retag@1.0.2 32 | with: 33 | image_name: ${{ env.imagenamespace }}/-bundle 34 | image_old_tag: ${{ github.sha }} 35 | image_new_tag: ${{ github.event.release.tag_name }} 36 | registry: ${{ env.imageregistry }} 37 | registry_username: ${{ secrets.QUAY_USERNAME }} 38 | registry_password: ${{ secrets.QUAY_PASSWORD }} 39 | 40 | - name: Tag -index image 41 | uses: tinact/docker.image-retag@1.0.2 42 | with: 43 | image_name: ${{ env.imagenamespace }}/-index 44 | image_old_tag: ${{ github.sha }} 45 | image_new_tag: ${{ github.event.release.tag_name }} 46 | registry: ${{ env.imageregistry }} 47 | registry_username: ${{ secrets.QUAY_USERNAME }} 48 | registry_password: ${{ secrets.QUAY_PASSWORD }} 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Temporary Build Files 2 | build/_output 3 | build/_test 4 | # Created by https://www.gitignore.io/api/go,vim,emacs,visualstudiocode 5 | ### Emacs ### 6 | # -*- mode: gitignore; -*- 7 | *~ 8 | \#*\# 9 | /.emacs.desktop 10 | /.emacs.desktop.lock 11 | *.elc 12 | auto-save-list 13 | tramp 14 | .\#* 15 | # Org-mode 16 | .org-id-locations 17 | *_archive 18 | # flymake-mode 19 | *_flymake.* 20 | # eshell files 21 | /eshell/history 22 | /eshell/lastdir 23 | # elpa packages 24 | /elpa/ 25 | # reftex files 26 | *.rel 27 | # AUCTeX auto folder 28 | /auto/ 29 | # cask packages 30 | .cask/ 31 | dist/ 32 | # Flycheck 33 | flycheck_*.el 34 | # server auth directory 35 | /server/ 36 | # projectiles files 37 | .projectile 38 | projectile-bookmarks.eld 39 | # directory configuration 40 | .dir-locals.el 41 | # saveplace 42 | places 43 | # url cache 44 | url/cache/ 45 | # cedet 46 | ede-projects.el 47 | # smex 48 | smex-items 49 | # company-statistics 50 | company-statistics-cache.el 51 | # anaconda-mode 52 | anaconda-mode/ 53 | ### Go ### 54 | # Binaries for programs and plugins 55 | *.exe 56 | *.exe~ 57 | *.dll 58 | *.so 59 | *.dylib 60 | # Test binary, build with 'go test -c' 61 | *.test 62 | # Output of the go coverage tool, specifically when used with LiteIDE 63 | *.out 64 | ### Vim ### 65 | # swap 66 | .sw[a-p] 67 | .*.sw[a-p] 68 | # session 69 | Session.vim 70 | # temporary 71 | .netrwhist 72 | # auto-generated tag files 73 | tags 74 | ### VisualStudioCode ### 75 | .vscode/* 76 | .history 77 | # End of https://www.gitignore.io/api/go,vim,emacs,visualstudiocode 78 | # vscode debug binary 79 | __debug_bin 80 | 81 | #Operator SDK generated files 82 | /bundle/ 83 | bundle.Dockerfile 84 | config/manager/kustomization.yaml 85 | 86 | # Common CI tools repository 87 | CI_TOOLS_REPO 88 | 89 | # utility binaries 90 | /bin 91 | 92 | # python venvs 93 | .venv 94 | 95 | # openstack client config 96 | clouds.yaml 97 | 98 | # go.work is not supported by our build tooling (cachito) 99 | # https://github.com/containerbuildsystem/cachito/commit/c7fbbb13eeb7d7edec3c01643eb5b24381027365 100 | go.work 101 | go.work.sum 102 | 103 | # kuttl testing 104 | test/kuttl/test-suites/**/output/* 105 | kubeconfig 106 | -------------------------------------------------------------------------------- /.gitleaks.toml: -------------------------------------------------------------------------------- 1 | [allowlist] 2 | description = "ignore test dirs" 3 | 4 | # Ignore based on any subset of the file path 5 | paths = [ 6 | '''\/test''', 7 | ] 8 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | linters: 2 | # Enable specific linter 3 | # https://golangci-lint.run/usage/linters/#enabled-by-default 4 | enable: 5 | - errorlint 6 | - revive 7 | - ginkgolinter 8 | - gofmt 9 | - govet 10 | - gosec 11 | - errname 12 | - err113 13 | run: 14 | timeout: 5m 15 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: local 3 | hooks: 4 | - id: gotidy 5 | name: gotidy 6 | language: system 7 | entry: make 8 | args: ["tidy"] 9 | pass_filenames: false 10 | - id: make-manifests 11 | name: make-manifests 12 | language: system 13 | entry: make 14 | args: ['manifests'] 15 | pass_filenames: false 16 | - id: make-generate 17 | name: make-generate 18 | language: system 19 | entry: make 20 | args: ['generate'] 21 | pass_filenames: false 22 | - id: make-operator-lint 23 | name: make-operator-lint 24 | language: system 25 | entry: make 26 | args: ['operator-lint'] 27 | pass_filenames: false 28 | - id: make-bundle 29 | name: make-bundle 30 | language: system 31 | entry: make 32 | args: ['bundle', 'VERSION=0.0.1'] 33 | pass_filenames: false 34 | - id: make-crd-schema-check 35 | name: make-crd-schema-check 36 | language: system 37 | entry: make 38 | args: ['crd-schema-check'] 39 | pass_filenames: false 40 | 41 | - repo: https://github.com/pre-commit/pre-commit-hooks 42 | rev: v4.4.0 43 | hooks: 44 | - id: check-added-large-files 45 | - id: fix-byte-order-marker 46 | - id: check-case-conflict 47 | - id: check-executables-have-shebangs 48 | exclude: ^vendor 49 | - id: check-shebang-scripts-are-executable 50 | exclude: ^vendor 51 | - id: check-merge-conflict 52 | - id: check-symlinks 53 | - id: destroyed-symlinks 54 | - id: check-yaml 55 | args: [-m] 56 | - id: check-json 57 | - id: detect-private-key 58 | - id: end-of-file-fixer 59 | exclude: ^vendor 60 | - id: no-commit-to-branch 61 | - id: trailing-whitespace 62 | exclude: ^vendor 63 | 64 | - repo: https://github.com/openstack/bashate.git 65 | rev: 2.1.1 66 | hooks: 67 | - id: bashate 68 | entry: bashate --error . --ignore=E006,E040,E020,E012 69 | # Run bashate check for all bash scripts 70 | # Ignores the following rules: 71 | # E006: Line longer than 79 columns (as many scripts use jinja 72 | # templating, this is very difficult) 73 | # E040: Syntax error determined using `bash -n` (as many scripts 74 | # use jinja templating, this will often fail and the syntax 75 | # error will be discovered in execution anyway) 76 | # E020: Function declaration not in format ^function name {$ 77 | # E012: here doc didn't end before EOF 78 | 79 | - repo: https://github.com/golangci/golangci-lint 80 | rev: v1.59.1 81 | hooks: 82 | - id: golangci-lint-full 83 | args: ["-v"] 84 | 85 | - repo: https://github.com/openstack-k8s-operators/openstack-k8s-operators-ci 86 | # NOTE(gibi): we cannot automatically track main here 87 | # see https://pre-commit.com/#using-the-latest-version-for-a-repository 88 | rev: e30d72fcbced0ab8a7b6d23be1dee129e2a7b849 89 | hooks: 90 | - id: kuttl-single-test-assert 91 | -------------------------------------------------------------------------------- /.prow_ci.env: -------------------------------------------------------------------------------- 1 | export USE_IMAGE_DIGESTS=true 2 | export FAIL_FIPS_CHECK=true 3 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | # Based on ansible-lint config 3 | extends: default 4 | 5 | rules: 6 | braces: 7 | max-spaces-inside: 1 8 | level: error 9 | brackets: 10 | max-spaces-inside: 1 11 | level: error 12 | colons: 13 | max-spaces-after: -1 14 | level: error 15 | commas: 16 | max-spaces-after: -1 17 | level: error 18 | comments: disable 19 | comments-indentation: disable 20 | document-start: disable 21 | empty-lines: 22 | max: 3 23 | level: error 24 | hyphens: 25 | level: error 26 | indentation: disable 27 | key-duplicates: enable 28 | line-length: disable 29 | new-line-at-end-of-file: disable 30 | new-lines: 31 | type: unix 32 | trailing-spaces: disable 33 | truthy: disable 34 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG GOLANG_BUILDER=registry.access.redhat.com/ubi9/go-toolset:1.21 2 | ARG OPERATOR_BASE_IMAGE=registry.access.redhat.com/ubi9/ubi-minimal:latest 3 | 4 | # Build the manager binary 5 | FROM $GOLANG_BUILDER AS builder 6 | 7 | #Arguments required by OSBS build system 8 | ARG CACHITO_ENV_FILE=/remote-source/cachito.env 9 | ARG REMOTE_SOURCE=. 10 | ARG REMOTE_SOURCE_DIR=/remote-source 11 | ARG REMOTE_SOURCE_SUBDIR= 12 | ARG DEST_ROOT=/dest-root 13 | ARG GO_BUILD_EXTRA_ARGS="-tags strictfipsruntime" 14 | ARG GO_BUILD_EXTRA_ENV_ARGS="CGO_ENABLED=1 GO111MODULE=on" 15 | 16 | COPY $REMOTE_SOURCE $REMOTE_SOURCE_DIR 17 | WORKDIR $REMOTE_SOURCE_DIR/$REMOTE_SOURCE_SUBDIR 18 | USER root 19 | RUN mkdir -p ${DEST_ROOT}/usr/local/bin/ 20 | 21 | # cache deps before building and copying source so that we don't need to re-download as much 22 | # and so that source changes don't invalidate our downloaded layer 23 | RUN if [ ! -f $CACHITO_ENV_FILE ]; then go mod download ; fi 24 | 25 | # Build manager 26 | RUN if [ -f $CACHITO_ENV_FILE ] ; then source $CACHITO_ENV_FILE ; fi ; env ${GO_BUILD_EXTRA_ENV_ARGS} go build ${GO_BUILD_EXTRA_ARGS} -a -o ${DEST_ROOT}/manager main.go 27 | 28 | 29 | RUN cp -r templates ${DEST_ROOT}/templates 30 | 31 | # Use distroless as minimal base image to package the manager binary 32 | # Refer to https://github.com/GoogleContainerTools/distroless for more details 33 | FROM $OPERATOR_BASE_IMAGE 34 | 35 | ARG DEST_ROOT=/dest-root 36 | # NONROOT default id https://github.com/GoogleContainerTools/distroless/blob/main/base/base.bzl#L8= 37 | ARG USER_ID=65532 38 | 39 | ARG IMAGE_COMPONENT="nova-operator-container" 40 | ARG IMAGE_NAME="nova-operator" 41 | ARG IMAGE_VERSION="1.0.0" 42 | ARG IMAGE_SUMMARY="Nova Operator" 43 | ARG IMAGE_DESC="This image includes the nova-operator" 44 | ARG IMAGE_TAGS="cn-openstack openstack" 45 | 46 | ### DO NOT EDIT LINES BELOW 47 | # Auto generated using CI tools from 48 | # https://github.com/openstack-k8s-operators/openstack-k8s-operators-ci 49 | 50 | # Labels required by upstream and osbs build system 51 | LABEL com.redhat.component="${IMAGE_COMPONENT}" \ 52 | name="${IMAGE_NAME}" \ 53 | version="${IMAGE_VERSION}" \ 54 | summary="${IMAGE_SUMMARY}" \ 55 | io.k8s.name="${IMAGE_NAME}" \ 56 | io.k8s.description="${IMAGE_DESC}" \ 57 | io.openshift.tags="${IMAGE_TAGS}" 58 | ### DO NOT EDIT LINES ABOVE 59 | 60 | ENV USER_UID=$USER_ID \ 61 | OPERATOR_TEMPLATES=/usr/share/nova-operator/templates/ 62 | 63 | WORKDIR / 64 | 65 | # Install operator binary to WORKDIR 66 | COPY --from=builder ${DEST_ROOT}/manager . 67 | 68 | # Install templates 69 | COPY --from=builder ${DEST_ROOT}/templates ${OPERATOR_TEMPLATES} 70 | 71 | USER $USER_ID 72 | 73 | ENV PATH="/:${PATH}" 74 | 75 | ENTRYPOINT ["/manager"] 76 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | approvers: 3 | - ci-approvers 4 | - openstack-approvers 5 | - compute-approvers 6 | 7 | reviewers: 8 | - ci-approvers 9 | - openstack-approvers 10 | - compute-approvers 11 | -------------------------------------------------------------------------------- /OWNERS_ALIASES: -------------------------------------------------------------------------------- 1 | # See the OWNERS_ALIASES docs: https://git.k8s.io/community/contributors/guide/owners.md#owners_aliases 2 | 3 | aliases: 4 | ci-approvers: 5 | - lewisdenny 6 | - frenzyfriday 7 | - viroel 8 | openstack-approvers: 9 | - abays 10 | - dprince 11 | - olliewalsh 12 | - stuggi 13 | compute-approvers: 14 | - gibizer 15 | - SeanMooney 16 | - bogdando 17 | - kk7ds 18 | - mrKisaoLamb 19 | - jamepark4 20 | - auniyal61 21 | - ratailor 22 | -------------------------------------------------------------------------------- /PROJECT: -------------------------------------------------------------------------------- 1 | domain: openstack.org 2 | layout: 3 | - go.kubebuilder.io/v3 4 | plugins: 5 | manifests.sdk.operatorframework.io/v2: {} 6 | scorecard.sdk.operatorframework.io/v2: {} 7 | projectName: nova-operator 8 | repo: github.com/openstack-k8s-operators/nova-operator 9 | resources: 10 | - api: 11 | crdVersion: v1 12 | namespaced: true 13 | controller: true 14 | domain: openstack.org 15 | group: nova 16 | kind: NovaAPI 17 | path: github.com/openstack-k8s-operators/nova-operator/api/v1beta1 18 | version: v1beta1 19 | webhooks: 20 | defaulting: true 21 | validation: true 22 | webhookVersion: v1 23 | - api: 24 | crdVersion: v1 25 | namespaced: true 26 | controller: true 27 | domain: openstack.org 28 | group: nova 29 | kind: NovaScheduler 30 | path: github.com/openstack-k8s-operators/nova-operator/api/v1beta1 31 | version: v1beta1 32 | webhooks: 33 | defaulting: true 34 | validation: true 35 | webhookVersion: v1 36 | - api: 37 | crdVersion: v1 38 | namespaced: true 39 | controller: true 40 | domain: openstack.org 41 | group: nova 42 | kind: NovaConductor 43 | path: github.com/openstack-k8s-operators/nova-operator/api/v1beta1 44 | version: v1beta1 45 | webhooks: 46 | defaulting: true 47 | validation: true 48 | webhookVersion: v1 49 | - api: 50 | crdVersion: v1 51 | namespaced: true 52 | controller: true 53 | domain: openstack.org 54 | group: nova 55 | kind: NovaMetadata 56 | path: github.com/openstack-k8s-operators/nova-operator/api/v1beta1 57 | version: v1beta1 58 | webhooks: 59 | defaulting: true 60 | validation: true 61 | webhookVersion: v1 62 | - api: 63 | crdVersion: v1 64 | namespaced: true 65 | controller: true 66 | domain: openstack.org 67 | group: nova 68 | kind: NovaNoVNCProxy 69 | path: github.com/openstack-k8s-operators/nova-operator/api/v1beta1 70 | version: v1beta1 71 | webhooks: 72 | defaulting: true 73 | validation: true 74 | webhookVersion: v1 75 | - api: 76 | crdVersion: v1 77 | namespaced: true 78 | controller: true 79 | domain: openstack.org 80 | group: nova 81 | kind: NovaCell 82 | path: github.com/openstack-k8s-operators/nova-operator/api/v1beta1 83 | version: v1beta1 84 | webhooks: 85 | defaulting: true 86 | validation: true 87 | webhookVersion: v1 88 | - api: 89 | crdVersion: v1 90 | namespaced: true 91 | controller: true 92 | domain: openstack.org 93 | group: nova 94 | kind: Nova 95 | path: github.com/openstack-k8s-operators/nova-operator/api/v1beta1 96 | version: v1beta1 97 | webhooks: 98 | defaulting: true 99 | validation: true 100 | webhookVersion: v1 101 | - api: 102 | crdVersion: v1 103 | namespaced: true 104 | controller: true 105 | domain: openstack.org 106 | group: nova 107 | kind: NovaCompute 108 | path: github.com/openstack-k8s-operators/nova-operator/api/v1beta1 109 | version: v1beta1 110 | webhooks: 111 | defaulting: true 112 | validation: true 113 | webhookVersion: v1 114 | version: "3" 115 | -------------------------------------------------------------------------------- /api/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/openstack-k8s-operators/nova-operator/api 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/google/go-cmp v0.7.0 7 | github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250430070919-2ce4eea3a06d 8 | github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250505061650-7cb2f323fb35 9 | github.com/robfig/cron/v3 v3.0.1 10 | k8s.io/api v0.29.15 11 | k8s.io/apimachinery v0.29.15 12 | k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 13 | sigs.k8s.io/controller-runtime v0.17.6 14 | ) 15 | 16 | require ( 17 | github.com/beorn7/perks v1.0.1 // indirect 18 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 19 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 20 | github.com/emicklei/go-restful/v3 v3.12.0 // indirect 21 | github.com/evanphx/json-patch/v5 v5.9.0 // indirect 22 | github.com/fsnotify/fsnotify v1.7.0 // indirect 23 | github.com/go-logr/logr v1.4.2 // indirect 24 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 25 | github.com/go-openapi/jsonreference v0.21.0 // indirect 26 | github.com/go-openapi/swag v0.23.0 // indirect 27 | github.com/gogo/protobuf v1.3.2 // indirect 28 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 29 | github.com/golang/protobuf v1.5.4 // indirect 30 | github.com/google/gnostic-models v0.6.8 // indirect 31 | github.com/google/gofuzz v1.2.0 // indirect 32 | github.com/google/uuid v1.6.0 // indirect 33 | github.com/imdario/mergo v0.3.16 // indirect 34 | github.com/josharian/intern v1.0.0 // indirect 35 | github.com/json-iterator/go v1.1.12 // indirect 36 | github.com/mailru/easyjson v0.7.7 // indirect 37 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 38 | github.com/modern-go/reflect2 v1.0.2 // indirect 39 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 40 | github.com/pkg/errors v0.9.1 // indirect 41 | github.com/prometheus/client_golang v1.19.0 // indirect 42 | github.com/prometheus/client_model v0.6.0 // indirect 43 | github.com/prometheus/common v0.51.1 // indirect 44 | github.com/prometheus/procfs v0.13.0 // indirect 45 | github.com/spf13/pflag v1.0.5 // indirect 46 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect 47 | golang.org/x/net v0.28.0 // indirect 48 | golang.org/x/oauth2 v0.18.0 // indirect 49 | golang.org/x/sys v0.23.0 // indirect 50 | golang.org/x/term v0.23.0 // indirect 51 | golang.org/x/text v0.17.0 // indirect 52 | golang.org/x/time v0.5.0 // indirect 53 | gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect 54 | google.golang.org/appengine v1.6.8 // indirect 55 | google.golang.org/protobuf v1.34.1 // indirect 56 | gopkg.in/inf.v0 v0.9.1 // indirect 57 | gopkg.in/yaml.v2 v2.4.0 // indirect 58 | gopkg.in/yaml.v3 v3.0.1 // indirect 59 | k8s.io/apiextensions-apiserver v0.29.15 // indirect 60 | k8s.io/client-go v0.29.15 // indirect 61 | k8s.io/component-base v0.29.15 // indirect 62 | k8s.io/klog/v2 v2.120.1 // indirect 63 | k8s.io/kube-openapi v0.0.0-20240322212309-b815d8309940 // indirect 64 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect 65 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect 66 | sigs.k8s.io/yaml v1.4.0 // indirect 67 | ) 68 | 69 | // mschuppert: map to latest commit from release-4.16 tag 70 | // must consistent within modules and service operators 71 | replace github.com/openshift/api => github.com/openshift/api v0.0.0-20240830023148-b7d0481c9094 //allow-merging 72 | 73 | // custom RabbitmqClusterSpecCore for OpenStackControlplane (v2.6.0_patches_tag) 74 | replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20241017142550-a3524acedd49 //allow-merging 75 | -------------------------------------------------------------------------------- /api/v1beta1/common_webhook.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1beta1 18 | 19 | import ( 20 | "fmt" 21 | "path/filepath" 22 | "strings" 23 | 24 | "k8s.io/apimachinery/pkg/util/validation/field" 25 | ) 26 | 27 | // ValidateDefaultConfigOverwrite checks if the file names in the overwrite map 28 | // are allowed and return an error for each unsupported files. The allowedKeys 29 | // list supports direct string match and globs like provider*.yaml 30 | func ValidateDefaultConfigOverwrite( 31 | basePath *field.Path, 32 | defaultConfigOverwrite map[string]string, 33 | allowedKeys []string, 34 | ) field.ErrorList { 35 | var errors field.ErrorList 36 | for requested := range defaultConfigOverwrite { 37 | if !matchAny(requested, allowedKeys) { 38 | errors = append( 39 | errors, 40 | field.Invalid( 41 | basePath, 42 | requested, 43 | fmt.Sprintf( 44 | "Only the following keys are valid: %s", 45 | strings.Join(allowedKeys, ", ")), 46 | ), 47 | ) 48 | } 49 | } 50 | return errors 51 | } 52 | 53 | func matchAny(requested string, allowed []string) bool { 54 | for _, a := range allowed { 55 | if matched, _ := filepath.Match(a, requested); matched { 56 | return true 57 | } 58 | } 59 | return false 60 | } 61 | -------------------------------------------------------------------------------- /api/v1beta1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package v1beta1 contains API Schema definitions for the nova v1beta1 API group 18 | // +kubebuilder:object:generate=true 19 | // +groupName=nova.openstack.org 20 | package v1beta1 21 | 22 | import ( 23 | "k8s.io/apimachinery/pkg/runtime/schema" 24 | "sigs.k8s.io/controller-runtime/pkg/scheme" 25 | ) 26 | 27 | var ( 28 | // GroupVersion is group version used to register these objects 29 | GroupVersion = schema.GroupVersion{Group: "nova.openstack.org", Version: "v1beta1"} 30 | 31 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 32 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 33 | 34 | // AddToScheme adds the types in this group-version to the given scheme. 35 | AddToScheme = SchemeBuilder.AddToScheme 36 | ) 37 | -------------------------------------------------------------------------------- /ci/nova-operator-base/playbooks/collect-logs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: controller 3 | name: Collect logs on the controller 4 | gather_facts: false 5 | vars: 6 | collection_namespace: "{{ collection_namespace_override | default('openstack') }}" 7 | tasks: 8 | - name: Create log dir 9 | ansible.builtin.file: 10 | path: "{{ ansible_user_dir }}/zuul-output/logs/controller" 11 | state: directory 12 | mode: "0755" 13 | - name: Collect general openshift cr info 14 | environment: 15 | KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" 16 | PATH: "{{ cifmw_path | default(ansible_env.PATH) }}" 17 | ansible.builtin.shell: | 18 | source ~/.bashrc 19 | collection_namespace_dir="{{ ansible_user_dir }}/zuul-output/logs/controller/{{collection_namespace}}" 20 | mkdir ${collection_namespace_dir} 21 | pushd ${collection_namespace_dir} 22 | oc get -n {{collection_namespace}} secrets > all_secrets.txt 23 | oc get -n {{collection_namespace}} pv > all_pv.txt 24 | oc get -n {{collection_namespace}} events > oc_events.txt 25 | oc get -n {{collection_namespace}} routes > oc_routes.txt 26 | oc get -n {{collection_namespace}} all > oc_all.txt 27 | popd 28 | pod_dir="${collection_namespace_dir}/pods" 29 | mkdir ${pod_dir} 30 | pushd ${pod_dir} 31 | all_pods=$(oc get -n {{collection_namespace}} pods | awk '{print $1}' | awk -F '.' '{print $1}') 32 | for pod in $all_pods; do 33 | echo $pod 34 | oc logs -n {{collection_namespace}} pod/${pod} > ${pod}-logs.txt 35 | oc get -n {{collection_namespace}} -o yaml pod/${pod} > ${pod}.yaml 36 | oc describe -n {{collection_namespace}} pod/${pod} > ${pod}-describe.txt 37 | done 38 | popd 39 | crd_logs="${collection_namespace_dir}/crd" 40 | mkdir ${crd_logs} 41 | pushd ${crd_logs} 42 | all_crds=$(oc get crd | grep openstack | awk '{print $1}' | awk -F '.' '{print $1}') 43 | for cr in $all_crds; do 44 | echo $crd 45 | oc get -n {{collection_namespace}} -o yaml $cr > ${cr}.yaml 46 | oc describe -n {{collection_namespace}} $cr > ${cr}-describe.txt 47 | done 48 | popd 49 | openstack_operator_namespace_dir="{{ ansible_user_dir }}/zuul-output/logs/controller/openstack-operators" 50 | mkdir ${openstack_operator_namespace_dir} 51 | csv_logs="${openstack_operator_namespace_dir}/csv" 52 | mkdir ${csv_logs} 53 | pushd ${csv_logs} 54 | all_csv=$(oc get -n openstack-operators csv | awk '{print $1}') 55 | for csv in $all_csv; do 56 | echo $crd 57 | oc get -n openstack-operators -o yaml csv/${csv} > ${csv}.yaml 58 | oc describe -n openstack-operators csv/${csv} > ${csv}-describe.txt 59 | done 60 | popd 61 | pod_dir="${openstack_operator_namespace_dir}/pods" 62 | mkdir ${pod_dir} 63 | pushd ${pod_dir} 64 | all_pods=$(oc get -n openstack-operators pods | awk '{print $1}' | awk -F '.' '{print $1}') 65 | for pod in $all_pods; do 66 | echo $pod 67 | oc logs -n openstack-operators pod/${pod} > ${pod}-logs.txt 68 | oc get -n openstack-operators -o yaml pod/${pod} > ${pod}.yaml 69 | oc describe -n openstack-operators pod/${pod} > ${pod}-describe.txt 70 | done 71 | popd 72 | args: 73 | chdir: "{{ ansible_user_dir }}/zuul-output/logs/controller" 74 | changed_when: true 75 | ignore_errors: true 76 | tags: 77 | - skip_ansible_lint 78 | -------------------------------------------------------------------------------- /ci/nova-operator-kuttl/deploy_webhooks.yaml: -------------------------------------------------------------------------------- 1 | - name: Create custom service 2 | hosts: "{{ cifmw_target_hook_host | default('localhost') }}" 3 | environment: 4 | KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" 5 | PATH: "{{ cifmw_path }}" 6 | gather_facts: false 7 | tasks: 8 | - name: Get the CSV name for openstack-operator 9 | ansible.builtin.shell: | 10 | oc get csv -n openstack-operators -o jsonpath="{.items[?(@.spec.displayName=='OpenStack')].metadata.name}" 11 | register: csv_name 12 | - name: Scale down deployment 13 | ansible.builtin.shell: | 14 | oc patch csv -n openstack-operators {{ csv_name.stdout }} --type json -p="[{"op": "replace", "path": "/spec/install/spec/deployments/0/spec/replicas", "value": "0"}]" 15 | - name: Install Nova Operator 16 | cifmw.general.ci_script: 17 | output_dir: "{{ cifmw_basedir }}/artifacts" 18 | chdir: "{{ ansible_user_dir }}/src/github.com/openstack-k8s-operators/nova-operator" 19 | script: make run_with_olm 20 | extra_args: 21 | CATALOG_IMAGE: "{{ nova_catalog_image }}" 22 | -------------------------------------------------------------------------------- /ci/nova-operator-tempest-multinode-ceph/ci_fw_vars.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | cifmw_install_yamls_vars: 3 | BMO_SETUP: false 4 | INSTALL_CERT_MANAGER: false 5 | 6 | cifmw_edpm_prepare_skip_crc_storage_creation: true 7 | # as we scale the openstack services to 3 replicas we need more PVs 8 | cifmw_cls_pv_count: 20 9 | 10 | cifmw_services_swift_enabled: false 11 | pre_deploy: 12 | - name: 61 HCI pre deploy kustomizations 13 | type: playbook 14 | source: control_plane_hci_pre_deploy.yml 15 | 16 | # note by defualt the source for the playbook specified 17 | # in the hooks is relative to 18 | # https://github.com/openstack-k8s-operators/ci-framework/tree/main/hooks/playbooks 19 | # if you want to use a different source you can use the full path on the ansible controller 20 | post_deploy: 21 | - name: 71 Kustomize control plane to scale openstack services 22 | type: playbook 23 | source: "{{ ansible_user_dir }}/{{ zuul.projects['github.com/openstack-k8s-operators/nova-operator'].src_dir }}/ci/nova-operator-tempest-multinode-ceph/control_plane_hook.yaml" 24 | - name: 81 Kustomize OpenStack CR with Ceph 25 | type: playbook 26 | source: control_plane_ceph_backends.yml 27 | - name: 82 Kustomize and update Control Plane 28 | type: playbook 29 | source: control_plane_kustomize_deploy.yml 30 | 31 | # we can use this hook to create flavors, images, etc 32 | # before we execute tempest simiilar to how we would use 33 | # local.sh in devstack based jobs 34 | pre_tests: 35 | - name: 01 Create cinder multiattach volume type 36 | type: playbook 37 | source: cinder_multiattach_volume_type.yml 38 | 39 | 40 | cifmw_run_tests: true 41 | cifmw_tempest_container: openstack-tempest-extras 42 | # we do not want the ci framwork trying to enbable any 43 | # tempest groups by default we will manage all tempest execution 44 | # via the job definition. 45 | cifmw_tempest_default_groups: [] 46 | -------------------------------------------------------------------------------- /ci/nova-operator-tempest-multinode-ceph/control_plane_hook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Kustomize ControlPlane 3 | hosts: "{{ cifmw_target_hook_host | default('localhost') }}" 4 | gather_facts: false 5 | tasks: 6 | - name: Ensure the kustomizations dir exists 7 | ansible.builtin.file: 8 | path: "{{ cifmw_basedir }}/artifacts/manifests/kustomizations/controlplane" 9 | state: directory 10 | 11 | - name: Create kustomization 12 | ansible.builtin.copy: 13 | dest: "{{ cifmw_basedir }}/artifacts/manifests/kustomizations/controlplane/71-controlplane-kustomization.yaml" 14 | content: |- 15 | apiVersion: kustomize.config.k8s.io/v1beta1 16 | kind: Kustomization 17 | resources: 18 | namespace: {{ cifmw_install_yamls_defaults['NAMESPACE'] }} 19 | patches: 20 | - target: 21 | kind: OpenStackControlPlane 22 | patch: |- 23 | - op: replace 24 | path: /spec/nova/template/apiServiceTemplate/replicas 25 | value: 2 26 | 27 | - op: replace 28 | path: /spec/neutron/template/replicas 29 | value: 2 30 | 31 | - op: replace 32 | path: /spec/neutron/template/customServiceConfig 33 | value: | 34 | [DEFAULT] 35 | debug = True 36 | 37 | - op: replace 38 | path: /spec/ovn/template/ovnDBCluster/ovndbcluster-nb/replicas 39 | value: 2 40 | 41 | - op: replace 42 | path: /spec/glance/template/glanceAPIs/default/replicas 43 | value: 2 44 | 45 | - op: replace 46 | path: /spec/cinder/template/cinderAPI/replicas 47 | value: 2 48 | 49 | - op: replace 50 | path: /spec/keystone/template/replicas 51 | value: 2 52 | -------------------------------------------------------------------------------- /ci/nova-operator-tempest-multinode/ci_fw_vars.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | cifmw_install_yamls_vars: 3 | BMO_SETUP: false 4 | INSTALL_CERT_MANAGER: false 5 | 6 | cifmw_edpm_prepare_skip_crc_storage_creation: true 7 | # as we scale the openstack services to 3 replicas we need more PVs 8 | cifmw_cls_pv_count: 20 9 | 10 | cifmw_services_swift_enabled: false 11 | 12 | 13 | # note by default the source for the playbook specified 14 | # in the hooks is relative to 15 | # https://github.com/openstack-k8s-operators/ci-framework/tree/main/hooks/playbooks 16 | # if you want to use a different source you can use the full path on the ansible controller 17 | post_ctlplane_deploy: 18 | - name: 71 Kustomize control plane to scale openstack services 19 | type: playbook 20 | source: "{{ ansible_user_dir }}/{{ zuul.projects['github.com/openstack-k8s-operators/nova-operator'].src_dir }}/ci/nova-operator-tempest-multinode/control_plane_hook.yaml" 21 | - name: 82 Kustomize and update Control Plane 22 | type: playbook 23 | source: control_plane_kustomize_deploy.yml 24 | - name: 85 Create neutron-metadata-custom 25 | type: playbook 26 | source: "{{ ansible_user_dir }}/{{ zuul.projects['github.com/openstack-k8s-operators/nova-operator'].src_dir }}/ci/nova-operator-tempest-multinode/pre_deploy_hook.yml" 27 | 28 | 29 | 30 | cifmw_run_tests: true 31 | cifmw_tempest_container: openstack-tempest-extras 32 | # we do not want the ci framework trying to enable any 33 | # tempest groups by default we will manage all tempest execution 34 | # via the job definition. 35 | cifmw_tempest_default_groups: [] 36 | 37 | 38 | cifmw_edpm_kustomize_content: |- 39 | apiVersion: kustomize.config.k8s.io/v1beta1 40 | kind: Kustomization 41 | resources: 42 | namespace: {{ cifmw_install_yamls_defaults.NAMESPACE }} 43 | patches: 44 | - target: 45 | kind: OpenStackDataPlaneNodeSet 46 | patch: |- 47 | - op: replace 48 | path: /spec/services 49 | value: 50 | - repo-setup 51 | - bootstrap 52 | - download-cache 53 | - configure-network 54 | - validate-network 55 | - install-os 56 | - configure-os 57 | - ssh-known-hosts 58 | - run-os 59 | - reboot-os 60 | - install-certs 61 | - ovn 62 | - neutron-metadata-custom 63 | - libvirt 64 | - nova 65 | - telemetry 66 | -------------------------------------------------------------------------------- /ci/nova-operator-tempest-multinode/control_plane_hook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Kustomize ControlPlane 3 | hosts: "{{ cifmw_target_hook_host | default('localhost') }}" 4 | gather_facts: false 5 | tasks: 6 | - name: Ensure the kustomizations dir exists 7 | ansible.builtin.file: 8 | path: "{{ cifmw_basedir }}/artifacts/manifests/kustomizations/controlplane" 9 | state: directory 10 | 11 | - name: Create kustomization 12 | ansible.builtin.copy: 13 | dest: "{{ cifmw_basedir }}/artifacts/manifests/kustomizations/controlplane/71-controlplane-kustomization.yaml" 14 | content: |- 15 | apiVersion: kustomize.config.k8s.io/v1beta1 16 | kind: Kustomization 17 | resources: 18 | namespace: {{ cifmw_install_yamls_defaults['NAMESPACE'] }} 19 | patches: 20 | - target: 21 | kind: OpenStackControlPlane 22 | patch: |- 23 | - op: replace 24 | path: /spec/nova/template/apiServiceTemplate/replicas 25 | value: 2 26 | 27 | - op: replace 28 | path: /spec/neutron/template/replicas 29 | value: 2 30 | 31 | - op: replace 32 | path: /spec/neutron/template/customServiceConfig 33 | value: | 34 | [DEFAULT] 35 | debug = True 36 | 37 | - op: replace 38 | path: /spec/keystone/template/replicas 39 | value: 2 40 | 41 | - op: add 42 | path: /spec/nova/template/cellTemplates 43 | value: 44 | cell0: 45 | cellDatabaseAccount: nova-cell0 46 | hasAPIAccess: true 47 | metadataServiceTemplate: 48 | enabled: false 49 | cell1: 50 | cellDatabaseAccount: nova-cell1 51 | hasAPIAccess: true 52 | cellMessageBusInstance: rabbitmq-cell1 53 | cellDatabaseInstance: openstack-cell1 54 | metadataServiceTemplate: 55 | enabled: true 56 | override: 57 | service: 58 | metadata: 59 | annotations: 60 | metallb.universe.tf/address-pool: internalapi 61 | metallb.universe.tf/allow-shared-ip: internalapi 62 | metallb.universe.tf/loadBalancerIPs: 172.17.0.80 63 | spec: 64 | type: LoadBalancer 65 | 66 | - op: add 67 | path: /spec/nova/template/metadataServiceTemplate/enabled 68 | value: false 69 | -------------------------------------------------------------------------------- /ci/nova-operator-tempest-multinode/pre_deploy_hook.yml: -------------------------------------------------------------------------------- 1 | - name: Create custom service 2 | hosts: "{{ cifmw_target_hook_host | default('localhost') }}" 3 | gather_facts: false 4 | tasks: 5 | - name: Create kustomization 6 | ansible.builtin.copy: 7 | dest: "{{ cifmw_basedir }}/artifacts/manifests/kustomizations/dataplane/98-kustomization.yaml" 8 | content: |- 9 | apiVersion: kustomize.config.k8s.io/v1beta1 10 | kind: Kustomization 11 | resources: 12 | namespace: {{ cifmw_install_yamls_defaults.NAMESPACE }} 13 | patches: 14 | - target: 15 | kind: OpenStackDataPlaneNodeSet 16 | patch: |- 17 | - op: replace 18 | path: /spec/services 19 | value: 20 | - repo-setup 21 | - bootstrap 22 | - download-cache 23 | - configure-network 24 | - validate-network 25 | - install-os 26 | - configure-os 27 | - ssh-known-hosts 28 | - run-os 29 | - reboot-os 30 | - install-certs 31 | - ovn 32 | - neutron-metadata-custom 33 | - libvirt 34 | - nova 35 | - telemetry 36 | - name: Create neutron-metadata-custom service 37 | environment: 38 | KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}" 39 | PATH: "{{ cifmw_path }}" 40 | ansible.builtin.shell: | 41 | oc apply -f - < ci/olm.yaml < 8 | apiDatabaseInstance: openstack 9 | apiDatabaseAccount: nova-api 10 | # This is the name of the single RabbitMqCluster CR we deploy today 11 | # The Service is labelled with 12 | # app.kubernetes.io/component=rabbitmq, app.kubernetes.io/name= 13 | apiMessageBusInstance: rabbitmq 14 | # This is the name of the KeystoneAPI CR we deploy today 15 | # The Service is labelled with service=keystone,internal=true 16 | keystoneInstance: keystone 17 | # This is the name of a Secret having fields according to the 18 | # passwordSelectors directly below and the passwordSelectors in each 19 | # NovaCellSpec instances 20 | # Today all the passwords are stored in the same Secret object named 21 | # osp-secret, but the openstack operator could create a nova specific 22 | # secret and pass it here in the future. 23 | secret: osp-secret 24 | apiServiceTemplate: 25 | customServiceConfig: | 26 | # service config customization 27 | [DEFAULT] 28 | debug=True 29 | defaultConfigOverwrite: 30 | policy.yaml: | 31 | # my custom policy configuration 32 | nodeSelector: {} 33 | schedulerServiceTemplate: 34 | customServiceConfig: | 35 | # service config customization 36 | [DEFAULT] 37 | debug=True 38 | nodeSelector: {} 39 | metadataServiceTemplate: 40 | customServiceConfig: | 41 | # service config customization 42 | [DEFAULT] 43 | debug=True 44 | defaultConfigOverwrite: 45 | api-paste.ini: | 46 | # my custom api paste config 47 | nodeSelector: {} 48 | cellTemplates: 49 | cell0: 50 | cellDatabaseInstance: openstack 51 | cellDatabaseAccount: nova-cell0 52 | cellMessageBusInstance: rabbitmq 53 | # cell0 alway needs access to the API DB and MQ as it hosts the super 54 | # conductor. It will inherit the API DB and MQ access from the Nova CR 55 | # that creates it. 56 | hasAPIAccess: true 57 | conductorServiceTemplate: 58 | customServiceConfig: | 59 | # service config customization 60 | [DEFAULT] 61 | debug=True 62 | nodeSelector: {} 63 | cell1: 64 | cellDatabaseInstance: mariadb-cell1 65 | cellDatabaseAccount: nova-cell1 66 | cellMessageBusInstance: rabbitmq-cell1 67 | # cell1 will have upcalls support. It will inherit the API DB and MQ 68 | # access from the Nova CR that creates it. 69 | hasAPIAccess: true 70 | conductorServiceTemplate: 71 | customServiceConfig: | 72 | # service config customization 73 | [DEFAULT] 74 | debug=True 75 | nodeSelector: {} 76 | noVNCProxyServiceTemplate: 77 | customServiceConfig: | 78 | # service config customization 79 | [DEFAULT] 80 | debug=True 81 | nodeSelector: {} 82 | cell2: 83 | cellDatabaseInstance: mariadb-cell2 84 | cellDatabaseAccount: nova-cell2 85 | cellMessageBusInstance: rabbitmq-cell2 86 | # cell2 will not get the API DB and MQ connection info from the Nova CR 87 | hasAPIAccess: false 88 | conductorServiceTemplate: 89 | customServiceConfig: | 90 | # service config customization 91 | [DEFAULT] 92 | debug=True 93 | nodeSelector: {} 94 | noVNCProxyServiceTemplate: 95 | customServiceConfig: | 96 | # service config customization 97 | [DEFAULT] 98 | debug=True 99 | nodeSelector: {} 100 | -------------------------------------------------------------------------------- /config/samples/nova_v1beta1_nova.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: Nova 3 | metadata: 4 | name: nova 5 | spec: 6 | secret: osp-secret 7 | -------------------------------------------------------------------------------- /config/samples/nova_v1beta1_nova_collapsed_cell.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: Nova 3 | metadata: 4 | name: nova 5 | spec: 6 | secret: osp-secret 7 | cellTemplates: 8 | cell0: 9 | cellDatabaseAccount: nova-cell0 10 | conductorServiceTemplate: 11 | # conductor in cell1 will act both as the super conductor and as the 12 | # cell1 conductor 13 | replicas: 0 14 | hasAPIAccess: true 15 | cell1: 16 | cellDatabaseAccount: nova-cell1 17 | conductorServiceTemplate: 18 | replicas: 1 19 | hasAPIAccess: true 20 | -------------------------------------------------------------------------------- /config/samples/nova_v1beta1_novaapi.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: NovaAPI 3 | metadata: 4 | name: novaapi-sample 5 | spec: 6 | apiDatabaseHostname: openstack 7 | cell0DatabaseHostname: openstack 8 | keystoneAuthURL: http://keystone-public-openstack.apps-crc.testing 9 | secret: osp-secret 10 | serviceAccount: nova 11 | registeredCells: {} 12 | memcachedInstance: memcached 13 | -------------------------------------------------------------------------------- /config/samples/nova_v1beta1_novacell0.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: NovaCell 3 | metadata: 4 | name: novacell0-sample 5 | spec: 6 | # cell0 always needs API DB access 7 | apiDatabaseHostname: openstack 8 | cellDatabaseHostname: openstack 9 | cellName: cell0 10 | keystoneAuthURL: http://keystone-public-openstack.apps-crc.testing 11 | secret: osp-secret 12 | serviceAccount: nova 13 | memcachedInstance: memcached 14 | -------------------------------------------------------------------------------- /config/samples/nova_v1beta1_novacell1-upcall.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: NovaCell 3 | metadata: 4 | name: novacell1-with-upcall-sample 5 | spec: 6 | # By having access to the API DB this cell has upcall support 7 | apiDatabaseHostname: openstack 8 | cellDatabaseHostname: openstack 9 | cellName: cell1 10 | keystoneAuthURL: http://keystone-public-openstack.apps-crc.testing 11 | secret: osp-secret 12 | serviceAccount: nova 13 | memcachedInstance: memcached 14 | -------------------------------------------------------------------------------- /config/samples/nova_v1beta1_novacell2-without-upcall.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: NovaCell 3 | metadata: 4 | name: novacell2-without-upcall-sample 5 | spec: 6 | cellDatabaseHostname: openstack 7 | cellName: cell2 8 | keystoneAuthURL: http://keystone-public-openstack.apps-crc.testing 9 | secret: osp-secret 10 | serviceAccount: nova 11 | memcachedInstance: memcached 12 | -------------------------------------------------------------------------------- /config/samples/nova_v1beta1_novacompute-ironic.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: NovaCompute 3 | metadata: 4 | name: nova-compute-ironic 5 | spec: 6 | novaComputeTemplates: 7 | compute-ironic: 8 | customServiceConfig: "" 9 | replicas: 1 10 | resources: {} 11 | computeDriver: ironic.IronicDriver 12 | networkAttachments: 13 | - internalapi 14 | -------------------------------------------------------------------------------- /config/samples/nova_v1beta1_novaconductor-cell.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: NovaConductor 3 | metadata: 4 | name: novaconductor-sample 5 | spec: 6 | cellName: cell1 7 | keystoneAuthURL: http://keystone-public-openstack.apps-crc.testing 8 | secret: osp-secret 9 | serviceAccount: nova 10 | memcachedInstance: memcached 11 | -------------------------------------------------------------------------------- /config/samples/nova_v1beta1_novaconductor-super.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: NovaConductor 3 | metadata: 4 | name: novaconductor-sample 5 | spec: 6 | apiDatabaseHostname: openstack 7 | cellName: cell0 8 | keystoneAuthURL: http://keystone-public-openstack.apps-crc.testing 9 | secret: osp-secret 10 | serviceAccount: nova 11 | memcachedInstance: memcached 12 | -------------------------------------------------------------------------------- /config/samples/nova_v1beta1_novametadata.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: NovaMetadata 3 | metadata: 4 | name: novametadata-sample 5 | spec: 6 | apiDatabaseHostname: openstack 7 | cellDatabaseHostname: openstack 8 | cellDatabaseAccount: nova-cell0 9 | keystoneAuthURL: http://keystone-public-openstack.apps-crc.testing 10 | secret: osp-secret 11 | apiDatabaseAccount: nova-api 12 | serviceAccount: nova 13 | registeredCells: {} 14 | memcachedInstance: memcached 15 | -------------------------------------------------------------------------------- /config/samples/nova_v1beta1_novanovncproxy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: NovaNoVNCProxy 3 | metadata: 4 | name: novanovncproxy-sample 5 | spec: 6 | # TODO(user): Add fields here 7 | -------------------------------------------------------------------------------- /config/samples/nova_v1beta1_novascheduler.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: NovaScheduler 3 | metadata: 4 | name: novascheduler-sample 5 | spec: 6 | secret: osp-secret 7 | apiDatabaseHostname: openstack 8 | cell0DatabaseHostname: openstack 9 | keystoneAuthURL: http://keystone-public-openstack.apps-crc.testing 10 | customServiceConfig: | 11 | [DEFAULT] 12 | debug=true 13 | serviceAccount: nova 14 | registeredCells: {} 15 | memcachedInstance: memcached 16 | -------------------------------------------------------------------------------- /config/scorecard/bases/config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scorecard.operatorframework.io/v1alpha3 2 | kind: Configuration 3 | metadata: 4 | name: config 5 | stages: 6 | - parallel: true 7 | tests: [] 8 | -------------------------------------------------------------------------------- /config/scorecard/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - bases/config.yaml 3 | patchesJson6902: 4 | - path: patches/basic.config.yaml 5 | target: 6 | group: scorecard.operatorframework.io 7 | version: v1alpha3 8 | kind: Configuration 9 | name: config 10 | - path: patches/olm.config.yaml 11 | target: 12 | group: scorecard.operatorframework.io 13 | version: v1alpha3 14 | kind: Configuration 15 | name: config 16 | #+kubebuilder:scaffold:patchesJson6902 17 | -------------------------------------------------------------------------------- /config/scorecard/patches/basic.config.yaml: -------------------------------------------------------------------------------- 1 | - op: add 2 | path: /stages/0/tests/- 3 | value: 4 | entrypoint: 5 | - scorecard-test 6 | - basic-check-spec 7 | image: quay.io/operator-framework/scorecard-test:v1.23.0 8 | labels: 9 | suite: basic 10 | test: basic-check-spec-test 11 | -------------------------------------------------------------------------------- /config/scorecard/patches/olm.config.yaml: -------------------------------------------------------------------------------- 1 | - op: add 2 | path: /stages/0/tests/- 3 | value: 4 | entrypoint: 5 | - scorecard-test 6 | - olm-bundle-validation 7 | image: quay.io/operator-framework/scorecard-test:v1.23.0 8 | labels: 9 | suite: olm 10 | test: olm-bundle-validation-test 11 | - op: add 12 | path: /stages/0/tests/- 13 | value: 14 | entrypoint: 15 | - scorecard-test 16 | - olm-crds-have-validation 17 | image: quay.io/operator-framework/scorecard-test:v1.23.0 18 | labels: 19 | suite: olm 20 | test: olm-crds-have-validation-test 21 | - op: add 22 | path: /stages/0/tests/- 23 | value: 24 | entrypoint: 25 | - scorecard-test 26 | - olm-crds-have-resources 27 | image: quay.io/operator-framework/scorecard-test:v1.23.0 28 | labels: 29 | suite: olm 30 | test: olm-crds-have-resources-test 31 | - op: add 32 | path: /stages/0/tests/- 33 | value: 34 | entrypoint: 35 | - scorecard-test 36 | - olm-spec-descriptors 37 | image: quay.io/operator-framework/scorecard-test:v1.23.0 38 | labels: 39 | suite: olm 40 | test: olm-spec-descriptors-test 41 | - op: add 42 | path: /stages/0/tests/- 43 | value: 44 | entrypoint: 45 | - scorecard-test 46 | - olm-status-descriptors 47 | image: quay.io/operator-framework/scorecard-test:v1.23.0 48 | labels: 49 | suite: olm 50 | test: olm-status-descriptors-test 51 | -------------------------------------------------------------------------------- /config/webhook/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manifests.yaml 3 | - service.yaml 4 | 5 | configurations: 6 | - kustomizeconfig.yaml 7 | -------------------------------------------------------------------------------- /config/webhook/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # the following config is for teaching kustomize where to look at when substituting vars. 2 | # It requires kustomize v2.1.0 or newer to work properly. 3 | nameReference: 4 | - kind: Service 5 | version: v1 6 | fieldSpecs: 7 | - kind: MutatingWebhookConfiguration 8 | group: admissionregistration.k8s.io 9 | path: webhooks/clientConfig/service/name 10 | - kind: ValidatingWebhookConfiguration 11 | group: admissionregistration.k8s.io 12 | path: webhooks/clientConfig/service/name 13 | 14 | namespace: 15 | - kind: MutatingWebhookConfiguration 16 | group: admissionregistration.k8s.io 17 | path: webhooks/clientConfig/service/namespace 18 | create: true 19 | - kind: ValidatingWebhookConfiguration 20 | group: admissionregistration.k8s.io 21 | path: webhooks/clientConfig/service/namespace 22 | create: true 23 | 24 | varReference: 25 | - path: metadata/annotations 26 | -------------------------------------------------------------------------------- /config/webhook/service.yaml: -------------------------------------------------------------------------------- 1 | 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: service 7 | app.kubernetes.io/instance: webhook-service 8 | app.kubernetes.io/component: webhook 9 | app.kubernetes.io/created-by: nova-operator 10 | app.kubernetes.io/part-of: nova-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: webhook-service 13 | namespace: system 14 | spec: 15 | ports: 16 | - port: 443 17 | protocol: TCP 18 | targetPort: 9444 19 | selector: 20 | openstack.org/operator-name: nova 21 | -------------------------------------------------------------------------------- /doc/developer.md: -------------------------------------------------------------------------------- 1 | 2 | # Implementation guidelines 3 | This is a collection of guidelines for developing the nova-operator. The goal 4 | here is to keep the codebase consistent and help spread good patterns 5 | between the developers. 6 | 7 | Please read the [developer guidelines](https://github.com/openstack-k8s-operators/docs/blob/main/developer.md) 8 | from openstack-k8s-operator first. Also use that doc for guidelines that are 9 | true for the whole openstack-k8s-operator development and use this nova 10 | specific doc for nova specific guidelines. 11 | 12 | ## \ 13 | -------------------------------------------------------------------------------- /doc/testing_with_nova.md: -------------------------------------------------------------------------------- 1 | 2 | # Testing with local nova 3 | 4 | 5 | Nova is included in several services in the control plane: nova-api, nova-cellX-conductor, nova-cellX-novncproxy, nova-metadata, and nova-scheduler container image. The nova-operator doesn't support extra volume mounts for any of the mentioned pods. However, thanks to oc debug, it is possible to develop and test local changes to nova without having to build and deploy new Nova OpenStack changes. 6 | 7 | ## Provide NFS access to your nova-openstack directory 8 | 9 | 10 | The technique described here uses NFS to access the nova opensctack directory on 11 | your development system, so you'll need to install an NFS server and create 12 | an appropriate export on your development system. Of course, this implies 13 | your OpenShift deployment that runs the openstack-operator has access to 14 | the NFS server, including any required firewall rules. 15 | 16 | When using OpenShift Local (aka CRC), your export will be something like this: 17 | 18 | ``` 19 | % echo "${HOME}/nova/nova 192.168.130.0/24(rw,sync,no_root_squash)" > /etc/exports 20 | 21 | % exportfs -r 22 | ``` 23 | 24 | Make sure nfs-server and firewalld are started: 25 | 26 | 27 | ``` % systemctl start firewalld 28 | % systemctl start nfs-server 29 | ``` 30 | ### tip:: 31 | 32 | CRC installs its own firewall rules, which likely will need to be adjusted 33 | depending on the location of your NFS server. If your nova-openstack 34 | directory is on the same system that hosts your CRC, then the simplest 35 | thing to do is insert a rule that essentially circumvents the other rules: 36 | 37 | `% nft add rule inet firewalld filter_IN_libvirt_pre accept` 38 | 39 | ## Create nova openstack PV and PVC 40 | 41 | 42 | Create an NFS PV, and a PVC that can be mounted on the ansibleee pods. 43 | 44 | ### note:: 45 | 46 | While it's possible to add an NFS volume directly to a pod, the default k8s 47 | Security Context Constraint (SCC) for non-privileged pods does not permit 48 | NFS volume mounts. The approach of using an NFS PV and PVC works just as 49 | well, and avoids the need to fiddle with SCC policies. 50 | 51 | ``` 52 | NFS_SHARE= 53 | NFS_SERVER= 54 | cat <nova-openstack-storage.yaml 55 | apiVersion: v1 56 | kind: PersistentVolume 57 | metadata: 58 | # Do not use just "nova" for the metadata name! 59 | name: nova-openstack-dev 60 | spec: 61 | capacity: 62 | storage: 1Gi 63 | volumeMode: Filesystem 64 | accessModes: 65 | - ReadOnlyMany 66 | # IMPORTANT! The persistentVolumeReclaimPolicy must be "Retain" or else 67 | # your code will be deleted when the volume is reclaimed! 68 | persistentVolumeReclaimPolicy: Retain 69 | storageClassName: nova-openstack 70 | mountOptions: 71 | - nfsvers=4.1 72 | nfs: 73 | path: ${NFS_SHARE} 74 | server: ${NFS_SERVER} 75 | --- 76 | apiVersion: v1 77 | kind: PersistentVolumeClaim 78 | metadata: 79 | name: nova-openstack-dev 80 | spec: 81 | storageClassName: nova-openstack 82 | accessModes: 83 | - ReadOnlyMany 84 | resources: 85 | requests: 86 | storage: 1Gi 87 | EOF 88 | 89 | oc apply -f nova-openstacke-storage.yaml 90 | ``` 91 | 92 | ## Add additional mounts to your CR 93 | 94 | 95 | First, we need to get the correct pod definition to debug. From oc get pod, find the pod in which you want to replace Nova and then run: 96 | ``` 97 | oc debug --keep-labels=true pod/nova- -o yaml 98 | ``` 99 | 100 | Next, edit the file to add the Nova OpenStack PVC to the pod definition: 101 | 102 | ``` 103 | spec: 104 | containers: 105 | volumeMounts: 106 | - mountPath: /usr/lib/python3.9/site-packages/nova 107 | name: nova-openstack 108 | name: config-data 109 | volumes: 110 | - name: nova-openstack 111 | persistentVolumeClaim: 112 | claimName: nova-openstack 113 | readOnly: true 114 | ``` 115 | 116 | Now we can spawn the container using: `oc debug -f ` 117 | Finally, scale your pod to zero by using `oc edit OpenStackControlPlane` and editing the replicas of the selected service to 0. 118 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/openstack-k8s-operators/nova-operator 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/go-logr/logr v1.4.2 7 | github.com/google/go-cmp v0.7.0 8 | github.com/google/uuid v1.6.0 9 | github.com/gophercloud/gophercloud v1.14.1 10 | github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.7.6 11 | github.com/onsi/ginkgo/v2 v2.20.1 12 | github.com/onsi/gomega v1.34.1 13 | github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250430070919-2ce4eea3a06d 14 | github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20250429200536-ceab98cb3680 15 | github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250505061650-7cb2f323fb35 16 | github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20250423055245-3cb2ae8df6f0 17 | github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20250423055245-3cb2ae8df6f0 18 | github.com/openstack-k8s-operators/mariadb-operator/api v0.6.1-0.20250429105455-119a21fd879a 19 | github.com/openstack-k8s-operators/nova-operator/api v0.0.0-20221209164002-f9e6b9363961 20 | go.uber.org/zap v1.27.0 21 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 22 | gopkg.in/yaml.v3 v3.0.1 23 | k8s.io/api v0.29.15 24 | k8s.io/apimachinery v0.29.15 25 | k8s.io/client-go v0.29.15 26 | k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 27 | sigs.k8s.io/controller-runtime v0.17.6 28 | ) 29 | 30 | require ( 31 | github.com/beorn7/perks v1.0.1 // indirect 32 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 33 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 34 | github.com/emicklei/go-restful/v3 v3.12.0 // indirect 35 | github.com/evanphx/json-patch/v5 v5.9.0 // indirect 36 | github.com/fsnotify/fsnotify v1.7.0 // indirect 37 | github.com/go-logr/zapr v1.3.0 // indirect 38 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 39 | github.com/go-openapi/jsonreference v0.21.0 // indirect 40 | github.com/go-openapi/swag v0.23.0 // indirect 41 | github.com/go-task/slim-sprig/v3 v3.0.0 // indirect 42 | github.com/gogo/protobuf v1.3.2 // indirect 43 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 44 | github.com/golang/protobuf v1.5.4 // indirect 45 | github.com/google/gnostic-models v0.6.8 // indirect 46 | github.com/google/gofuzz v1.2.0 // indirect 47 | github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect 48 | github.com/imdario/mergo v0.3.16 // indirect 49 | github.com/josharian/intern v1.0.0 // indirect 50 | github.com/json-iterator/go v1.1.12 // indirect 51 | github.com/mailru/easyjson v0.7.7 // indirect 52 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 53 | github.com/modern-go/reflect2 v1.0.2 // indirect 54 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 55 | github.com/openshift/api v3.9.0+incompatible // indirect 56 | github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20250423055245-3cb2ae8df6f0 // indirect 57 | github.com/pkg/errors v0.9.1 // indirect 58 | github.com/prometheus/client_golang v1.19.0 // indirect 59 | github.com/prometheus/client_model v0.6.0 // indirect 60 | github.com/prometheus/common v0.51.1 // indirect 61 | github.com/prometheus/procfs v0.13.0 // indirect 62 | github.com/rabbitmq/cluster-operator/v2 v2.9.0 // indirect 63 | github.com/robfig/cron/v3 v3.0.1 // indirect 64 | github.com/spf13/pflag v1.0.5 // indirect 65 | go.uber.org/multierr v1.11.0 // indirect 66 | golang.org/x/mod v0.20.0 // indirect 67 | golang.org/x/net v0.28.0 // indirect 68 | golang.org/x/oauth2 v0.18.0 // indirect 69 | golang.org/x/sys v0.23.0 // indirect 70 | golang.org/x/term v0.23.0 // indirect 71 | golang.org/x/text v0.17.0 // indirect 72 | golang.org/x/time v0.5.0 // indirect 73 | golang.org/x/tools v0.24.0 // indirect 74 | gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect 75 | google.golang.org/appengine v1.6.8 // indirect 76 | google.golang.org/protobuf v1.34.1 // indirect 77 | gopkg.in/inf.v0 v0.9.1 // indirect 78 | gopkg.in/yaml.v2 v2.4.0 // indirect 79 | k8s.io/apiextensions-apiserver v0.29.15 // indirect 80 | k8s.io/component-base v0.29.15 // indirect 81 | k8s.io/klog/v2 v2.120.1 // indirect 82 | k8s.io/kube-openapi v0.0.0-20240322212309-b815d8309940 // indirect 83 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect 84 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect 85 | sigs.k8s.io/yaml v1.4.0 // indirect 86 | ) 87 | 88 | replace github.com/openstack-k8s-operators/nova-operator/api => ./api 89 | 90 | // mschuppert: map to latest commit from release-4.16 tag 91 | // must consistent within modules and service operators 92 | replace github.com/openshift/api => github.com/openshift/api v0.0.0-20240830023148-b7d0481c9094 //allow-merging 93 | 94 | // custom RabbitmqClusterSpecCore for OpenStackControlplane (v2.6.0_patches_tag) 95 | replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20241017142550-a3524acedd49 //allow-merging 96 | -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | -------------------------------------------------------------------------------- /hack/build-crd-schema-checker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | 4 | if [ -f "$INSTALL_DIR/crd-schema-checker" ]; then 5 | exit 0 6 | fi 7 | 8 | mkdir -p "$INSTALL_DIR/git-tmp" 9 | git clone https://github.com/openshift/crd-schema-checker.git \ 10 | -b "$CRD_SCHEMA_CHECKER_VERSION" "$INSTALL_DIR/git-tmp" 11 | pushd "$INSTALL_DIR/git-tmp" 12 | GOWORK=off make 13 | cp crd-schema-checker "$INSTALL_DIR/" 14 | popd 15 | rm -rf "$INSTALL_DIR/git-tmp" 16 | -------------------------------------------------------------------------------- /hack/clean_local_webhook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | oc delete validatingwebhookconfiguration/vnova.kb.io --ignore-not-found 5 | oc delete mutatingwebhookconfiguration/mnova.kb.io --ignore-not-found 6 | oc delete validatingwebhookconfiguration/vnovaapi.kb.io --ignore-not-found 7 | oc delete mutatingwebhookconfiguration/mnovaapi.kb.io --ignore-not-found 8 | oc delete validatingwebhookconfiguration/vnovacell.kb.io --ignore-not-found 9 | oc delete mutatingwebhookconfiguration/mnovacell.kb.io --ignore-not-found 10 | oc delete validatingwebhookconfiguration/vnovaconductor.kb.io --ignore-not-found 11 | oc delete mutatingwebhookconfiguration/mnovaconductor.kb.io --ignore-not-found 12 | oc delete validatingwebhookconfiguration/vnovametadata.kb.io --ignore-not-found 13 | oc delete mutatingwebhookconfiguration/mnovametadata.kb.io --ignore-not-found 14 | oc delete validatingwebhookconfiguration/vnovanovncproxy.kb.io --ignore-not-found 15 | oc delete mutatingwebhookconfiguration/mnovanovncproxy.kb.io --ignore-not-found 16 | oc delete validatingwebhookconfiguration/vnovascheduler.kb.io --ignore-not-found 17 | oc delete mutatingwebhookconfiguration/mnovascheduler.kb.io --ignore-not-found 18 | oc delete validatingwebhookconfiguration/vnovacompute.kb.io --ignore-not-found 19 | oc delete mutatingwebhookconfiguration/mnovacompute.kb.io --ignore-not-found 20 | -------------------------------------------------------------------------------- /hack/crd-schema-checker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | 4 | CHECKER=$INSTALL_DIR/crd-schema-checker 5 | 6 | TMP_DIR=$(mktemp -d) 7 | 8 | function cleanup { 9 | rm -rf "$TMP_DIR" 10 | } 11 | 12 | trap cleanup EXIT 13 | 14 | 15 | for crd in config/crd/bases/*.yaml; do 16 | mkdir -p "$(dirname "$TMP_DIR/$crd")" 17 | if git show "$BASE_REF:$crd" > "$TMP_DIR/$crd"; then 18 | $CHECKER check-manifests \ 19 | --existing-crd-filename="$TMP_DIR/$crd" \ 20 | --new-crd-filename="$crd" 21 | fi 22 | done 23 | -------------------------------------------------------------------------------- /hack/install-krew.sh: -------------------------------------------------------------------------------- 1 | ( 2 | set -x; cd "$(mktemp -d)" && 3 | OS="$(uname | tr '[:upper:]' '[:lower:]')" && 4 | ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')" && 5 | KREW="krew-${OS}_${ARCH}" && 6 | curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz" && 7 | tar zxvf "${KREW}.tar.gz" && 8 | ./"${KREW}" install krew 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/nova/celldelete.go: -------------------------------------------------------------------------------- 1 | package nova 2 | 3 | import ( 4 | batchv1 "k8s.io/api/batch/v1" 5 | corev1 "k8s.io/api/core/v1" 6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 | "k8s.io/utils/ptr" 8 | 9 | "github.com/openstack-k8s-operators/lib-common/modules/common/env" 10 | novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" 11 | ) 12 | 13 | func CellDeleteJob( 14 | instance *novav1.Nova, 15 | cell *novav1.NovaCell, 16 | configName string, 17 | scriptName string, 18 | inputHash string, 19 | labels map[string]string, 20 | ) *batchv1.Job { 21 | args := []string{"-c", KollaServiceCommand} 22 | 23 | envVars := map[string]env.Setter{} 24 | envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") 25 | envVars["KOLLA_BOOTSTRAP"] = env.SetValue("true") 26 | envVars["CELL_NAME"] = env.SetValue(cell.Spec.CellName) 27 | 28 | // This is stored in the Job so that if the input of the job changes 29 | // then it results in a new job hash and therefore lib-common will re-run 30 | // the job 31 | envVars["INPUT_HASH"] = env.SetValue(inputHash) 32 | 33 | env := env.MergeEnvs([]corev1.EnvVar{}, envVars) 34 | 35 | jobName := instance.Name + "-" + cell.Spec.CellName + "-cell-delete" 36 | 37 | volumes := []corev1.Volume{ 38 | GetConfigVolume(configName), 39 | GetScriptVolume(scriptName), 40 | } 41 | volumeMounts := []corev1.VolumeMount{ 42 | GetConfigVolumeMount(), 43 | GetScriptVolumeMount(), 44 | GetKollaConfigVolumeMount("cell-delete"), 45 | } 46 | 47 | // add CA cert if defined 48 | if instance.Spec.APIServiceTemplate.TLS.CaBundleSecretName != "" { 49 | volumes = append(volumes, instance.Spec.APIServiceTemplate.TLS.CreateVolume()) 50 | volumeMounts = append(volumeMounts, instance.Spec.APIServiceTemplate.TLS.CreateVolumeMounts(nil)...) 51 | } 52 | 53 | job := &batchv1.Job{ 54 | ObjectMeta: metav1.ObjectMeta{ 55 | Name: jobName, 56 | Namespace: instance.Namespace, 57 | Labels: labels, 58 | }, 59 | Spec: batchv1.JobSpec{ 60 | Template: corev1.PodTemplateSpec{ 61 | Spec: corev1.PodSpec{ 62 | RestartPolicy: corev1.RestartPolicyOnFailure, 63 | ServiceAccountName: instance.RbacResourceName(), 64 | Volumes: volumes, 65 | Containers: []corev1.Container{ 66 | { 67 | Name: "nova-manage", 68 | Command: []string{ 69 | "/bin/bash", 70 | }, 71 | Args: args, 72 | Image: cell.Spec.ConductorContainerImageURL, 73 | SecurityContext: &corev1.SecurityContext{ 74 | RunAsUser: ptr.To(NovaUserID), 75 | }, 76 | Env: env, 77 | VolumeMounts: volumeMounts, 78 | }, 79 | }, 80 | }, 81 | }, 82 | }, 83 | } 84 | 85 | if cell.Spec.NodeSelector != nil { 86 | job.Spec.Template.Spec.NodeSelector = *cell.Spec.NodeSelector 87 | } 88 | 89 | return job 90 | } 91 | -------------------------------------------------------------------------------- /pkg/nova/cellmapping.go: -------------------------------------------------------------------------------- 1 | package nova 2 | 3 | import ( 4 | batchv1 "k8s.io/api/batch/v1" 5 | corev1 "k8s.io/api/core/v1" 6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 | "k8s.io/utils/ptr" 8 | 9 | "github.com/openstack-k8s-operators/lib-common/modules/common/env" 10 | novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" 11 | ) 12 | 13 | func CellMappingJob( 14 | instance *novav1.Nova, 15 | cell *novav1.NovaCell, 16 | configName string, 17 | scriptName string, 18 | inputHash string, 19 | labels map[string]string, 20 | ) *batchv1.Job { 21 | args := []string{"-c", KollaServiceCommand} 22 | 23 | envVars := map[string]env.Setter{} 24 | envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") 25 | envVars["KOLLA_BOOTSTRAP"] = env.SetValue("true") 26 | envVars["CELL_NAME"] = env.SetValue(cell.Spec.CellName) 27 | 28 | // This is stored in the Job so that if the input of the job changes 29 | // then it results in a new job hash and therefore lib-common will re-run 30 | // the job 31 | envVars["INPUT_HASH"] = env.SetValue(inputHash) 32 | 33 | env := env.MergeEnvs([]corev1.EnvVar{}, envVars) 34 | 35 | jobName := instance.Name + "-" + cell.Spec.CellName + "-cell-mapping" 36 | 37 | volumes := []corev1.Volume{ 38 | GetConfigVolume(configName), 39 | GetScriptVolume(scriptName), 40 | } 41 | volumeMounts := []corev1.VolumeMount{ 42 | GetConfigVolumeMount(), 43 | GetScriptVolumeMount(), 44 | GetKollaConfigVolumeMount("cell-mapping"), 45 | } 46 | 47 | // add CA cert if defined 48 | if instance.Spec.APIServiceTemplate.TLS.CaBundleSecretName != "" { 49 | volumes = append(volumes, instance.Spec.APIServiceTemplate.TLS.CreateVolume()) 50 | volumeMounts = append(volumeMounts, instance.Spec.APIServiceTemplate.TLS.CreateVolumeMounts(nil)...) 51 | } 52 | 53 | job := &batchv1.Job{ 54 | ObjectMeta: metav1.ObjectMeta{ 55 | Name: jobName, 56 | Namespace: instance.Namespace, 57 | Labels: labels, 58 | }, 59 | Spec: batchv1.JobSpec{ 60 | Template: corev1.PodTemplateSpec{ 61 | Spec: corev1.PodSpec{ 62 | RestartPolicy: corev1.RestartPolicyOnFailure, 63 | ServiceAccountName: instance.RbacResourceName(), 64 | Volumes: volumes, 65 | Containers: []corev1.Container{ 66 | { 67 | Name: "nova-manage", 68 | Command: []string{ 69 | "/bin/bash", 70 | }, 71 | Args: args, 72 | Image: cell.Spec.ConductorContainerImageURL, 73 | SecurityContext: &corev1.SecurityContext{ 74 | RunAsUser: ptr.To(NovaUserID), 75 | }, 76 | Env: env, 77 | VolumeMounts: volumeMounts, 78 | }, 79 | }, 80 | }, 81 | }, 82 | }, 83 | } 84 | 85 | if cell.Spec.NodeSelector != nil { 86 | job.Spec.Template.Spec.NodeSelector = *cell.Spec.NodeSelector 87 | } 88 | 89 | return job 90 | } 91 | -------------------------------------------------------------------------------- /pkg/nova/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package nova 18 | 19 | import ( 20 | "fmt" 21 | 22 | mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" 23 | ) 24 | 25 | const ( 26 | // KollaServiceCommand - the command to start the service binary in the kolla container 27 | KollaServiceCommand = "/usr/local/bin/kolla_start" 28 | // NovaUserID is the linux user ID used by Kolla for the nova user 29 | // in the service containers 30 | NovaUserID int64 = 42436 31 | ) 32 | 33 | // GetScriptSecretName returns the name of the Secret used for the 34 | // db sync scripts 35 | func GetScriptSecretName(crName string) string { 36 | return fmt.Sprintf("%s-scripts", crName) 37 | } 38 | 39 | // GetServiceConfigSecretName returns the name of the Secret used to 40 | // store the service configuration files 41 | func GetServiceConfigSecretName(crName string) string { 42 | return fmt.Sprintf("%s-config-data", crName) 43 | } 44 | 45 | // DatabaseStatus - 46 | type DatabaseStatus int 47 | 48 | const ( 49 | // DBFailed - 50 | DBFailed DatabaseStatus = iota 51 | // DBCreating - 52 | DBCreating DatabaseStatus = iota 53 | // DBCompleted - 54 | DBCompleted DatabaseStatus = iota 55 | ) 56 | 57 | // MessageBusStatus - 58 | type MessageBusStatus int 59 | 60 | const ( 61 | // MQFailed - 62 | MQFailed MessageBusStatus = iota 63 | // MQCreating - 64 | MQCreating MessageBusStatus = iota 65 | // MQCompleted - 66 | MQCompleted MessageBusStatus = iota 67 | ) 68 | 69 | type CellDeploymentStatus int 70 | 71 | // CellDeploymentStatus - 72 | const ( 73 | // CellDeploying indicates that NovaCell is created and waiting to reach 74 | // Ready status 75 | CellDeploying CellDeploymentStatus = iota 76 | // CellMapping indicates that NovaCell reached the Ready status and it is 77 | // being mapped to the Nova API database 78 | CellMapping CellDeploymentStatus = iota 79 | // CellMappingFailed indicates that NovaCell reached the Ready status but 80 | // mapping it to the Nova API database failed 81 | CellMappingFailed CellDeploymentStatus = iota 82 | // CellMappingReady indicates that NovaCell reached the Ready status and 83 | // it is mapped to the Nova API database 84 | CellMappingReady CellDeploymentStatus = iota 85 | // CellReady indicates that the NovaCell is Ready and it is mapped to 86 | // Nova API database so it is accessible. 87 | CellReady CellDeploymentStatus = iota 88 | // CellFailed indicates that the NovaCell deployment failed. 89 | CellFailed CellDeploymentStatus = iota 90 | // CellComputeDiscovering indicates that all NovaComputes in the cell have reached the Ready status, 91 | // and the hosts in the cell are still in the process of being discovered. 92 | CellComputeDiscovering CellDeploymentStatus = iota 93 | // CellComputeDiscoveryFailed indicates that all NovaComputes in cell reached the Ready status but 94 | // host discovery is failed 95 | CellComputeDiscoveryFailed CellDeploymentStatus = iota 96 | // CellComputeDiscoveryReady indicates that all NovaComputes in cell reached the Ready status and 97 | // the hosts in the cell have been successfully discovered 98 | CellComputeDiscoveryReady CellDeploymentStatus = iota 99 | // CellDeleteInProgress indicates that the NovaCell deletion is in progress 100 | CellDeleteInProgress CellDeploymentStatus = iota 101 | // CellDeleteFailed indicates that the NovaCell deletion failed 102 | CellDeleteFailed CellDeploymentStatus = iota 103 | // CellDeleteComplete indicates that the NovaCell deletion is complete 104 | CellDeleteComplete CellDeploymentStatus = iota 105 | ) 106 | 107 | // Database - 108 | type Database struct { 109 | Database *mariadbv1.Database 110 | Status DatabaseStatus 111 | } 112 | 113 | // MessageBus - 114 | type MessageBus struct { 115 | TransportURL string 116 | Status MessageBusStatus 117 | } 118 | -------------------------------------------------------------------------------- /pkg/nova/host_discover.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | package nova 16 | 17 | import ( 18 | env "github.com/openstack-k8s-operators/lib-common/modules/common/env" 19 | novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" 20 | 21 | batchv1 "k8s.io/api/batch/v1" 22 | corev1 "k8s.io/api/core/v1" 23 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | "k8s.io/utils/ptr" 25 | ) 26 | 27 | func HostDiscoveryJob( 28 | instance *novav1.NovaCell, 29 | configName string, 30 | scriptName string, 31 | inputHash string, 32 | labels map[string]string, 33 | ) *batchv1.Job { 34 | args := []string{"-c", KollaServiceCommand} 35 | 36 | envVars := map[string]env.Setter{} 37 | envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") 38 | envVars["KOLLA_BOOTSTRAP"] = env.SetValue("true") 39 | 40 | // This is stored in the Job so that if the input of the job changes 41 | // then it results in a new job hash and therefore lib-common will re-run 42 | // the job 43 | envVars["INPUT_HASH"] = env.SetValue(inputHash) 44 | 45 | env := env.MergeEnvs([]corev1.EnvVar{}, envVars) 46 | 47 | jobName := instance.Name + "-host-discover" 48 | 49 | volumes := []corev1.Volume{ 50 | GetConfigVolume(configName), 51 | GetScriptVolume(scriptName), 52 | } 53 | volumeMounts := []corev1.VolumeMount{ 54 | GetConfigVolumeMount(), 55 | GetScriptVolumeMount(), 56 | GetKollaConfigVolumeMount("host-discover"), 57 | } 58 | 59 | // add CA cert if defined 60 | if instance.Spec.TLS.CaBundleSecretName != "" { 61 | volumes = append(volumes, instance.Spec.TLS.CreateVolume()) 62 | volumeMounts = append(volumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) 63 | } 64 | 65 | job := &batchv1.Job{ 66 | ObjectMeta: metav1.ObjectMeta{ 67 | Name: jobName, 68 | Namespace: instance.Namespace, 69 | Labels: labels, 70 | }, 71 | Spec: batchv1.JobSpec{ 72 | Template: corev1.PodTemplateSpec{ 73 | Spec: corev1.PodSpec{ 74 | RestartPolicy: corev1.RestartPolicyOnFailure, 75 | ServiceAccountName: instance.Spec.ServiceAccount, 76 | Volumes: volumes, 77 | Containers: []corev1.Container{ 78 | { 79 | Name: "nova-manage", 80 | Command: []string{ 81 | "/bin/bash", 82 | }, 83 | Args: args, 84 | Image: instance.Spec.ConductorContainerImageURL, 85 | SecurityContext: &corev1.SecurityContext{ 86 | RunAsUser: ptr.To(NovaUserID), 87 | }, 88 | Env: env, 89 | VolumeMounts: volumeMounts, 90 | }, 91 | }, 92 | }, 93 | }, 94 | }, 95 | } 96 | 97 | if instance.Spec.NodeSelector != nil { 98 | job.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector 99 | } 100 | 101 | return job 102 | } 103 | -------------------------------------------------------------------------------- /pkg/nova/volumes.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package nova 18 | 19 | import ( 20 | corev1 "k8s.io/api/core/v1" 21 | ) 22 | 23 | const ( 24 | scriptVolume = "scripts" 25 | configVolume = "config-data" 26 | logVolume = "logs" 27 | ) 28 | 29 | var ( 30 | configMode int32 = 0640 31 | scriptMode int32 = 0740 32 | ) 33 | 34 | func GetConfigVolumeMount() corev1.VolumeMount { 35 | return corev1.VolumeMount{ 36 | Name: configVolume, 37 | MountPath: "/var/lib/openstack/config", 38 | ReadOnly: false, 39 | } 40 | } 41 | 42 | func GetKollaConfigVolumeMount(serviceName string) corev1.VolumeMount { 43 | return corev1.VolumeMount{ 44 | Name: configVolume, 45 | MountPath: "/var/lib/kolla/config_files/config.json", 46 | SubPath: serviceName + "-config.json", 47 | ReadOnly: false, 48 | } 49 | } 50 | 51 | func GetConfigVolume(secretName string) corev1.Volume { 52 | return corev1.Volume{ 53 | Name: configVolume, 54 | VolumeSource: corev1.VolumeSource{ 55 | Secret: &corev1.SecretVolumeSource{ 56 | DefaultMode: &configMode, 57 | SecretName: secretName, 58 | }, 59 | }, 60 | } 61 | } 62 | 63 | func GetLogVolumeMount() corev1.VolumeMount { 64 | return corev1.VolumeMount{ 65 | Name: logVolume, 66 | MountPath: "/var/log/nova", 67 | ReadOnly: false, 68 | } 69 | } 70 | 71 | func GetLogVolume() corev1.Volume { 72 | return corev1.Volume{ 73 | Name: logVolume, 74 | VolumeSource: corev1.VolumeSource{ 75 | EmptyDir: &corev1.EmptyDirVolumeSource{Medium: ""}, 76 | }, 77 | } 78 | } 79 | 80 | func GetScriptVolumeMount() corev1.VolumeMount { 81 | return corev1.VolumeMount{ 82 | Name: scriptVolume, 83 | MountPath: "/var/lib/openstack/bin", 84 | ReadOnly: false, 85 | } 86 | } 87 | 88 | func GetScriptVolume(secretName string) corev1.Volume { 89 | return corev1.Volume{ 90 | Name: scriptVolume, 91 | VolumeSource: corev1.VolumeSource{ 92 | Secret: &corev1.SecretVolumeSource{ 93 | DefaultMode: &scriptMode, 94 | SecretName: secretName, 95 | }, 96 | }, 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /pkg/novaapi/const.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package novaapi 18 | 19 | const ( 20 | //APIServicePort - The port the nova-api service is exposed on 21 | APIServicePort = 8774 22 | // ServiceName - The name of the service exposed to k8s 23 | ServiceName = "nova" 24 | ) 25 | -------------------------------------------------------------------------------- /pkg/novacompute/deployment.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package novacompute 18 | 19 | import ( 20 | common "github.com/openstack-k8s-operators/lib-common/modules/common" 21 | affinity "github.com/openstack-k8s-operators/lib-common/modules/common/affinity" 22 | env "github.com/openstack-k8s-operators/lib-common/modules/common/env" 23 | novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" 24 | "github.com/openstack-k8s-operators/nova-operator/pkg/nova" 25 | 26 | topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1" 27 | appsv1 "k8s.io/api/apps/v1" 28 | corev1 "k8s.io/api/core/v1" 29 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 | "k8s.io/utils/ptr" 31 | ) 32 | 33 | // StatefulSet - returns the StatefulSet definition for the nova-compute service 34 | func StatefulSet( 35 | instance *novav1.NovaCompute, 36 | configHash string, 37 | labels map[string]string, 38 | annotations map[string]string, 39 | topology *topologyv1.Topology, 40 | ) *appsv1.StatefulSet { 41 | // After the first successful startupProbe, livenessProbe takes over 42 | livenessProbe := &corev1.Probe{ 43 | // TODO might need tuning 44 | TimeoutSeconds: 10, 45 | PeriodSeconds: 10, 46 | } 47 | readinessProbe := &corev1.Probe{ 48 | // TODO might need tuning 49 | TimeoutSeconds: 5, 50 | PeriodSeconds: 5, 51 | } 52 | 53 | args := []string{"-c", nova.KollaServiceCommand} 54 | livenessProbe.Exec = &corev1.ExecAction{ 55 | Command: []string{ 56 | "/usr/bin/pgrep", "-r", "DRST", "nova-compute", 57 | }, 58 | } 59 | 60 | readinessProbe.Exec = &corev1.ExecAction{ 61 | Command: []string{ 62 | "/usr/bin/pgrep", "-r", "DRST", "nova-compute", 63 | }, 64 | } 65 | 66 | envVars := map[string]env.Setter{} 67 | envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") 68 | // NOTE(gibi): The statefulset does not use this hash directly. We store it 69 | // in the environment to trigger a Pod restart if any input of the 70 | // statefulset has changed. The k8s will trigger a restart automatically if 71 | // the env changes. 72 | envVars["CONFIG_HASH"] = env.SetValue(configHash) 73 | env := env.MergeEnvs([]corev1.EnvVar{}, envVars) 74 | 75 | // create Volume and VolumeMounts 76 | volumes := []corev1.Volume{ 77 | nova.GetConfigVolume(nova.GetServiceConfigSecretName(instance.Name)), 78 | } 79 | volumeMounts := []corev1.VolumeMount{ 80 | nova.GetConfigVolumeMount(), 81 | nova.GetKollaConfigVolumeMount("nova-compute"), 82 | } 83 | 84 | // add CA cert if defined 85 | if instance.Spec.TLS.CaBundleSecretName != "" { 86 | volumes = append(volumes, instance.Spec.TLS.CreateVolume()) 87 | volumeMounts = append(volumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) 88 | } 89 | 90 | statefulset := &appsv1.StatefulSet{ 91 | ObjectMeta: metav1.ObjectMeta{ 92 | Name: instance.Name, 93 | Namespace: instance.Namespace, 94 | }, 95 | Spec: appsv1.StatefulSetSpec{ 96 | Selector: &metav1.LabelSelector{ 97 | MatchLabels: labels, 98 | }, 99 | PodManagementPolicy: appsv1.ParallelPodManagement, 100 | Replicas: instance.Spec.Replicas, 101 | Template: corev1.PodTemplateSpec{ 102 | ObjectMeta: metav1.ObjectMeta{ 103 | Annotations: annotations, 104 | Labels: labels, 105 | }, 106 | Spec: corev1.PodSpec{ 107 | ServiceAccountName: instance.Spec.ServiceAccount, 108 | Volumes: volumes, 109 | Containers: []corev1.Container{ 110 | { 111 | Name: instance.Name + "-compute", 112 | Command: []string{ 113 | "/bin/bash", 114 | }, 115 | Args: args, 116 | Image: instance.Spec.ContainerImage, 117 | SecurityContext: &corev1.SecurityContext{ 118 | RunAsUser: ptr.To(nova.NovaUserID), 119 | }, 120 | Env: env, 121 | VolumeMounts: volumeMounts, 122 | Resources: instance.Spec.Resources, 123 | ReadinessProbe: readinessProbe, 124 | LivenessProbe: livenessProbe, 125 | }, 126 | }, 127 | }, 128 | }, 129 | }, 130 | } 131 | 132 | if instance.Spec.NodeSelector != nil { 133 | statefulset.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector 134 | } 135 | if topology != nil { 136 | topology.ApplyTo(&statefulset.Spec.Template) 137 | } else { 138 | // If possible two pods of the same service should not 139 | // run on the same worker node. If this is not possible 140 | // the get still created on the same worker node. 141 | statefulset.Spec.Template.Spec.Affinity = affinity.DistributePods( 142 | common.AppSelector, 143 | []string{ 144 | instance.Name, 145 | }, 146 | corev1.LabelHostname, 147 | ) 148 | } 149 | 150 | return statefulset 151 | } 152 | -------------------------------------------------------------------------------- /pkg/novaconductor/dbpurge.go: -------------------------------------------------------------------------------- 1 | package novaconductor 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | batchv1 "k8s.io/api/batch/v1" 8 | corev1 "k8s.io/api/core/v1" 9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 | "k8s.io/utils/ptr" 11 | 12 | "github.com/openstack-k8s-operators/lib-common/modules/common/env" 13 | novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" 14 | "github.com/openstack-k8s-operators/nova-operator/pkg/nova" 15 | ) 16 | 17 | func DBPurgeCronJob( 18 | instance *novav1.NovaConductor, 19 | labels map[string]string, 20 | annotations map[string]string, 21 | ) *batchv1.CronJob { 22 | args := []string{"-c", nova.KollaServiceCommand} 23 | 24 | envVars := map[string]env.Setter{} 25 | envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") 26 | envVars["KOLLA_BOOTSTRAP"] = env.SetValue("true") 27 | 28 | envVars["ARCHIVE_AGE"] = env.SetValue(fmt.Sprintf("%d", *instance.Spec.DBPurge.ArchiveAge)) 29 | envVars["PURGE_AGE"] = env.SetValue(fmt.Sprintf("%d", *instance.Spec.DBPurge.PurgeAge)) 30 | 31 | env := env.MergeEnvs([]corev1.EnvVar{}, envVars) 32 | 33 | volumes := []corev1.Volume{ 34 | nova.GetConfigVolume(nova.GetServiceConfigSecretName(instance.Name)), 35 | nova.GetScriptVolume(nova.GetScriptSecretName(instance.Name)), 36 | } 37 | volumeMounts := []corev1.VolumeMount{ 38 | nova.GetConfigVolumeMount(), 39 | nova.GetScriptVolumeMount(), 40 | nova.GetKollaConfigVolumeMount("nova-conductor-dbpurge"), 41 | } 42 | 43 | // add CA cert if defined 44 | if instance.Spec.TLS.CaBundleSecretName != "" { 45 | volumes = append(volumes, instance.Spec.TLS.CreateVolume()) 46 | volumeMounts = append(volumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) 47 | } 48 | 49 | // we want to hide the fact that the job is created by the conductor 50 | // controller, but we don't have direct access to the Cell CR name, so we 51 | // remove the known conductor suffix from the Conductor CR name. 52 | name := strings.TrimSuffix(instance.Name, "-conductor") + "-db-purge" 53 | 54 | cron := &batchv1.CronJob{ 55 | ObjectMeta: metav1.ObjectMeta{ 56 | Name: name, 57 | Namespace: instance.Namespace, 58 | Labels: labels, 59 | }, 60 | Spec: batchv1.CronJobSpec{ 61 | Schedule: *instance.Spec.DBPurge.Schedule, 62 | ConcurrencyPolicy: batchv1.ForbidConcurrent, 63 | JobTemplate: batchv1.JobTemplateSpec{ 64 | ObjectMeta: metav1.ObjectMeta{ 65 | Labels: labels, 66 | Annotations: annotations, 67 | }, 68 | Spec: batchv1.JobSpec{ 69 | Parallelism: ptr.To[int32](1), 70 | Completions: ptr.To[int32](1), 71 | Template: corev1.PodTemplateSpec{ 72 | Spec: corev1.PodSpec{ 73 | RestartPolicy: corev1.RestartPolicyOnFailure, 74 | ServiceAccountName: instance.Spec.ServiceAccount, 75 | Volumes: volumes, 76 | Containers: []corev1.Container{ 77 | { 78 | Name: "nova-manage", 79 | Command: []string{ 80 | "/bin/bash", 81 | }, 82 | Args: args, 83 | Image: instance.Spec.ContainerImage, 84 | SecurityContext: &corev1.SecurityContext{ 85 | RunAsUser: ptr.To(nova.NovaUserID), 86 | }, 87 | Env: env, 88 | VolumeMounts: volumeMounts, 89 | }, 90 | }, 91 | }, 92 | }, 93 | }, 94 | }, 95 | }, 96 | } 97 | 98 | if instance.Spec.NodeSelector != nil { 99 | cron.Spec.JobTemplate.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector 100 | } 101 | 102 | return cron 103 | } 104 | -------------------------------------------------------------------------------- /pkg/novaconductor/dbsync.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package novaconductor 18 | 19 | import ( 20 | novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" 21 | "github.com/openstack-k8s-operators/nova-operator/pkg/nova" 22 | 23 | env "github.com/openstack-k8s-operators/lib-common/modules/common/env" 24 | 25 | batchv1 "k8s.io/api/batch/v1" 26 | corev1 "k8s.io/api/core/v1" 27 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 | "k8s.io/utils/ptr" 29 | ) 30 | 31 | // CellDBSyncJob - define a batchv1.Job to be run to apply the cel DB schema 32 | func CellDBSyncJob( 33 | instance *novav1.NovaConductor, 34 | labels map[string]string, 35 | annotations map[string]string, 36 | ) *batchv1.Job { 37 | args := []string{"-c", nova.KollaServiceCommand} 38 | 39 | envVars := map[string]env.Setter{} 40 | envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") 41 | envVars["KOLLA_BOOTSTRAP"] = env.SetValue("true") 42 | 43 | envVars["CELL_NAME"] = env.SetValue(instance.Spec.CellName) 44 | 45 | env := env.MergeEnvs([]corev1.EnvVar{}, envVars) 46 | 47 | // create Volume and VolumeMounts 48 | volumes := []corev1.Volume{ 49 | nova.GetConfigVolume(nova.GetServiceConfigSecretName(instance.Name)), 50 | nova.GetScriptVolume(nova.GetScriptSecretName(instance.Name)), 51 | } 52 | volumeMounts := []corev1.VolumeMount{ 53 | nova.GetConfigVolumeMount(), 54 | nova.GetScriptVolumeMount(), 55 | nova.GetKollaConfigVolumeMount("nova-conductor-dbsync"), 56 | } 57 | 58 | // add CA cert if defined 59 | if instance.Spec.TLS.CaBundleSecretName != "" { 60 | volumes = append(volumes, instance.Spec.TLS.CreateVolume()) 61 | volumeMounts = append(volumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) 62 | } 63 | 64 | job := &batchv1.Job{ 65 | ObjectMeta: metav1.ObjectMeta{ 66 | Name: instance.Name + "-db-sync", 67 | Namespace: instance.Namespace, 68 | Annotations: annotations, 69 | Labels: labels, 70 | }, 71 | Spec: batchv1.JobSpec{ 72 | Template: corev1.PodTemplateSpec{ 73 | Spec: corev1.PodSpec{ 74 | RestartPolicy: corev1.RestartPolicyOnFailure, 75 | ServiceAccountName: instance.Spec.ServiceAccount, 76 | Volumes: volumes, 77 | Containers: []corev1.Container{ 78 | { 79 | Name: instance.Name + "-db-sync", 80 | Command: []string{ 81 | "/bin/bash", 82 | }, 83 | Args: args, 84 | Image: instance.Spec.ContainerImage, 85 | SecurityContext: &corev1.SecurityContext{ 86 | RunAsUser: ptr.To(nova.NovaUserID), 87 | }, 88 | Env: env, 89 | VolumeMounts: volumeMounts, 90 | }, 91 | }, 92 | }, 93 | }, 94 | }, 95 | } 96 | 97 | if instance.Spec.NodeSelector != nil { 98 | job.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector 99 | } 100 | 101 | return job 102 | } 103 | -------------------------------------------------------------------------------- /pkg/novaconductor/deployment.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package novaconductor 18 | 19 | import ( 20 | topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1" 21 | common "github.com/openstack-k8s-operators/lib-common/modules/common" 22 | affinity "github.com/openstack-k8s-operators/lib-common/modules/common/affinity" 23 | env "github.com/openstack-k8s-operators/lib-common/modules/common/env" 24 | novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" 25 | "github.com/openstack-k8s-operators/nova-operator/pkg/nova" 26 | 27 | appsv1 "k8s.io/api/apps/v1" 28 | corev1 "k8s.io/api/core/v1" 29 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 | "k8s.io/utils/ptr" 31 | ) 32 | 33 | // StatefulSet - returns the StatefulSet definition for the nova-api service 34 | func StatefulSet( 35 | instance *novav1.NovaConductor, 36 | configHash string, 37 | labels map[string]string, 38 | annotations map[string]string, 39 | topology *topologyv1.Topology, 40 | ) *appsv1.StatefulSet { 41 | livenessProbe := &corev1.Probe{ 42 | // TODO might need tuning 43 | TimeoutSeconds: 5, 44 | PeriodSeconds: 3, 45 | InitialDelaySeconds: 3, 46 | } 47 | readinessProbe := &corev1.Probe{ 48 | // TODO might need tuning 49 | TimeoutSeconds: 5, 50 | PeriodSeconds: 5, 51 | InitialDelaySeconds: 5, 52 | } 53 | 54 | args := []string{"-c", nova.KollaServiceCommand} 55 | 56 | // TODO(gibi): replace this with a proper health check once 57 | // https://review.opendev.org/q/topic:per-process-healthchecks merges. 58 | // NOTE(gibi): -r DRST means we consider nova-conductor processes 59 | // healthy if they are not in zombie state. 60 | livenessProbe.Exec = &corev1.ExecAction{ 61 | Command: []string{ 62 | "/usr/bin/pgrep", "-r", "DRST", "nova-conductor", 63 | }, 64 | } 65 | 66 | readinessProbe.Exec = &corev1.ExecAction{ 67 | Command: []string{ 68 | "/usr/bin/pgrep", "-r", "DRST", "nova-conductor", 69 | }, 70 | } 71 | 72 | envVars := map[string]env.Setter{} 73 | envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") 74 | // NOTE(gibi): The statefulset does not use this hash directly. We store it 75 | // in the environment to trigger a Pod restart if any input of the 76 | // statefulset has changed. The k8s will trigger a restart automatically if 77 | // the env changes. 78 | envVars["CONFIG_HASH"] = env.SetValue(configHash) 79 | env := env.MergeEnvs([]corev1.EnvVar{}, envVars) 80 | 81 | // create Volume and VolumeMounts 82 | volumes := []corev1.Volume{ 83 | nova.GetConfigVolume(nova.GetServiceConfigSecretName(instance.Name)), 84 | } 85 | volumeMounts := []corev1.VolumeMount{ 86 | nova.GetConfigVolumeMount(), 87 | nova.GetKollaConfigVolumeMount("nova-conductor"), 88 | } 89 | 90 | // add CA cert if defined 91 | if instance.Spec.TLS.CaBundleSecretName != "" { 92 | volumes = append(volumes, instance.Spec.TLS.CreateVolume()) 93 | volumeMounts = append(volumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) 94 | } 95 | 96 | statefulset := &appsv1.StatefulSet{ 97 | ObjectMeta: metav1.ObjectMeta{ 98 | Name: instance.Name, 99 | Namespace: instance.Namespace, 100 | }, 101 | Spec: appsv1.StatefulSetSpec{ 102 | Selector: &metav1.LabelSelector{ 103 | MatchLabels: labels, 104 | }, 105 | PodManagementPolicy: appsv1.ParallelPodManagement, 106 | Replicas: instance.Spec.Replicas, 107 | Template: corev1.PodTemplateSpec{ 108 | ObjectMeta: metav1.ObjectMeta{ 109 | Annotations: annotations, 110 | Labels: labels, 111 | }, 112 | Spec: corev1.PodSpec{ 113 | ServiceAccountName: instance.Spec.ServiceAccount, 114 | Volumes: volumes, 115 | Containers: []corev1.Container{ 116 | { 117 | Name: instance.Name + "-conductor", 118 | Command: []string{ 119 | "/bin/bash", 120 | }, 121 | Args: args, 122 | Image: instance.Spec.ContainerImage, 123 | SecurityContext: &corev1.SecurityContext{ 124 | RunAsUser: ptr.To(nova.NovaUserID), 125 | }, 126 | Env: env, 127 | VolumeMounts: volumeMounts, 128 | Resources: instance.Spec.Resources, 129 | ReadinessProbe: readinessProbe, 130 | LivenessProbe: livenessProbe, 131 | }, 132 | }, 133 | }, 134 | }, 135 | }, 136 | } 137 | 138 | if instance.Spec.NodeSelector != nil { 139 | statefulset.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector 140 | } 141 | if topology != nil { 142 | topology.ApplyTo(&statefulset.Spec.Template) 143 | } else { 144 | // If possible two pods of the same service should not 145 | // run on the same worker node. If this is not possible 146 | // the get still created on the same worker node. 147 | statefulset.Spec.Template.Spec.Affinity = affinity.DistributePods( 148 | common.AppSelector, 149 | []string{ 150 | instance.Name, 151 | }, 152 | corev1.LabelHostname, 153 | ) 154 | } 155 | 156 | return statefulset 157 | } 158 | -------------------------------------------------------------------------------- /pkg/novametadata/const.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package novametadata 18 | 19 | const ( 20 | //APIServicePort - The port the nova-api service is exposed on 21 | APIServicePort = 8775 22 | // ServiceName - The name of the service exposed to k8s 23 | ServiceName = "nova-metadata" 24 | ) 25 | -------------------------------------------------------------------------------- /pkg/novascheduler/deployment.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package novascheduler 18 | 19 | import ( 20 | common "github.com/openstack-k8s-operators/lib-common/modules/common" 21 | affinity "github.com/openstack-k8s-operators/lib-common/modules/common/affinity" 22 | env "github.com/openstack-k8s-operators/lib-common/modules/common/env" 23 | novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" 24 | "github.com/openstack-k8s-operators/nova-operator/pkg/nova" 25 | 26 | topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1" 27 | appsv1 "k8s.io/api/apps/v1" 28 | corev1 "k8s.io/api/core/v1" 29 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 | "k8s.io/utils/ptr" 31 | ) 32 | 33 | // StatefulSet - returns the StatefulSet definition for the nova-scheduler service 34 | func StatefulSet( 35 | instance *novav1.NovaScheduler, 36 | configHash string, 37 | labels map[string]string, 38 | annotations map[string]string, 39 | topology *topologyv1.Topology, 40 | ) *appsv1.StatefulSet { 41 | // This allows the pod to start up slowly. The pod will only be killed 42 | // if it does not succeed a probe in 60 seconds. 43 | startupProbe := &corev1.Probe{ 44 | FailureThreshold: 6, 45 | PeriodSeconds: 10, 46 | } 47 | // After the first successful startupProbe, livenessProbe takes over 48 | livenessProbe := &corev1.Probe{ 49 | // TODO might need tuning 50 | TimeoutSeconds: 10, 51 | PeriodSeconds: 10, 52 | } 53 | readinessProbe := &corev1.Probe{ 54 | // TODO might need tuning 55 | TimeoutSeconds: 5, 56 | PeriodSeconds: 5, 57 | } 58 | 59 | args := []string{"-c", nova.KollaServiceCommand} 60 | livenessProbe.Exec = &corev1.ExecAction{ 61 | Command: []string{ 62 | "/usr/bin/pgrep", "-r", "DRST", "nova-scheduler", 63 | }, 64 | } 65 | readinessProbe.Exec = &corev1.ExecAction{ 66 | Command: []string{ 67 | "/usr/bin/pgrep", "-r", "DRST", "nova-scheduler", 68 | }, 69 | } 70 | startupProbe.Exec = &corev1.ExecAction{ 71 | Command: []string{ 72 | "/usr/bin/pgrep", "-r", "DRST", "nova-scheduler", 73 | }, 74 | } 75 | 76 | envVars := map[string]env.Setter{} 77 | envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") 78 | // NOTE(gibi): The statefulset does not use this hash directly. We store it 79 | // in the environment to trigger a Pod restart if any input of the 80 | // statefulset has changed. The k8s will trigger a restart automatically if 81 | // the env changes. 82 | envVars["CONFIG_HASH"] = env.SetValue(configHash) 83 | env := env.MergeEnvs([]corev1.EnvVar{}, envVars) 84 | 85 | // create Volume and VolumeMounts 86 | volumes := []corev1.Volume{ 87 | nova.GetConfigVolume(nova.GetServiceConfigSecretName(instance.Name)), 88 | } 89 | volumeMounts := []corev1.VolumeMount{ 90 | nova.GetConfigVolumeMount(), 91 | nova.GetKollaConfigVolumeMount("nova-scheduler"), 92 | } 93 | 94 | // add CA cert if defined 95 | if instance.Spec.TLS.CaBundleSecretName != "" { 96 | volumes = append(volumes, instance.Spec.TLS.CreateVolume()) 97 | volumeMounts = append(volumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) 98 | } 99 | 100 | statefulset := &appsv1.StatefulSet{ 101 | ObjectMeta: metav1.ObjectMeta{ 102 | Name: instance.Name, 103 | Namespace: instance.Namespace, 104 | }, 105 | Spec: appsv1.StatefulSetSpec{ 106 | Selector: &metav1.LabelSelector{ 107 | MatchLabels: labels, 108 | }, 109 | Replicas: instance.Spec.Replicas, 110 | PodManagementPolicy: appsv1.ParallelPodManagement, 111 | Template: corev1.PodTemplateSpec{ 112 | ObjectMeta: metav1.ObjectMeta{ 113 | Annotations: annotations, 114 | Labels: labels, 115 | }, 116 | Spec: corev1.PodSpec{ 117 | ServiceAccountName: instance.Spec.ServiceAccount, 118 | Volumes: volumes, 119 | Containers: []corev1.Container{ 120 | { 121 | Name: instance.Name + "-scheduler", 122 | Command: []string{ 123 | "/bin/bash", 124 | }, 125 | Args: args, 126 | Image: instance.Spec.ContainerImage, 127 | SecurityContext: &corev1.SecurityContext{ 128 | RunAsUser: ptr.To(nova.NovaUserID), 129 | }, 130 | Env: env, 131 | VolumeMounts: volumeMounts, 132 | Resources: instance.Spec.Resources, 133 | StartupProbe: startupProbe, 134 | ReadinessProbe: readinessProbe, 135 | LivenessProbe: livenessProbe, 136 | }, 137 | }, 138 | }, 139 | }, 140 | }, 141 | } 142 | 143 | if instance.Spec.NodeSelector != nil { 144 | statefulset.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector 145 | } 146 | 147 | if topology != nil { 148 | topology.ApplyTo(&statefulset.Spec.Template) 149 | } else { 150 | // If possible two pods of the same service should not 151 | // run on the same worker node. If this is not possible 152 | // the get still created on the same worker node. 153 | statefulset.Spec.Template.Spec.Affinity = affinity.DistributePods( 154 | common.AppSelector, 155 | []string{ 156 | instance.Name, 157 | }, 158 | corev1.LabelHostname, 159 | ) 160 | } 161 | 162 | return statefulset 163 | } 164 | -------------------------------------------------------------------------------- /pkg/novncproxy/const.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package novncproxy 18 | 19 | const ( 20 | //NoVNCProxyPort - The port the nova-noVNCProxyPort service is exposed on 21 | NoVNCProxyPort = 6080 22 | // ServiceName - The name of the service exposed to k8s 23 | ServiceName = "nova-novncproxy" 24 | Host = "::0" 25 | VencryptName = "vencrypt" 26 | ) 27 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "github>openstack-k8s-operators/renovate-config:default.json5" 4 | ], 5 | "baseBranches": ["main"], 6 | "useBaseBranchConfig": "merge", 7 | "packageRules": [ 8 | { 9 | "matchPackageNames": ["github.com/openstack-k8s-operators/nova-operator/api"], 10 | "enabled": false 11 | } 12 | ], 13 | "postUpgradeTasks": { 14 | "commands": ["make gowork", "make tidy", "make manifests generate"], 15 | "fileFilters": ["**/go.mod", "**/go.sum", "**/*.go", "**/*.yaml"], 16 | "executionMode": "update" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /templates/firewall.goyaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Generated via nova-operator 3 | - rule_name: 005 Allow vnc access on all networks. 4 | rule: 5 | proto: tcp 6 | dport: 7 | - "5900-6923" {{/* use same port range as tripleo */}} 8 | -------------------------------------------------------------------------------- /templates/neutron-metadata.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | nova_metadata_host = {{.nova_metadata_host}} 3 | nova_metadata_port = {{.nova_metadata_port}} 4 | nova_metadata_protocol = {{.nova_metadata_protocol}} 5 | metadata_proxy_shared_secret = {{.metadata_proxy_shared_secret}} 6 | -------------------------------------------------------------------------------- /templates/nova-blank.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack-k8s-operators/nova-operator/aa8325f052971ce543d3879d5582d0b565e88745/templates/nova-blank.conf -------------------------------------------------------------------------------- /templates/nova-manage/bin/delete_cell.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2023. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -xe 17 | 18 | export CELL_NAME=${CELL_NAME:?"Please specify a CELL_NAME variable."} 19 | 20 | # NOTE(gibi): nova-manage should be enhanced upstream to get rid of this 21 | # uglyness 22 | # Note the "|" around the CELL_NAME, that is needed as a single line from 23 | # nova-manage cell_v2 cell_list can match to multiple cells if the cell name 24 | # is part of the line, e.g. as the user name of the DB URL 25 | cell_uuid=$(nova-manage cell_v2 list_cells | tr ' ' '|' | tr --squeeze-repeats '|' | grep -e "^|$CELL_NAME|" | cut -d '|' -f 3) 26 | 27 | nova-manage cell_v2 delete_cell --cell_uuid "${cell_uuid}" 28 | -------------------------------------------------------------------------------- /templates/nova-manage/bin/ensure_cell_mapping.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2023. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -xe 17 | 18 | export CELL_NAME=${CELL_NAME:?"Please specify a CELL_NAME variable."} 19 | 20 | # NOTE(gibi): nova-manage should be enhanced upstream to get rid of this 21 | # uglyness 22 | # Note the "|" around the CELL_NAME, that is needed as a single line from 23 | # nova-manage cell_v2 cell_list can match to multiple cells if the cell name 24 | # is part of the line, e.g. as the user name of the DB URL 25 | cell_uuid=$(nova-manage cell_v2 list_cells | tr ' ' '|' | tr --squeeze-repeats '|' | grep -e "^|$CELL_NAME|" | cut -d '|' -f 3) 26 | 27 | if [ -z "${cell_uuid}" ]; then 28 | if [ "${CELL_NAME}" = "cell0" ]; then 29 | nova-manage cell_v2 map_cell0 30 | # NOTE(gibi): cell_v2 map_cell0 command above blindly appended _cell0 to the end 31 | # of the DB URL found in the configuration and ended up with nova_cell0_cell0 which 32 | # is invalid. This is an nova upstream bug to fix. But we can workaround it as 33 | # update_cell does have the corret behavior when collecting the cell mapping information 34 | # from the nova.conf 35 | nova-manage cell_v2 update_cell --cell_uuid 00000000-0000-0000-0000-000000000000 36 | else 37 | nova-manage cell_v2 create_cell --name "${CELL_NAME}" --verbose 38 | fi 39 | 40 | else 41 | nova-manage cell_v2 update_cell --cell_uuid "${cell_uuid}" 42 | fi 43 | -------------------------------------------------------------------------------- /templates/nova-manage/bin/host_discover.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2023. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -xe 17 | 18 | nova-manage cell_v2 discover_hosts --by-service --verbose 19 | -------------------------------------------------------------------------------- /templates/nova-manage/config/cell-delete-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/bin/delete_cell.sh", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/openstack/config/nova-blank.conf", 6 | "dest": "/etc/nova/nova.conf", 7 | "owner": "nova", 8 | "perm": "0600" 9 | }, 10 | { 11 | "source": "/var/lib/openstack/config/01-nova.conf", 12 | "dest": "/etc/nova/nova.conf.d/01-nova.conf", 13 | "owner": "nova", 14 | "perm": "0600" 15 | }, 16 | { 17 | "source": "/var/lib/openstack/bin/delete_cell.sh", 18 | "dest": "/bin/", 19 | "owner": "nova", 20 | "perm": "0700" 21 | }, 22 | { 23 | "source": "/var/lib/openstack/config/my.cnf", 24 | "dest": "/etc/my.cnf", 25 | "owner": "nova", 26 | "perm": "0644" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /templates/nova-manage/config/cell-mapping-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/bin/ensure_cell_mapping.sh", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/openstack/config/nova-blank.conf", 6 | "dest": "/etc/nova/nova.conf", 7 | "owner": "nova", 8 | "perm": "0600" 9 | }, 10 | { 11 | "source": "/var/lib/openstack/config/01-nova.conf", 12 | "dest": "/etc/nova/nova.conf.d/01-nova.conf", 13 | "owner": "nova", 14 | "perm": "0600" 15 | }, 16 | { 17 | "source": "/var/lib/openstack/bin/ensure_cell_mapping.sh", 18 | "dest": "/bin/", 19 | "owner": "nova", 20 | "perm": "0700" 21 | }, 22 | { 23 | "source": "/var/lib/openstack/config/my.cnf", 24 | "dest": "/etc/my.cnf", 25 | "owner": "nova", 26 | "perm": "0644" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /templates/nova-manage/config/host-discover-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/bin/host_discover.sh", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/openstack/config/nova-blank.conf", 6 | "dest": "/etc/nova/nova.conf", 7 | "owner": "nova", 8 | "perm": "0600" 9 | }, 10 | { 11 | "source": "/var/lib/openstack/config/01-nova.conf", 12 | "dest": "/etc/nova/nova.conf.d/01-nova.conf", 13 | "owner": "nova", 14 | "perm": "0600" 15 | }, 16 | { 17 | "source": "/var/lib/openstack/bin/host_discover.sh", 18 | "dest": "/bin/", 19 | "owner": "nova", 20 | "perm": "0700" 21 | }, 22 | { 23 | "source": "/var/lib/openstack/config/my.cnf", 24 | "dest": "/etc/my.cnf", 25 | "owner": "nova", 26 | "perm": "0644" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /templates/novaapi/bin/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack-k8s-operators/nova-operator/aa8325f052971ce543d3879d5582d0b565e88745/templates/novaapi/bin/.keep -------------------------------------------------------------------------------- /templates/novaapi/config/httpd.conf: -------------------------------------------------------------------------------- 1 | ServerTokens Prod 2 | ServerSignature Off 3 | TraceEnable Off 4 | PidFile run/httpd.pid 5 | ServerRoot "/etc/httpd" 6 | ServerName "localhost.localdomain" 7 | 8 | User apache 9 | Group apache 10 | 11 | Listen 8774 12 | 13 | TypesConfig /etc/mime.types 14 | 15 | Include conf.modules.d/*.conf 16 | {{- if .tls }} 17 | ## TODO: fix default ssl.conf to comment not available tls certs. Than we can remove this condition 18 | Include conf.d/*.conf 19 | {{- end }} 20 | 21 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined 22 | LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" proxy 23 | 24 | SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded 25 | ErrorLog /dev/stderr 26 | TransferLog /dev/stdout 27 | CustomLog /dev/stdout combined env=!forwarded 28 | CustomLog /dev/stdout proxy env=forwarded 29 | ## set default apache log level to info from warning 30 | LogLevel info 31 | 32 | {{ range $endpt, $vhost := .VHosts }} 33 | # {{ $endpt }} vhost {{ $vhost.ServerName }} configuration 34 | 35 | = 2.4> 36 | ErrorLogFormat "%M" 37 | 38 | SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded 39 | 40 | ServerName {{ $vhost.ServerName }} 41 | TimeOut {{ $vhost.TimeOut }} 42 | 43 | ## Vhost docroot 44 | DocumentRoot "/var/www/cgi-bin" 45 | 46 | ## Directories, there should at least be a declaration for /var/www/cgi-bin 47 | 48 | Options -Indexes +FollowSymLinks +MultiViews 49 | AllowOverride None 50 | Require all granted 51 | 52 | 53 | ## Logging 54 | ErrorLog /dev/stdout 55 | ServerSignature Off 56 | CustomLog /dev/stdout combined env=!forwarded 57 | CustomLog /dev/stdout proxy env=forwarded 58 | ## set nova vhost log level to debug 59 | LogLevel debug 60 | 61 | {{- if $vhost.tls }} 62 | SetEnvIf X-Forwarded-Proto https HTTPS=1 63 | 64 | ## SSL directives 65 | SSLEngine on 66 | SSLCertificateFile "{{ $vhost.SSLCertificateFile }}" 67 | SSLCertificateKeyFile "{{ $vhost.SSLCertificateKeyFile }}" 68 | {{- end }} 69 | 70 | ## WSGI configuration 71 | WSGIProcessGroup {{ $endpt }} 72 | #WSGIProcessGroup nova-api 73 | WSGIApplicationGroup %{GLOBAL} 74 | WSGIPassAuthorization On 75 | ## In general we want nova-api to scale via k8s replicas but we need 76 | ## two processes per replica to always has a room for a healthecheck query 77 | WSGIDaemonProcess {{ $endpt }} display-name={{ $endpt }} processes=2 threads=1 user=nova group=nova 78 | WSGIScriptAlias / "/usr/bin/nova-api-wsgi" 79 | 80 | {{ end }} 81 | 82 | Alias /nova-api /usr/bin/nova-api-wsgi 83 | 84 | SetHandler wsgi-script 85 | Options +ExecCGI 86 | WSGIProcessGroup public 87 | WSGIApplicationGroup %{GLOBAL} 88 | WSGIPassAuthorization On 89 | 90 | -------------------------------------------------------------------------------- /templates/novaapi/config/nova-api-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/usr/sbin/httpd -DFOREGROUND", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/openstack/config/nova-blank.conf", 6 | "dest": "/etc/nova/nova.conf", 7 | "owner": "nova", 8 | "perm": "0600" 9 | }, 10 | { 11 | "source": "/var/lib/openstack/config/01-nova.conf", 12 | "dest": "/etc/nova/nova.conf.d/01-nova.conf", 13 | "owner": "nova", 14 | "perm": "0600" 15 | }, 16 | { 17 | "source": "/var/lib/openstack/config/02-nova-override.conf", 18 | "dest": "/etc/nova/nova.conf.d/02-nova-override.conf", 19 | "owner": "nova", 20 | "perm": "0600", 21 | "optional": true 22 | }, 23 | { 24 | "source": "/var/lib/openstack/config/httpd.conf", 25 | "dest": "/etc/httpd/conf/httpd.conf", 26 | "owner": "apache", 27 | "perm": "0644" 28 | }, 29 | { 30 | "source": "/var/lib/openstack/config/ssl.conf", 31 | "dest": "/etc/httpd/conf.d/ssl.conf", 32 | "owner": "apache", 33 | "perm": "0444" 34 | }, 35 | { 36 | "source": "/var/lib/config-data/tls/certs/*", 37 | "dest": "/etc/pki/tls/certs/", 38 | "owner": "nova", 39 | "perm": "0640", 40 | "optional": true, 41 | "merge": true 42 | }, 43 | { 44 | "source": "/var/lib/config-data/tls/private/*", 45 | "dest": "/etc/pki/tls/private/", 46 | "owner": "nova", 47 | "perm": "0600", 48 | "optional": true, 49 | "merge": true 50 | }, 51 | { 52 | "source": "/var/lib/openstack/config/policy.yaml", 53 | "dest": "/etc/nova/policy.yaml", 54 | "owner": "nova", 55 | "perm": "0600", 56 | "optional": true 57 | }, 58 | { 59 | "source": "/var/lib/openstack/config/api-paste.ini", 60 | "dest": "/etc/nova/api-paste.ini", 61 | "owner": "nova", 62 | "perm": "0600", 63 | "optional": true 64 | }, 65 | { 66 | "source": "/var/lib/openstack/config/my.cnf", 67 | "dest": "/etc/my.cnf", 68 | "owner": "nova", 69 | "perm": "0644" 70 | } 71 | ], 72 | "permissions": [ 73 | { 74 | "path": "/var/log/nova", 75 | "owner": "nova:apache", 76 | "recurse": true 77 | }, 78 | { 79 | "path": "/etc/httpd/run/", 80 | "owner": "nova:apache", 81 | "recurse": true 82 | } 83 | ] 84 | } 85 | -------------------------------------------------------------------------------- /templates/novaapi/config/ssl.conf: -------------------------------------------------------------------------------- 1 | 2 | SSLRandomSeed startup builtin 3 | SSLRandomSeed startup file:/dev/urandom 512 4 | SSLRandomSeed connect builtin 5 | SSLRandomSeed connect file:/dev/urandom 512 6 | 7 | AddType application/x-x509-ca-cert .crt 8 | AddType application/x-pkcs7-crl .crl 9 | 10 | SSLPassPhraseDialog builtin 11 | SSLSessionCache "shmcb:/var/cache/mod_ssl/scache(512000)" 12 | SSLSessionCacheTimeout 300 13 | Mutex default 14 | SSLCryptoDevice builtin 15 | SSLHonorCipherOrder On 16 | SSLUseStapling Off 17 | SSLStaplingCache "shmcb:/run/httpd/ssl_stapling(32768)" 18 | SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!RC4:!3DES 19 | SSLProtocol all -SSLv2 -SSLv3 -TLSv1 20 | SSLOptions StdEnvVars 21 | 22 | -------------------------------------------------------------------------------- /templates/novacompute/bin/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack-k8s-operators/nova-operator/aa8325f052971ce543d3879d5582d0b565e88745/templates/novacompute/bin/.keep -------------------------------------------------------------------------------- /templates/novacompute/config/nova-compute-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/usr/bin/nova-compute", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/openstack/config/nova-blank.conf", 6 | "dest": "/etc/nova/nova.conf", 7 | "owner": "nova", 8 | "perm": "0600" 9 | }, 10 | { 11 | "source": "/var/lib/openstack/config/01-nova.conf", 12 | "dest": "/etc/nova/nova.conf.d/01-nova.conf", 13 | "owner": "nova", 14 | "perm": "0600" 15 | }, 16 | { 17 | "source": "/var/lib/openstack/config/02-nova-override.conf", 18 | "dest": "/etc/nova/nova.conf.d/02-nova-override.conf", 19 | "owner": "nova", 20 | "perm": "0600", 21 | "optional": true 22 | }, 23 | { 24 | "source": "/var/lib/openstack/config/provider*.yaml", 25 | "dest": "/etc/nova/provider_config/", 26 | "owner": "nova", 27 | "perm": "0600", 28 | "optional": true 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /templates/novaconductor/bin/dbpurge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -x 17 | export ARCHIVE_AGE=${ARCHIVE_AGE:?"Please specify ARCHIVE_AGE variable."} 18 | export PURGE_AGE=${PURGE_AGE:?"Please specify PURGE_AGE variable."} 19 | archive_before=$(date --date="${ARCHIVE_AGE} day ago" +%Y-%m-%d) 20 | purge_before=$(date --date="${PURGE_AGE} day ago" +%Y-%m-%d) 21 | 22 | nova-manage db archive_deleted_rows --verbose --until-complete --task-log --before "${archive_before}" 23 | ret=$? 24 | # 0 means no error and nothing is archived 25 | # 1 means no error and someting is archived 26 | if [ $ret -gt "1" ]; then 27 | exit $ret 28 | fi 29 | 30 | nova-manage db purge --verbose --before "${purge_before}" 31 | ret=$? 32 | # 0 means no error and something is deleted 33 | # 3 means no error and nothing is deleted 34 | if [[ $ret -eq 1 || $ret -eq 2 || $ret -gt 3 ]]; then 35 | exit $ret 36 | fi 37 | 38 | exit 0 39 | -------------------------------------------------------------------------------- /templates/novaconductor/bin/dbsync.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2023. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -ex 17 | 18 | export CELL_NAME=${CELL_NAME:?"Please specify a CELL_NAME variable."} 19 | 20 | if [ "${CELL_NAME}" = "cell0" ]; then 21 | nova-manage api_db sync 22 | fi 23 | 24 | nova-manage db sync --local_cell 25 | -------------------------------------------------------------------------------- /templates/novaconductor/config/nova-conductor-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/usr/bin/nova-conductor", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/openstack/config/nova-blank.conf", 6 | "dest": "/etc/nova/nova.conf", 7 | "owner": "nova", 8 | "perm": "0600" 9 | }, 10 | { 11 | "source": "/var/lib/openstack/config/01-nova.conf", 12 | "dest": "/etc/nova/nova.conf.d/01-nova.conf", 13 | "owner": "nova", 14 | "perm": "0600" 15 | }, 16 | { 17 | "source": "/var/lib/openstack/config/02-nova-override.conf", 18 | "dest": "/etc/nova/nova.conf.d/02-nova-override.conf", 19 | "owner": "nova", 20 | "perm": "0600", 21 | "optional": true 22 | }, 23 | { 24 | "source": "/var/lib/openstack/config/my.cnf", 25 | "dest": "/etc/my.cnf", 26 | "owner": "nova", 27 | "perm": "0644" 28 | } 29 | ], 30 | "permissions": [ 31 | { 32 | "path": "/var/log/nova", 33 | "owner": "nova:nova", 34 | "recurse": true 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /templates/novaconductor/config/nova-conductor-dbpurge-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/bin/dbpurge.sh", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/openstack/config/nova-blank.conf", 6 | "dest": "/etc/nova/nova.conf", 7 | "owner": "nova", 8 | "perm": "0600" 9 | }, 10 | { 11 | "source": "/var/lib/openstack/config/01-nova.conf", 12 | "dest": "/etc/nova/nova.conf.d/01-nova.conf", 13 | "owner": "nova", 14 | "perm": "0600" 15 | }, 16 | { 17 | "source": "/var/lib/openstack/config/02-nova-override.conf", 18 | "dest": "/etc/nova/nova.conf.d/02-nova-override.conf", 19 | "owner": "nova", 20 | "perm": "0600", 21 | "optional": true 22 | }, 23 | { 24 | "source": "/var/lib/openstack/bin/dbpurge.sh", 25 | "dest": "/bin/", 26 | "owner": "nova", 27 | "perm": "0700" 28 | } 29 | ], 30 | "permissions": [ 31 | { 32 | "path": "/var/log/nova", 33 | "owner": "nova:nova", 34 | "recurse": true 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /templates/novaconductor/config/nova-conductor-dbsync-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/bin/dbsync.sh", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/openstack/config/nova-blank.conf", 6 | "dest": "/etc/nova/nova.conf", 7 | "owner": "nova", 8 | "perm": "0600" 9 | }, 10 | { 11 | "source": "/var/lib/openstack/config/01-nova.conf", 12 | "dest": "/etc/nova/nova.conf.d/01-nova.conf", 13 | "owner": "nova", 14 | "perm": "0600" 15 | }, 16 | { 17 | "source": "/var/lib/openstack/config/02-nova-override.conf", 18 | "dest": "/etc/nova/nova.conf.d/02-nova-override.conf", 19 | "owner": "nova", 20 | "perm": "0600", 21 | "optional": true 22 | }, 23 | { 24 | "source": "/var/lib/openstack/bin/dbsync.sh", 25 | "dest": "/bin/", 26 | "owner": "nova", 27 | "perm": "0700" 28 | }, 29 | { 30 | "source": "/var/lib/openstack/config/my.cnf", 31 | "dest": "/etc/my.cnf", 32 | "owner": "nova", 33 | "perm": "0644" 34 | } 35 | ], 36 | "permissions": [ 37 | { 38 | "path": "/var/log/nova", 39 | "owner": "nova:nova", 40 | "recurse": true 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /templates/novametadata/bin/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack-k8s-operators/nova-operator/aa8325f052971ce543d3879d5582d0b565e88745/templates/novametadata/bin/.keep -------------------------------------------------------------------------------- /templates/novametadata/config/httpd.conf: -------------------------------------------------------------------------------- 1 | ServerTokens Prod 2 | ServerSignature Off 3 | TraceEnable Off 4 | PidFile run/httpd.pid 5 | ServerRoot "/etc/httpd" 6 | ServerName "localhost.localdomain" 7 | 8 | User apache 9 | Group apache 10 | 11 | Listen 8775 12 | 13 | TypesConfig /etc/mime.types 14 | 15 | Include conf.modules.d/*.conf 16 | {{- if .tls }} 17 | ## TODO: fix default ssl.conf to comment not available tls certs. Than we can remove this condition 18 | Include conf.d/*.conf 19 | {{- end }} 20 | 21 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined 22 | LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" proxy 23 | 24 | SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded 25 | ErrorLog /dev/stderr 26 | TransferLog /dev/stdout 27 | CustomLog /dev/stdout combined env=!forwarded 28 | CustomLog /dev/stdout proxy env=forwarded 29 | ## set default apache log level to info from warning 30 | LogLevel info 31 | 32 | 33 | = 2.4> 34 | ErrorLogFormat "%M" 35 | 36 | SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded 37 | 38 | ServerName {{ .ServerName }} 39 | TimeOut {{ .TimeOut }} 40 | 41 | ErrorLog /dev/stdout 42 | CustomLog /dev/stdout combined env=!forwarded 43 | CustomLog /dev/stdout proxy env=forwarded 44 | ## set nova vhost log level to debug 45 | LogLevel debug 46 | 47 | {{- if .tls }} 48 | SetEnvIf X-Forwarded-Proto https HTTPS=1 49 | 50 | ## SSL directives 51 | SSLEngine on 52 | SSLCertificateFile "{{ .SSLCertificateFile }}" 53 | SSLCertificateKeyFile "{{ .SSLCertificateKeyFile }}" 54 | {{- end }} 55 | 56 | ## WSGI configuration 57 | WSGIProcessGroup nova-metadata 58 | WSGIApplicationGroup %{GLOBAL} 59 | WSGIPassAuthorization On 60 | ## In general we want nova-metadata to scale via k8s replicas but we need 61 | ## two processes per replica to always has a room for a healthecheck query 62 | WSGIDaemonProcess nova-metadata processes=2 threads=1 user=nova group=nova display-name=nova-metadata-api 63 | WSGIScriptAlias / /usr/bin/nova-metadata-wsgi 64 | 65 | 66 | Alias /nova-metadata /usr/bin/nova-metadata-wsgi 67 | 68 | SetHandler wsgi-script 69 | Options +ExecCGI 70 | WSGIProcessGroup nova-metadata 71 | WSGIApplicationGroup %{GLOBAL} 72 | WSGIPassAuthorization On 73 | 74 | -------------------------------------------------------------------------------- /templates/novametadata/config/nova-metadata-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/usr/sbin/httpd -DFOREGROUND", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/openstack/config/nova-blank.conf", 6 | "dest": "/etc/nova/nova.conf", 7 | "owner": "nova", 8 | "perm": "0600" 9 | }, 10 | { 11 | "source": "/var/lib/openstack/config/01-nova.conf", 12 | "dest": "/etc/nova/nova.conf.d/01-nova.conf", 13 | "owner": "nova", 14 | "perm": "0600" 15 | }, 16 | { 17 | "source": "/var/lib/openstack/config/02-nova-override.conf", 18 | "dest": "/etc/nova/nova.conf.d/02-nova-override.conf", 19 | "owner": "nova", 20 | "perm": "0600", 21 | "optional": true 22 | }, 23 | { 24 | "source": "/var/lib/openstack/config/httpd.conf", 25 | "dest": "/etc/httpd/conf/httpd.conf", 26 | "owner": "apache", 27 | "perm": "0644" 28 | }, 29 | { 30 | "source": "/var/lib/openstack/config/ssl.conf", 31 | "dest": "/etc/httpd/conf.d/ssl.conf", 32 | "owner": "apache", 33 | "perm": "0444" 34 | }, 35 | { 36 | "source": "/var/lib/config-data/tls/certs/*", 37 | "dest": "/etc/pki/tls/certs/", 38 | "owner": "nova", 39 | "perm": "0640", 40 | "optional": true, 41 | "merge": true 42 | }, 43 | { 44 | "source": "/var/lib/config-data/tls/private/*", 45 | "dest": "/etc/pki/tls/private/", 46 | "owner": "nova", 47 | "perm": "0600", 48 | "optional": true, 49 | "merge": true 50 | }, 51 | { 52 | "source": "/var/lib/openstack/config/api-paste.ini", 53 | "dest": "/etc/nova/api-paste.ini", 54 | "owner": "nova", 55 | "perm": "0600", 56 | "optional": true 57 | }, 58 | { 59 | "source": "/var/lib/openstack/config/my.cnf", 60 | "dest": "/etc/my.cnf", 61 | "owner": "nova", 62 | "perm": "0644" 63 | } 64 | ], 65 | "permissions": [ 66 | { 67 | "path": "/var/log/nova", 68 | "owner": "nova:apache", 69 | "recurse": true 70 | }, 71 | { 72 | "path": "/etc/httpd/run/", 73 | "owner": "nova:apache", 74 | "recurse": true 75 | } 76 | ] 77 | } 78 | -------------------------------------------------------------------------------- /templates/novametadata/config/ssl.conf: -------------------------------------------------------------------------------- 1 | 2 | SSLRandomSeed startup builtin 3 | SSLRandomSeed startup file:/dev/urandom 512 4 | SSLRandomSeed connect builtin 5 | SSLRandomSeed connect file:/dev/urandom 512 6 | 7 | AddType application/x-x509-ca-cert .crt 8 | AddType application/x-pkcs7-crl .crl 9 | 10 | SSLPassPhraseDialog builtin 11 | SSLSessionCache "shmcb:/var/cache/mod_ssl/scache(512000)" 12 | SSLSessionCacheTimeout 300 13 | Mutex default 14 | SSLCryptoDevice builtin 15 | SSLHonorCipherOrder On 16 | SSLUseStapling Off 17 | SSLStaplingCache "shmcb:/run/httpd/ssl_stapling(32768)" 18 | SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!RC4:!3DES 19 | SSLProtocol all -SSLv2 -SSLv3 -TLSv1 20 | SSLOptions StdEnvVars 21 | 22 | -------------------------------------------------------------------------------- /templates/novanovncproxy/bin/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack-k8s-operators/nova-operator/aa8325f052971ce543d3879d5582d0b565e88745/templates/novanovncproxy/bin/.keep -------------------------------------------------------------------------------- /templates/novanovncproxy/config/nova-novncproxy-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/usr/bin/nova-novncproxy --web /usr/share/novnc/", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/openstack/config/nova-blank.conf", 6 | "dest": "/etc/nova/nova.conf", 7 | "owner": "nova", 8 | "perm": "0600" 9 | }, 10 | { 11 | "source": "/var/lib/openstack/config/01-nova.conf", 12 | "dest": "/etc/nova/nova.conf.d/01-nova.conf", 13 | "owner": "nova", 14 | "perm": "0600" 15 | }, 16 | { 17 | "source": "/var/lib/openstack/config/02-nova-override.conf", 18 | "dest": "/etc/nova/nova.conf.d/02-nova-override.conf", 19 | "owner": "nova", 20 | "perm": "0600", 21 | "optional": true 22 | }, 23 | { 24 | "source": "/var/lib/config-data/tls/certs/*", 25 | "dest": "/etc/pki/tls/certs/", 26 | "owner": "nova", 27 | "perm": "0640", 28 | "optional": true, 29 | "merge": true 30 | }, 31 | { 32 | "source": "/var/lib/config-data/tls/private/*", 33 | "dest": "/etc/pki/tls/private/", 34 | "owner": "nova", 35 | "perm": "0600", 36 | "optional": true, 37 | "merge": true 38 | }, 39 | { 40 | "source": "/var/lib/openstack/config/my.cnf", 41 | "dest": "/etc/my.cnf", 42 | "owner": "nova", 43 | "perm": "0644" 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /templates/novascheduler/bin/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack-k8s-operators/nova-operator/aa8325f052971ce543d3879d5582d0b565e88745/templates/novascheduler/bin/.keep -------------------------------------------------------------------------------- /templates/novascheduler/config/nova-scheduler-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/usr/bin/nova-scheduler", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/openstack/config/nova-blank.conf", 6 | "dest": "/etc/nova/nova.conf", 7 | "owner": "nova", 8 | "perm": "0600" 9 | }, 10 | { 11 | "source": "/var/lib/openstack/config/01-nova.conf", 12 | "dest": "/etc/nova/nova.conf.d/01-nova.conf", 13 | "owner": "nova", 14 | "perm": "0600" 15 | }, 16 | { 17 | "source": "/var/lib/openstack/config/02-nova-override.conf", 18 | "dest": "/etc/nova/nova.conf.d/02-nova-override.conf", 19 | "owner": "nova", 20 | "perm": "0600", 21 | "optional": true 22 | }, 23 | { 24 | "source": "/var/lib/openstack/config/my.cnf", 25 | "dest": "/etc/my.cnf", 26 | "owner": "nova", 27 | "perm": "0644" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/cell-tests/00-cleanup-nova.yaml: -------------------------------------------------------------------------------- 1 | ../common/cleanup-nova.yaml -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/cell-tests/01-deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: Nova 3 | metadata: 4 | name: nova-kuttl 5 | spec: 6 | secret: osp-secret 7 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/cell-tests/02-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: Nova 3 | metadata: 4 | finalizers: 5 | - openstack.org/nova 6 | name: nova-kuttl 7 | namespace: nova-kuttl-default 8 | status: 9 | apiServiceReadyCount: 1 10 | metadataServiceReadyCount: 1 11 | schedulerServiceReadyCount: 1 12 | conditions: 13 | - message: Setup complete 14 | reason: Ready 15 | status: "True" 16 | type: Ready 17 | - message: Input data complete 18 | reason: Ready 19 | status: "True" 20 | type: InputReady 21 | - message: Setup complete 22 | reason: Ready 23 | status: "True" 24 | type: KeystoneServiceReady 25 | - message: MariaDBAccount creation complete 26 | reason: Ready 27 | status: "True" 28 | type: MariaDBAccountReady 29 | - message: ' Memcached instance has been provisioned' 30 | reason: Ready 31 | status: "True" 32 | type: MemcachedReady 33 | - message: DB create completed 34 | reason: Ready 35 | status: "True" 36 | type: NovaAPIDBReady 37 | - message: API message bus creation successfully 38 | reason: Ready 39 | status: "True" 40 | type: NovaAPIMQReady 41 | - message: Setup complete 42 | reason: Ready 43 | status: "True" 44 | type: NovaAPIReady 45 | - message: All DBs created successfully 46 | reason: Ready 47 | status: "True" 48 | type: NovaAllCellDBReady 49 | - message: All NovaCells are ready 50 | reason: Ready 51 | status: "True" 52 | type: NovaAllCellReady 53 | - message: All message busses created successfully 54 | reason: Ready 55 | status: "True" 56 | type: NovaAllCellsMQReady 57 | - message: There is no more NovaCells to delete 58 | reason: Ready 59 | status: "True" 60 | type: NovaCellsDeletion 61 | - message: Setup complete 62 | reason: Ready 63 | status: "True" 64 | type: NovaMetadataReady 65 | - message: Setup complete 66 | reason: Ready 67 | status: "True" 68 | type: NovaSchedulerReady 69 | - message: RoleBinding created 70 | reason: Ready 71 | status: "True" 72 | type: RoleBindingReady 73 | - message: Role created 74 | reason: Ready 75 | status: "True" 76 | type: RoleReady 77 | - message: ServiceAccount created 78 | reason: Ready 79 | status: "True" 80 | type: ServiceAccountReady 81 | --- 82 | apiVersion: v1 83 | kind: Pod 84 | metadata: 85 | annotations: 86 | openshift.io/scc: anyuid 87 | labels: 88 | service: nova-api 89 | name: nova-kuttl-api-0 90 | status: 91 | containerStatuses: 92 | - name: nova-kuttl-api-api 93 | ready: true 94 | started: true 95 | - name: nova-kuttl-api-log 96 | ready: true 97 | started: true 98 | --- 99 | apiVersion: v1 100 | kind: Pod 101 | metadata: 102 | annotations: 103 | openshift.io/scc: anyuid 104 | labels: 105 | service: nova-metadata 106 | statefulset.kubernetes.io/pod-name: nova-kuttl-metadata-0 107 | name: nova-kuttl-metadata-0 108 | ownerReferences: 109 | - apiVersion: apps/v1 110 | blockOwnerDeletion: true 111 | controller: true 112 | kind: StatefulSet 113 | name: nova-kuttl-metadata 114 | status: 115 | containerStatuses: 116 | - name: nova-kuttl-metadata-log 117 | ready: true 118 | started: true 119 | - name: nova-kuttl-metadata-metadata 120 | ready: true 121 | started: true 122 | 123 | --- 124 | apiVersion: kuttl.dev/v1beta1 125 | kind: TestAssert 126 | commands: 127 | - script: | 128 | oc get -n nova-kuttl-default pod/nova-kuttl-cell1-novncproxy-0 || exit 0 129 | exit 1 130 | - script: | 131 | oc get -n nova-kuttl-default pod/nova-kuttl-cell1-conductor-0 || exit 0 132 | exit 1 133 | - script: | 134 | oc get -n nova-kuttl-default NovaCell/nova-cell1 || exit 0 135 | exit 1 136 | - script: | 137 | oc get -n nova-kuttl-default MariaDBAccount/nova-cell1 || exit 0 138 | exit 1 139 | - script: | 140 | oc get -n nova-kuttl-default MariaDBDatabase/nova-cell1 || exit 0 141 | exit 1 142 | - script: | 143 | oc get -n nova-kuttl-default TransportUrl/nova-cell1-transport || exit 0 144 | exit 1 145 | - script: | 146 | oc get -n nova-kuttl-default Secret/nova-cell1 || exit 0 147 | exit 1 148 | - script: | 149 | oc get -n nova-kuttl-default Secret/nova-cell1-db-secret || exit 0 150 | exit 1 151 | - script: | 152 | oc get -n nova-kuttl-default Secret/nova-cell1-compute-config || exit 0 153 | exit 1 154 | - script: | 155 | oc get -n nova-kuttl-default Secret/nova-cell1-manage-config-data || exit 0 156 | exit 1 157 | # TODO(gibi): this needs an openstack-operator change to clean up the cell1 158 | # cert secrets 159 | #- script: | 160 | # oc get -n nova-kuttl-default Secret/cert-nova-novncproxy-cell1-public-svc || exit 0 161 | # exit 1 162 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/cell-tests/02-delete-cell-nova.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "remove", "path": "/spec/cellTemplates/cell1"}]' 6 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/cell-tests/03-cleanup-nova.yaml: -------------------------------------------------------------------------------- 1 | 00-cleanup-nova.yaml -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/common/cleanup-nova.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | delete: 4 | - apiVersion: nova.openstack.org/v1beta1 5 | kind: Nova 6 | name: nova-kuttl 7 | namespace: nova-kuttl-default 8 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/config-tests/00-cleanup-nova.yaml: -------------------------------------------------------------------------------- 1 | ../common/cleanup-nova.yaml -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/config-tests/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: Nova 3 | metadata: 4 | finalizers: 5 | - openstack.org/nova 6 | name: nova-kuttl 7 | namespace: nova-kuttl-default 8 | status: 9 | apiServiceReadyCount: 1 10 | metadataServiceReadyCount: 1 11 | schedulerServiceReadyCount: 1 12 | conditions: 13 | - message: Setup complete 14 | reason: Ready 15 | status: "True" 16 | type: Ready 17 | - message: Input data complete 18 | reason: Ready 19 | status: "True" 20 | type: InputReady 21 | - message: Setup complete 22 | reason: Ready 23 | status: "True" 24 | type: KeystoneServiceReady 25 | - message: MariaDBAccount creation complete 26 | reason: Ready 27 | status: "True" 28 | type: MariaDBAccountReady 29 | - message: ' Memcached instance has been provisioned' 30 | reason: Ready 31 | status: "True" 32 | type: MemcachedReady 33 | - message: DB create completed 34 | reason: Ready 35 | status: "True" 36 | type: NovaAPIDBReady 37 | - message: API message bus creation successfully 38 | reason: Ready 39 | status: "True" 40 | type: NovaAPIMQReady 41 | - message: Setup complete 42 | reason: Ready 43 | status: "True" 44 | type: NovaAPIReady 45 | - message: All DBs created successfully 46 | reason: Ready 47 | status: "True" 48 | type: NovaAllCellDBReady 49 | - message: All NovaCells are ready 50 | reason: Ready 51 | status: "True" 52 | type: NovaAllCellReady 53 | - message: All message busses created successfully 54 | reason: Ready 55 | status: "True" 56 | type: NovaAllCellsMQReady 57 | - message: There is no more NovaCells to delete 58 | reason: Ready 59 | status: "True" 60 | type: NovaCellsDeletion 61 | - message: Setup complete 62 | reason: Ready 63 | status: "True" 64 | type: NovaMetadataReady 65 | - message: Setup complete 66 | reason: Ready 67 | status: "True" 68 | type: NovaSchedulerReady 69 | - message: RoleBinding created 70 | reason: Ready 71 | status: "True" 72 | type: RoleBindingReady 73 | - message: Role created 74 | reason: Ready 75 | status: "True" 76 | type: RoleReady 77 | - message: ServiceAccount created 78 | reason: Ready 79 | status: "True" 80 | type: ServiceAccountReady 81 | --- 82 | apiVersion: v1 83 | kind: Pod 84 | metadata: 85 | annotations: 86 | openshift.io/scc: anyuid 87 | labels: 88 | service: nova-api 89 | name: nova-kuttl-api-0 90 | status: 91 | containerStatuses: 92 | - name: nova-kuttl-api-api 93 | ready: true 94 | started: true 95 | - name: nova-kuttl-api-log 96 | ready: true 97 | started: true 98 | --- 99 | apiVersion: v1 100 | kind: Pod 101 | metadata: 102 | annotations: 103 | openshift.io/scc: anyuid 104 | labels: 105 | service: nova-metadata 106 | statefulset.kubernetes.io/pod-name: nova-kuttl-metadata-0 107 | name: nova-kuttl-metadata-0 108 | ownerReferences: 109 | - apiVersion: apps/v1 110 | blockOwnerDeletion: true 111 | controller: true 112 | kind: StatefulSet 113 | name: nova-kuttl-metadata 114 | status: 115 | containerStatuses: 116 | - name: nova-kuttl-metadata-log 117 | ready: true 118 | started: true 119 | - name: nova-kuttl-metadata-metadata 120 | ready: true 121 | started: true 122 | --- 123 | apiVersion: v1 124 | kind: Pod 125 | metadata: 126 | name: nova-kuttl-cell1-compute-fake1-compute-0 127 | status: 128 | containerStatuses: 129 | - name: nova-kuttl-cell1-compute-fake1-compute-compute 130 | ready: true 131 | started: true 132 | --- 133 | apiVersion: kuttl.dev/v1beta1 134 | kind: TestAssert 135 | namespaced: true 136 | commands: 137 | - script: | 138 | set -euxo pipefail 139 | MESSAGE=$(oc exec -n $NAMESPACE openstackclient -- openstack flavor create my-flavor 2>&1) || true 140 | echo $MESSAGE | grep "Policy doesn't allow os_compute_api:os-flavor-manage:create to be performed" 141 | - script: | 142 | set -euxo pipefail 143 | RP_UUID=$(oc exec -n $NAMESPACE openstackclient -- openstack resource provider list --name nova-kuttl-cell1-compute-fake1-compute-0 -f value -c uuid) 144 | oc exec -n $NAMESPACE openstackclient -- openstack resource provider trait list $RP_UUID | grep CUSTOM_FOO 145 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/config-tests/01-deploy-with-default-config-overwrite.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: Nova 3 | metadata: 4 | name: nova-kuttl 5 | spec: 6 | secret: osp-secret 7 | apiServiceTemplate: 8 | defaultConfigOverwrite: 9 | policy.yaml: | 10 | "os_compute_api:os-flavor-manage:create": "!" 11 | cellTemplates: 12 | cell0: 13 | cellDatabaseInstance: openstack 14 | cellDatabaseAccount: nova-cell0 15 | cellMessageBusInstance: rabbitmq 16 | hasAPIAccess: true 17 | memcachedInstance: memcached 18 | cell1: 19 | cellDatabaseInstance: openstack-cell1 20 | cellDatabaseAccount: nova-cell1 21 | cellMessageBusInstance: rabbitmq-cell1 22 | memcachedInstance: memcached 23 | novaComputeTemplates: 24 | compute-fake1: 25 | computeDriver: fake.FakeDriver 26 | defaultConfigOverwrite: 27 | provider.yaml: | 28 | meta: 29 | schema_version: '1.0' 30 | providers: 31 | - identification: 32 | uuid: '$COMPUTE_NODE' 33 | traits: 34 | additional: 35 | - 'CUSTOM_FOO' 36 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/config-tests/02-cleanup-nova.yaml: -------------------------------------------------------------------------------- 1 | ../common/cleanup-nova.yaml -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestSuite 3 | reportFormat: JSON 4 | reportName: kuttl-default-results 5 | namespace: nova-kuttl-default 6 | # we could set this lower, but the initial image pull can take a while 7 | timeout: 300 8 | parallel: 1 9 | skipDelete: true 10 | testDirs: 11 | - test/kuttl/test-suites/default/ 12 | suppress: 13 | - events 14 | artifactsDir: test/kuttl/test-suites/default/output 15 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/deps/OpenStackControlPlane.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: core.openstack.org/v1beta1 2 | kind: OpenStackControlPlane 3 | metadata: 4 | name: openstack 5 | spec: 6 | storageClass: "crc-csi-hostpath-provisioner" 7 | tls: 8 | ingress: 9 | enabled: true 10 | podLevel: 11 | enabled: false 12 | ironic: 13 | enabled: false 14 | template: 15 | ironicConductors: [] 16 | manila: 17 | enabled: false 18 | template: 19 | manilaShares: {} 20 | horizon: 21 | enabled: false 22 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/deps/infra.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: core.openstack.org/v1beta1 2 | kind: OpenStackControlPlane 3 | metadata: 4 | name: openstack 5 | spec: 6 | mariadb: 7 | enabled: false 8 | galera: 9 | enabled: true 10 | templates: 11 | openstack: 12 | storageRequest: 500M 13 | openstack-cell1: 14 | storageRequest: 500M 15 | rabbitmq: 16 | templates: 17 | rabbitmq: 18 | replicas: 1 19 | rabbitmq-cell1: 20 | replicas: 1 21 | memcached: 22 | templates: 23 | memcached: 24 | replicas: 1 25 | ovn: 26 | enabled: false 27 | template: 28 | ovnController: 29 | external-ids: 30 | ovn-encap-type: geneve 31 | ovs: 32 | enabled: false 33 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/deps/keystone.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: core.openstack.org/v1beta1 2 | kind: OpenStackControlPlane 3 | metadata: 4 | name: openstack 5 | spec: 6 | keystone: 7 | template: 8 | databaseInstance: openstack 9 | secret: osp-secret 10 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/deps/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | namespace: nova-kuttl-default 4 | 5 | secretGenerator: 6 | - literals: 7 | - AdminPassword=password 8 | - DbRootPassword=password 9 | - DatabasePassword=password 10 | - KeystoneDatabasePassword=password 11 | - PlacementPassword=password 12 | - PlacementDatabasePassword=password 13 | - GlancePassword=password 14 | - GlanceDatabasePassword=password 15 | - NeutronPassword=password 16 | - NeutronDatabasePassword=password 17 | - NovaPassword=password 18 | - NovaAPIDatabasePassword=password 19 | - NovaCell0DatabasePassword=password 20 | - NovaCell1DatabasePassword=password 21 | - MetadataSecret=42 22 | name: osp-secret 23 | generatorOptions: 24 | disableNameSuffixHash: true 25 | labels: 26 | type: osp-secret 27 | 28 | resources: 29 | - namespace.yaml 30 | - OpenStackControlPlane.yaml 31 | 32 | patches: 33 | - patch: |- 34 | apiVersion: core.openstack.org/v1beta1 35 | kind: OpenStackControlPlane 36 | metadata: 37 | name: openstack 38 | spec: 39 | secret: osp-secret 40 | - path: infra.yaml 41 | - path: keystone.yaml 42 | - path: placement.yaml 43 | - path: nova.yaml 44 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/deps/namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: nova-kuttl-multi-cell 5 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/deps/nova.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: core.openstack.org/v1beta1 2 | kind: OpenStackControlPlane 3 | metadata: 4 | name: openstack 5 | spec: 6 | nova: 7 | enabled: false 8 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/deps/placement.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: core.openstack.org/v1beta1 2 | kind: OpenStackControlPlane 3 | metadata: 4 | name: openstack 5 | spec: 6 | placement: 7 | template: 8 | databaseInstance: openstack 9 | secret: osp-secret 10 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/output/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack-k8s-operators/nova-operator/aa8325f052971ce543d3879d5582d0b565e88745/test/kuttl/test-suites/default/output/.keep -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/scale-tests/00-cleanup-nova.yaml: -------------------------------------------------------------------------------- 1 | ../common/cleanup-nova.yaml -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/scale-tests/01-deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: nova.openstack.org/v1beta1 2 | kind: Nova 3 | metadata: 4 | name: nova-kuttl 5 | spec: 6 | secret: osp-secret 7 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/scale-tests/02-scale-up-nova.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/apiServiceTemplate/replicas", "value":3}]' 6 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/cellTemplates/cell0/conductorServiceTemplate/replicas", "value":3}]' 7 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/cellTemplates/cell1/conductorServiceTemplate/replicas", "value":3}]' 8 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/metadataServiceTemplate/replicas", "value":3}]' 9 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/schedulerServiceTemplate/replicas", "value":3}]' 10 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/scale-tests/03-scale-down-nova.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/apiServiceTemplate/replicas", "value":1}]' 6 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/cellTemplates/cell0/conductorServiceTemplate/replicas", "value":1}]' 7 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/cellTemplates/cell1/conductorServiceTemplate/replicas", "value":1}]' 8 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/metadataServiceTemplate/replicas", "value":1}]' 9 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/schedulerServiceTemplate/replicas", "value":1}]' 10 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/scale-tests/04-scale-down-zero-nova.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/apiServiceTemplate/replicas", "value":0}]' 6 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/cellTemplates/cell0/conductorServiceTemplate/replicas", "value":0}]' 7 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/cellTemplates/cell1/conductorServiceTemplate/replicas", "value":0}]' 8 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/metadataServiceTemplate/replicas", "value":0}]' 9 | oc patch -n nova-kuttl-default nova/nova-kuttl --type='json' -p='[{"op": "replace", "path": "/spec/schedulerServiceTemplate/replicas", "value":0}]' 10 | -------------------------------------------------------------------------------- /test/kuttl/test-suites/default/scale-tests/05-cleanup-nova.yaml: -------------------------------------------------------------------------------- 1 | 00-cleanup-nova.yaml --------------------------------------------------------------------------------