├── .ci-operator.yaml ├── .dockerignore ├── .github └── workflows │ ├── build-neutron-operator.yaml │ ├── force-bump-pr-manual.yaml │ ├── force-bump-pr-scheduled.yaml │ ├── release-branch-sync.yaml │ └── release-neutron-operator.yaml ├── .gitignore ├── .golangci.yaml ├── .pre-commit-config.yaml ├── .prow_ci.env ├── Dockerfile ├── LICENSE.txt ├── Makefile ├── OWNERS ├── OWNERS_ALIASES ├── PROJECT ├── README.md ├── api ├── bases │ └── neutron.openstack.org_neutronapis.yaml ├── go.mod ├── go.sum └── v1beta1 │ ├── groupversion_info.go │ ├── neutronapi_types.go │ ├── neutronapi_webhook.go │ └── zz_generated.deepcopy.go ├── config ├── certmanager │ ├── certificate.yaml │ ├── kustomization.yaml │ └── kustomizeconfig.yaml ├── crd │ ├── bases │ │ └── neutron.openstack.org_neutronapis.yaml │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ └── patches │ │ ├── cainjection_in_neutronapis.yaml │ │ └── webhook_in_neutronapis.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 │ │ └── neutron-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 │ ├── neutronapi_editor_role.yaml │ ├── neutronapi_viewer_role.yaml │ ├── role.yaml │ ├── role_binding.yaml │ └── service_account.yaml ├── samples │ ├── kustomization.yaml │ ├── neutron-secret.yaml │ ├── neutron_v1beta1_neutronapi.yaml │ ├── neutron_v1beta1_neutronapi_openvswitch.yaml │ └── neutron_v1beta1_neutronapi_tls.yaml ├── scorecard │ ├── bases │ │ └── config.yaml │ ├── kustomization.yaml │ └── patches │ │ ├── basic.config.yaml │ │ └── olm.config.yaml └── webhook │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ ├── manifests.yaml │ └── service.yaml ├── controllers └── neutronapi_controller.go ├── go.mod ├── go.sum ├── hack ├── boilerplate.go.txt ├── build-crd-schema-checker.sh ├── clean_local_webhook.sh ├── crd-schema-checker.sh └── run_with_local_webhook.sh ├── kuttl-test.yaml ├── main.go ├── pkg └── neutronapi │ ├── const.go │ ├── dbsync.go │ ├── deployment.go │ ├── scc.go │ └── volumes.go ├── renovate.json ├── templates ├── dhcp-agent.conf ├── neutronapi │ ├── config │ │ ├── 01-neutron.conf │ │ ├── db-sync-config.json │ │ ├── neutron-api-config.json │ │ └── neutron-httpd-config.json │ └── httpd │ │ ├── 10-neutron-httpd.conf │ │ ├── httpd.conf │ │ └── ssl.conf ├── ovn-agent.conf ├── ovn-metadata-agent.conf └── sriov-agent.conf ├── test ├── functional │ ├── base_test.go │ ├── neutronapi_controller_test.go │ └── suite_test.go └── kuttl │ ├── common │ ├── assert_sample_deployment.yaml │ ├── assert_tls_cert.yaml │ ├── cleanup-neutron.yaml │ ├── errors_cleanup_neutron.yaml │ ├── scripts │ │ └── check_debug_in_neutron_pod_logs.sh │ ├── tls_ca_bundle.yaml │ ├── tls_cert_neutron-internal-svc.yaml │ └── tls_cert_neutron-public-svc.yaml │ └── tests │ ├── change_neutron_config │ ├── 00-assert.yaml │ ├── 00-test-resources.yaml │ ├── 01-assert.yaml │ ├── 01-deploy-neutron.yaml │ ├── 02-assert.yaml │ ├── 02-extramounts.yaml │ ├── 03-assert.yaml │ ├── 03-change_neutron_debug_config.yaml │ ├── 04-cleanup-neutron.yaml │ ├── 04-errors.yaml │ └── deploy │ │ └── kustomization.yaml │ ├── neutron_no_ovn │ ├── 01-assert.yaml │ ├── 01-deploy-neutron.yaml │ ├── 02-cleanup-neutron.yaml │ ├── 02-errors.yaml │ └── deploy │ │ └── kustomization.yaml │ ├── neutron_scale │ ├── 01-assert.yaml │ ├── 01-deploy-neutron.yaml │ ├── 02-assert.yaml │ ├── 02-scale-neutronapi.yaml │ ├── 03-assert.yaml │ ├── 03-scale-down-neutronapi.yaml │ ├── 04-assert.yaml │ ├── 04-errors.yaml │ ├── 04-scale-down-zero-neutronapi.yaml │ ├── 05-cleanup-neutron.yaml │ ├── 05-errors.yaml │ └── deploy │ │ └── kustomization.yaml │ └── neutron_tls │ ├── 00-assert.yaml │ ├── 00-tls_ca_bundle.yaml │ ├── 00-tls_cert_neutron-internal-svc.yaml │ ├── 00-tls_cert_neutron-public-svc.yaml │ ├── 01-assert.yaml │ ├── 01-deploy-neutron.yaml │ ├── 02-cleanup-neutron.yaml │ ├── 02-errors.yaml │ └── deploy │ └── kustomization.yaml └── zuul.d ├── jobs.yaml └── project.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-neutron-operator.yaml: -------------------------------------------------------------------------------- 1 | name: neutron 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: neutron 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/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: neutron 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 4 * * 6' # 4AM 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: neutron 13 | secrets: 14 | FORCE_BUMP_PULL_REQUEST_PAT: ${{ secrets.FORCE_BUMP_PULL_REQUEST_PAT }} 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-neutron-operator.yaml: -------------------------------------------------------------------------------- 1 | name: Release Neutron 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 | 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | /bin 9 | testbin/* 10 | 11 | # Test binary, build with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Kubernetes Generated files - skip generated files, except for vendored files 18 | 19 | !vendor/**/zz_generated.* 20 | 21 | #Operator SDK generated files 22 | /bundle/ 23 | bundle.Dockerfile 24 | config/manager/kustomization.yaml 25 | 26 | # editor and IDE paraphernalia 27 | .idea 28 | *.swp 29 | *.swo 30 | 31 | # Common CI tools repository 32 | CI_TOOLS_REPO 33 | *~ 34 | # generated workspace file 35 | go.work 36 | go.work.sum 37 | -------------------------------------------------------------------------------- /.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 | 16 | issues: 17 | exclude-rules: 18 | - path: '(.+)_test\.go' 19 | linters: 20 | - gosec 21 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | 3 | - repo: local 4 | hooks: 5 | - id: gotidy 6 | name: gotidy 7 | language: system 8 | entry: make 9 | args: ["tidy"] 10 | pass_filenames: false 11 | - id: make-manifests 12 | name: make-manifests 13 | language: system 14 | entry: make 15 | args: ['manifests'] 16 | pass_filenames: false 17 | - id: make-generate 18 | name: make-generate 19 | language: system 20 | entry: make 21 | args: ['generate'] 22 | pass_filenames: false 23 | - id: make-bundle 24 | name: make-bundle 25 | language: system 26 | entry: make 27 | args: ['bundle', 'VERSION=0.0.1'] 28 | pass_filenames: false 29 | - id: make-operator-lint 30 | name: make-operator-lint 31 | language: system 32 | entry: make 33 | args: ['operator-lint'] 34 | pass_filenames: false 35 | - id: make-crd-schema-check 36 | name: make-crd-schema-check 37 | language: system 38 | entry: make 39 | args: ['crd-schema-check'] 40 | pass_filenames: false 41 | 42 | - repo: https://github.com/pre-commit/pre-commit-hooks 43 | rev: v4.4.0 44 | hooks: 45 | - id: check-added-large-files 46 | - id: fix-byte-order-marker 47 | - id: check-case-conflict 48 | - id: check-executables-have-shebangs 49 | exclude: ^vendor 50 | - id: check-shebang-scripts-are-executable 51 | exclude: ^vendor 52 | - id: check-merge-conflict 53 | - id: check-symlinks 54 | - id: destroyed-symlinks 55 | - id: check-yaml 56 | args: [-m] 57 | exclude: "^templates/(openstackconfiggenerator|openstackcontrolplane)/.*$" 58 | - id: check-json 59 | - id: detect-private-key 60 | - id: end-of-file-fixer 61 | exclude: ^vendor 62 | - id: no-commit-to-branch 63 | - id: trailing-whitespace 64 | exclude: ^vendor 65 | 66 | - repo: https://github.com/openstack-dev/bashate.git 67 | rev: 2.1.1 68 | hooks: 69 | - id: bashate 70 | entry: bashate --error . --ignore=E006,E040,E020,E012 71 | # Run bashate check for all bash scripts 72 | # Ignores the following rules: 73 | # E006: Line longer than 79 columns (as many scripts use jinja 74 | # templating, this is very difficult) 75 | # E040: Syntax error determined using `bash -n` (as many scripts 76 | # use jinja templating, this will often fail and the syntax 77 | # error will be discovered in execution anyway) 78 | # E020: Function declaration not in format ^function name {$ 79 | # E012: here doc didn't end before EOF 80 | 81 | - repo: https://github.com/golangci/golangci-lint 82 | rev: v1.59.1 83 | hooks: 84 | - id: golangci-lint-full 85 | args: ["-v"] 86 | 87 | - repo: https://github.com/openstack-k8s-operators/openstack-k8s-operators-ci 88 | # NOTE(gibi): we cannot automatically track main here 89 | # see https://pre-commit.com/#using-the-latest-version-for-a-repository 90 | rev: e30d72fcbced0ab8a7b6d23be1dee129e2a7b849 91 | hooks: 92 | - id: kuttl-single-test-assert 93 | -------------------------------------------------------------------------------- /.prow_ci.env: -------------------------------------------------------------------------------- 1 | export USE_IMAGE_DIGESTS=true 2 | export FAIL_FIPS_CHECK=true 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Build the manager binary 2 | ARG GOLANG_BUILDER=registry.access.redhat.com/ubi9/go-toolset:1.21 3 | ARG OPERATOR_BASE_IMAGE=registry.access.redhat.com/ubi9/ubi-minimal:latest 4 | 5 | FROM $GOLANG_BUILDER AS builder 6 | 7 | #Arguments required by OSBS build system 8 | ARG CACHITO_ENV_FILE=/remote-source/cachito.env 9 | 10 | ARG REMOTE_SOURCE=. 11 | ARG REMOTE_SOURCE_DIR=/remote-source 12 | ARG REMOTE_SOURCE_SUBDIR= 13 | ARG DEST_ROOT=/dest-root 14 | 15 | ARG GO_BUILD_EXTRA_ARGS="-tags strictfipsruntime" 16 | # note we set CGO_ENABLED=0 to force a static build so that we can use 17 | # distroless/static as our base image 18 | ARG GO_BUILD_EXTRA_ENV_ARGS="CGO_ENABLED=1 GO111MODULE=on" 19 | 20 | COPY $REMOTE_SOURCE $REMOTE_SOURCE_DIR 21 | WORKDIR $REMOTE_SOURCE_DIR/$REMOTE_SOURCE_SUBDIR 22 | 23 | USER root 24 | RUN mkdir -p ${DEST_ROOT}/usr/local/bin/ 25 | 26 | # cache deps before building and copying source so that we don't need to re-download as much 27 | # and so that source changes don't invalidate our downloaded layer 28 | RUN if [ ! -f $CACHITO_ENV_FILE ]; then go mod download ; fi 29 | 30 | # Build manager 31 | 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 32 | 33 | RUN cp -r templates ${DEST_ROOT}/templates 34 | 35 | # Use distroless as minimal base image to package the manager binary 36 | # Refer to https://github.com/GoogleContainerTools/distroless for more details 37 | FROM $OPERATOR_BASE_IMAGE 38 | 39 | ARG DEST_ROOT=/dest-root 40 | # NONROOT default id https://github.com/GoogleContainerTools/distroless/blob/main/base/base.bzl#L8= 41 | ARG USER_ID=65532 42 | 43 | ARG IMAGE_COMPONENT="neutron-operator-container" 44 | ARG IMAGE_NAME="neutron-operator" 45 | ARG IMAGE_VERSION="1.0.0" 46 | ARG IMAGE_SUMMARY="Neutron Operator" 47 | ARG IMAGE_DESC="This image includes the neutron-operator" 48 | ARG IMAGE_TAGS="cn-openstack openstack" 49 | 50 | ### DO NOT EDIT LINES BELOW 51 | # Auto generated using CI tools from 52 | # https://github.com/openstack-k8s-operators/openstack-k8s-operators-ci 53 | 54 | # Labels required by upstream and osbs build system 55 | LABEL com.redhat.component="${IMAGE_COMPONENT}" \ 56 | name="${IMAGE_NAME}" \ 57 | version="${IMAGE_VERSION}" \ 58 | summary="${IMAGE_SUMMARY}" \ 59 | io.k8s.name="${IMAGE_NAME}" \ 60 | io.k8s.description="${IMAGE_DESC}" \ 61 | io.openshift.tags="${IMAGE_TAGS}" 62 | ### DO NOT EDIT LINES ABOVE 63 | 64 | ENV USER_UID=$USER_ID \ 65 | OPERATOR_TEMPLATES=/usr/share/neutron-operator/templates/ 66 | 67 | WORKDIR / 68 | 69 | # Install operator binary to WORKDIR 70 | COPY --from=builder ${DEST_ROOT}/manager . 71 | 72 | # Install templates 73 | COPY --from=builder ${DEST_ROOT}/templates ${OPERATOR_TEMPLATES} 74 | 75 | USER $USER_ID 76 | 77 | ENV PATH="/:${PATH}" 78 | 79 | ENTRYPOINT ["/manager"] 80 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | approvers: 3 | - ci-approvers 4 | - network-approvers 5 | - openstack-approvers 6 | 7 | reviewers: 8 | - ci-approvers 9 | - network-approvers 10 | - openstack-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 | network-approvers: 9 | - karelyatin 10 | - slawqo 11 | openstack-approvers: 12 | - abays 13 | - dprince 14 | - olliewalsh 15 | - stuggi 16 | -------------------------------------------------------------------------------- /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: neutron-operator 8 | repo: github.com/openstack-k8s-operators/neutron-operator 9 | resources: 10 | - api: 11 | crdVersion: v1 12 | namespaced: true 13 | controller: true 14 | domain: openstack.org 15 | group: neutron 16 | kind: NeutronAPI 17 | path: github.com/openstack-k8s-operators/neutron-operator/api/v1beta1 18 | version: v1beta1 19 | webhooks: 20 | defaulting: true 21 | validation: true 22 | webhookVersion: v1 23 | version: "3" 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # neutron-operator 2 | 3 | A Kubernetes Operator built using the [Operator Framework](https://github.com/operator-framework) for Go. 4 | The Operator provides a way to easily install and manage an OpenStack Neutron installation on Kubernetes. 5 | This Operator was developed using [RDO](https://www.rdoproject.org/) containers for openStack. 6 | 7 | # Deployment 8 | 9 | The operator is intended to be deployed via OLM [Operator Lifecycle Manager](https://github.com/operator-framework/operator-lifecycle-manager) 10 | 11 | # API Example 12 | 13 | The Operator creates a custom NeutronAPI resource that can be used to create Neutron API 14 | instances within the cluster. Example CR to create a Neutron API in your cluster: 15 | 16 | ```yaml 17 | apiVersion: neutron.openstack.org/v1beta1 18 | kind: NeutronAPI 19 | metadata: 20 | name: neutron 21 | spec: 22 | containerImage: quay.io/tripleowallabycentos9/openstack-neutron-server:current-podified 23 | databaseInstance: openstack 24 | secret: neutron-secret 25 | ``` 26 | 27 | ## Example: configure Neutron with additional networks 28 | 29 | The Neutron spec can be used to configure Neutron to have the pods 30 | being attached to additional networks. 31 | 32 | Create a network-attachement-definition which then can be referenced 33 | from the Neutron API CR. 34 | 35 | ``` 36 | --- 37 | apiVersion: k8s.cni.cncf.io/v1 38 | kind: NetworkAttachmentDefinition 39 | metadata: 40 | name: storage 41 | namespace: openstack 42 | spec: 43 | config: | 44 | { 45 | "cniVersion": "0.3.1", 46 | "name": "storage", 47 | "type": "macvlan", 48 | "master": "enp7s0.21", 49 | "ipam": { 50 | "type": "whereabouts", 51 | "range": "172.18.0.0/24", 52 | "range_start": "172.18.0.50", 53 | "range_end": "172.18.0.100" 54 | } 55 | } 56 | ``` 57 | 58 | The following represents an example of Neutron resource that can be used 59 | to trigger the service deployment, and have the service pods attached to 60 | the storage network using the above NetworkAttachmentDefinition. 61 | 62 | ``` 63 | apiVersion: neutron.openstack.org/v1beta1 64 | kind: NeutronAPI 65 | metadata: 66 | name: neutron 67 | spec: 68 | ... 69 | networkAttachents: 70 | - storage 71 | ... 72 | ``` 73 | 74 | When the service is up and running, it will now have an additional nic 75 | configured for the storage network: 76 | 77 | ``` 78 | # oc rsh neutron-75f5cd6595-kpfr2 79 | sh-5.1# ip a 80 | 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 81 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 82 | inet 127.0.0.1/8 scope host lo 83 | valid_lft forever preferred_lft forever 84 | inet6 ::1/128 scope host 85 | valid_lft forever preferred_lft forever 86 | 3: eth0@if298: mtu 1450 qdisc noqueue state UP group default 87 | link/ether 0a:58:0a:82:01:18 brd ff:ff:ff:ff:ff:ff link-netnsid 0 88 | inet 10.130.1.24/23 brd 10.130.1.255 scope global eth0 89 | valid_lft forever preferred_lft forever 90 | inet6 fe80::4cf2:a3ff:feb0:932/64 scope link 91 | valid_lft forever preferred_lft forever 92 | 4: net1@if26: mtu 1500 qdisc noqueue state UP group default 93 | link/ether a2:f1:3b:12:fd:be brd ff:ff:ff:ff:ff:ff link-netnsid 0 94 | inet 172.18.0.52/24 brd 172.18.0.255 scope global net1 95 | valid_lft forever preferred_lft forever 96 | inet6 fe80::a0f1:3bff:fe12:fdbe/64 scope link 97 | valid_lft forever preferred_lft forever 98 | ``` 99 | 100 | ## Example: expose Neutron to an isolated network 101 | 102 | The Neutron spec can be used to configure Neutron to register e.g. 103 | the internal endpoint to an isolated network. MetalLB is used for this 104 | scenario. 105 | 106 | As a pre requisite, MetalLB needs to be installed and worker nodes 107 | prepared to work as MetalLB nodes to serve the LoadBalancer service. 108 | 109 | In this example the following MetalLB IPAddressPool is used: 110 | 111 | ``` 112 | --- 113 | apiVersion: metallb.io/v1beta1 114 | kind: IPAddressPool 115 | metadata: 116 | name: osp-internalapi 117 | namespace: metallb-system 118 | spec: 119 | addresses: 120 | - 172.17.0.200-172.17.0.210 121 | autoAssign: false 122 | ``` 123 | 124 | The following represents an example of Neutron resource that can be used 125 | to trigger the service deployment, and have the internal neutronAPI endpoint 126 | registerd as a MetalLB service using the IPAddressPool `osp-internal`, 127 | request to use the IP `172.17.0.202` as the VIP and the IP is shared with 128 | other services. 129 | 130 | ``` 131 | apiVersion: neutron.openstack.org/v1beta1 132 | kind: NeutronAPI 133 | metadata: 134 | name: neutron 135 | spec: 136 | ... 137 | externalEndpoints: 138 | - endpoint: internal 139 | ipAddressPool: osp-internalapi 140 | loadBalancerIPs: 141 | - 172.17.0.202 142 | sharedIP: true 143 | sharedIPKey: "" 144 | ... 145 | ... 146 | ``` 147 | 148 | The internal neutron endpoint gets registered with its service name. This 149 | service name needs to resolve to the `LoadBalancerIP` on the isolated network 150 | either by DNS or via /etc/hosts: 151 | 152 | ``` 153 | # openstack endpoint list -c 'Service Name' -c Interface -c URL --service network 154 | +--------------+-----------+----------------------------------------------------------------+ 155 | | Service Name | Interface | URL | 156 | +--------------+-----------+----------------------------------------------------------------+ 157 | | neutron | public | http://neutron-public-openstack.apps.ostest.test.metalkube.org | 158 | | neutron | internal | http://neutron-internal.openstack.svc:9696 | 159 | +--------------+-----------+----------------------------------------------------------------+ 160 | ``` 161 | 162 | ## Provide additional volumes to Neutron 163 | 164 | The NeutronAPI spec can be used to configure Neutron to have multiple volumes 165 | attached to the deployed Pods. The operator will be able to define a set of 166 | `extraVolumes` using the standard k8s spec (they can be `Secrets`, `ConfigMaps` 167 | or even regular `PVCs`) and propagate the volumes to the Pods deployed by the 168 | neutron-operator. 169 | 170 | ## Example: Neutron Spec with a secret 171 | 172 | Create a `Secret` which contains the following data: 173 | 174 | ``` 175 | --- 176 | apiVersion: v1 177 | kind: Secret 178 | metadata: 179 | name: partner1 180 | namespace: openstack 181 | stringData: 182 | partner1-credentials: | 183 | supersecret-credential = ****** 184 | supersecret-credential = ****** 185 | supersecret-credential = ****** 186 | partner1-custom-config: | 187 | 188 | ``` 189 | 190 | Create a `NeutronAPI` CR that defines `extraMounts` in the spec and reference 191 | the secret which has been created: 192 | 193 | ``` 194 | apiVersion: neutron.openstack.org/v1beta1 195 | kind: NeutronAPI 196 | metadata: 197 | name: neutron 198 | namespace: openstack 199 | spec: 200 | serviceUser: neutron 201 | customServiceConfig: | 202 | [DEFAULT] 203 | debug = true 204 | databaseInstance: openstack 205 | databaseUser: neutron 206 | rabbitMqClusterName: rabbitmq 207 | memcachedInstance: memcached 208 | preserveJobs: false 209 | containerImage: quay.io/podified-antelope-centos9/openstack-neutron-server:current-podified 210 | replicas: 1 211 | secret: neutron-secret 212 | extraMounts: 213 | - extraVolType: Partner1 214 | volumes: 215 | - name: partner1 216 | secret: 217 | secretName: partner1-config 218 | mounts: 219 | - name: partner1 220 | mountPath: "/var/lib/neutron/third_party/partner1" 221 | readOnly: true 222 | ``` 223 | 224 | The data defined in `/var/lib/neutron/third_party/partner1` will be mounted 225 | to the resulting neutronAPI pod. 226 | 227 | # Design 228 | *TBD* 229 | 230 | # Testing 231 | The repository uses [EnvTest](https://book.kubebuilder.io/reference/envtest.html) to validate the operator in a self 232 | contained environment. 233 | 234 | The test can be run in the terminal with: 235 | ```shell 236 | make test 237 | ``` 238 | or in Visual Studio Code by defining the following in your settings.json: 239 | ```json 240 | "go.testEnvVars": { 241 | "KUBEBUILDER_ASSETS":"" 242 | }, 243 | ``` 244 | -------------------------------------------------------------------------------- /api/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/openstack-k8s-operators/neutron-operator/api 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250530085921-2b2be72badf4 7 | github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250508141203-be026d3164f7 8 | github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20250508141203-be026d3164f7 9 | k8s.io/api v0.29.15 10 | k8s.io/apimachinery v0.29.15 11 | sigs.k8s.io/controller-runtime v0.17.6 12 | ) 13 | 14 | require ( 15 | github.com/beorn7/perks v1.0.1 // indirect 16 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 17 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 18 | github.com/emicklei/go-restful/v3 v3.12.0 // indirect 19 | github.com/evanphx/json-patch/v5 v5.9.0 // indirect 20 | github.com/fsnotify/fsnotify v1.7.0 // indirect 21 | github.com/go-logr/logr v1.4.2 // indirect 22 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 23 | github.com/go-openapi/jsonreference v0.21.0 // indirect 24 | github.com/go-openapi/swag v0.23.0 // indirect 25 | github.com/gogo/protobuf v1.3.2 // indirect 26 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 27 | github.com/golang/protobuf v1.5.4 // indirect 28 | github.com/google/gnostic-models v0.6.8 // indirect 29 | github.com/google/go-cmp v0.6.0 // indirect 30 | github.com/google/gofuzz v1.2.0 // indirect 31 | github.com/google/uuid v1.6.0 // indirect 32 | github.com/imdario/mergo v0.3.16 // indirect 33 | github.com/josharian/intern v1.0.0 // indirect 34 | github.com/json-iterator/go v1.1.12 // indirect 35 | github.com/mailru/easyjson v0.7.7 // indirect 36 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 37 | github.com/modern-go/reflect2 v1.0.2 // indirect 38 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 39 | github.com/pkg/errors v0.9.1 // indirect 40 | github.com/prometheus/client_golang v1.19.0 // indirect 41 | github.com/prometheus/client_model v0.6.0 // indirect 42 | github.com/prometheus/common v0.51.1 // indirect 43 | github.com/prometheus/procfs v0.13.0 // indirect 44 | github.com/spf13/pflag v1.0.5 // indirect 45 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect 46 | golang.org/x/net v0.28.0 // indirect 47 | golang.org/x/oauth2 v0.18.0 // indirect 48 | golang.org/x/sys v0.23.0 // indirect 49 | golang.org/x/term v0.23.0 // indirect 50 | golang.org/x/text v0.17.0 // indirect 51 | golang.org/x/time v0.5.0 // indirect 52 | gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect 53 | google.golang.org/appengine v1.6.8 // indirect 54 | google.golang.org/protobuf v1.34.1 // indirect 55 | gopkg.in/inf.v0 v0.9.1 // indirect 56 | gopkg.in/yaml.v2 v2.4.0 // indirect 57 | gopkg.in/yaml.v3 v3.0.1 // indirect 58 | k8s.io/apiextensions-apiserver v0.29.15 // indirect 59 | k8s.io/client-go v0.29.15 // indirect 60 | k8s.io/component-base v0.29.15 // indirect 61 | k8s.io/klog/v2 v2.120.1 // indirect 62 | k8s.io/kube-openapi v0.0.0-20240322212309-b815d8309940 // indirect 63 | k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // 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/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 neutron v1beta1 API group 18 | // +kubebuilder:object:generate=true 19 | // +groupName=neutron.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: "neutron.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 | -------------------------------------------------------------------------------- /api/v1beta1/neutronapi_types.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 18 | 19 | import ( 20 | "github.com/openstack-k8s-operators/lib-common/modules/common/condition" 21 | "github.com/openstack-k8s-operators/lib-common/modules/common/service" 22 | "github.com/openstack-k8s-operators/lib-common/modules/common/tls" 23 | "github.com/openstack-k8s-operators/lib-common/modules/common/util" 24 | "github.com/openstack-k8s-operators/lib-common/modules/storage" 25 | topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1" 26 | "k8s.io/apimachinery/pkg/util/validation/field" 27 | corev1 "k8s.io/api/core/v1" 28 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 | 30 | ) 31 | 32 | const ( 33 | // DbSyncHash hash 34 | DbSyncHash = "dbsync" 35 | 36 | // DeploymentHash hash used to detect changes 37 | DeploymentHash = "deployment" 38 | 39 | // Container image fall-back defaults 40 | 41 | // NeutronAPIContainerImage is the fall-back container image for NeutronAPI 42 | NeutronAPIContainerImage = "quay.io/podified-antelope-centos9/openstack-neutron-server:current-podified" 43 | ) 44 | 45 | // NeutronAPISpec defines the desired state of NeutronAPI 46 | type NeutronAPISpec struct { 47 | NeutronAPISpecCore `json:",inline"` 48 | // +kubebuilder:validation:Required 49 | // NeutronAPI Container Image URL (will be set to environmental default if empty) 50 | ContainerImage string `json:"containerImage"` 51 | } 52 | 53 | // NeutronAPISpecCore - 54 | type NeutronAPISpecCore struct { 55 | // +kubebuilder:validation:Optional 56 | // +kubebuilder:default=120 57 | // +kubebuilder:validation:Minimum=1 58 | // APITimeout for HAProxy, Apache 59 | APITimeout int `json:"apiTimeout"` 60 | 61 | // +kubebuilder:validation:Optional 62 | // +kubebuilder:default=neutron 63 | // ServiceUser - optional username used for this service to register in neutron 64 | ServiceUser string `json:"serviceUser"` 65 | 66 | // +kubebuilder:validation:Required 67 | // MariaDB instance name 68 | // Right now required by the maridb-operator to get the credentials from the instance to create the DB 69 | // Might not be required in future 70 | DatabaseInstance string `json:"databaseInstance"` 71 | 72 | // +kubebuilder:validation:Optional 73 | // +kubebuilder:default=neutron 74 | // DatabaseAccount - optional MariaDBAccount CR name used for neutron DB, defaults to neutron 75 | DatabaseAccount string `json:"databaseAccount"` 76 | 77 | // +kubebuilder:validation:Required 78 | // +kubebuilder:default=rabbitmq 79 | // RabbitMQ instance name 80 | // Needed to request a transportURL that is created and used in Neutron 81 | RabbitMqClusterName string `json:"rabbitMqClusterName"` 82 | 83 | // +kubebuilder:validation:Required 84 | // +kubebuilder:default=memcached 85 | // Memcached instance name. 86 | MemcachedInstance string `json:"memcachedInstance"` 87 | 88 | // +kubebuilder:validation:Optional 89 | // +kubebuilder:default=1 90 | // +kubebuilder:validation:Maximum=32 91 | // +kubebuilder:validation:Minimum=0 92 | // Replicas of neutron API to run 93 | Replicas *int32 `json:"replicas"` 94 | 95 | // +kubebuilder:validation:Required 96 | // Secret containing OpenStack password information for NeutronPassword 97 | Secret string `json:"secret"` 98 | 99 | // +kubebuilder:validation:Optional 100 | // +kubebuilder:default={service: NeutronPassword} 101 | // PasswordSelectors - Selectors to identify the ServiceUser password from the Secret 102 | PasswordSelectors PasswordSelector `json:"passwordSelectors"` 103 | 104 | // +kubebuilder:validation:Optional 105 | // NodeSelector to target subset of worker nodes running this service 106 | NodeSelector *map[string]string `json:"nodeSelector,omitempty"` 107 | 108 | // +kubebuilder:validation:Optional 109 | // +kubebuilder:default=false 110 | // PreserveJobs - do not delete jobs after they finished e.g. to check logs 111 | PreserveJobs bool `json:"preserveJobs"` 112 | 113 | // +kubebuilder:validation:Optional 114 | // CorePlugin - Neutron core plugin to use. Using "ml2" if not set. 115 | // +kubebuilder:default="ml2" 116 | CorePlugin string `json:"corePlugin"` 117 | 118 | // +kubebuilder:validation:Optional 119 | // Ml2MechanismDrivers - list of ml2 drivers to enable. Using {"ovn"} if not set. 120 | // +kubebuilder:default={"ovn"} 121 | Ml2MechanismDrivers []string `json:"ml2MechanismDrivers"` 122 | 123 | // +kubebuilder:validation:Optional 124 | // CustomServiceConfig - customize the service config using this parameter to change service defaults, 125 | // or overwrite rendered information using raw OpenStack config format. The content gets added to 126 | // to /etc//.conf.d directory as custom.conf file. 127 | CustomServiceConfig string `json:"customServiceConfig,omitempty"` 128 | 129 | // +kubebuilder:validation:Optional 130 | // DefaultConfigOverwrite - interface to overwrite default config files like policy.yaml 131 | DefaultConfigOverwrite map[string]string `json:"defaultConfigOverwrite,omitempty"` 132 | 133 | // +kubebuilder:validation:Optional 134 | // Resources - Compute Resources required by this service (Limits/Requests). 135 | // https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ 136 | Resources corev1.ResourceRequirements `json:"resources,omitempty"` 137 | 138 | // +kubebuilder:validation:Optional 139 | // NetworkAttachments is a list of NetworkAttachment resource names to expose the services to the given network 140 | NetworkAttachments []string `json:"networkAttachments,omitempty"` 141 | 142 | // ExtraMounts containing conf files 143 | // +kubebuilder:validation:Optional 144 | ExtraMounts []NeutronExtraVolMounts `json:"extraMounts,omitempty"` 145 | 146 | // +kubebuilder:validation:Optional 147 | // Override, provides the ability to override the generated manifest of several child resources. 148 | Override APIOverrideSpec `json:"override,omitempty"` 149 | 150 | // +kubebuilder:validation:Optional 151 | // +operator-sdk:csv:customresourcedefinitions:type=spec 152 | // TLS - Parameters related to the TLS 153 | TLS NeutronApiTLS `json:"tls,omitempty"` 154 | 155 | // +kubebuilder:validation:Optional 156 | // TopologyRef to apply the Topology defined by the associated CR referenced 157 | // by name 158 | TopologyRef *topologyv1.TopoRef `json:"topologyRef,omitempty"` 159 | } 160 | 161 | type NeutronApiTLS struct { 162 | // +kubebuilder:validation:optional 163 | // +operator-sdk:csv:customresourcedefinitions:type=spec 164 | // API tls type which encapsulates for API services 165 | API tls.APIService `json:"api,omitempty"` 166 | // +kubebuilder:validation:optional 167 | // +operator-sdk:csv:customresourcedefinitions:type=spec 168 | // Secret containing CA bundle 169 | tls.Ca `json:",inline"` 170 | // +kubebuilder:validation:optional 171 | // +operator-sdk:csv:customresourcedefinitions:type=spec 172 | // Ovn GenericService - holds the secret for the OvnDb client cert 173 | Ovn tls.GenericService `json:"ovn,omitempty"` 174 | } 175 | 176 | // APIOverrideSpec to override the generated manifest of several child resources. 177 | type APIOverrideSpec struct { 178 | // Override configuration for the Service created to serve traffic to the cluster. 179 | // The key must be the endpoint type (public, internal) 180 | Service map[service.Endpoint]service.RoutedOverrideSpec `json:"service,omitempty"` 181 | } 182 | 183 | // PasswordSelector to identify the DB and AdminUser password from the Secret 184 | type PasswordSelector struct { 185 | // +kubebuilder:validation:Optional 186 | // +kubebuilder:default="NeutronPassword" 187 | // Database - Selector to get the neutron service password from the Secret 188 | Service string `json:"service"` 189 | } 190 | 191 | // NeutronAPIStatus defines the observed state of NeutronAPI 192 | type NeutronAPIStatus struct { 193 | // ReadyCount of neutron API instances 194 | ReadyCount int32 `json:"readyCount,omitempty"` 195 | 196 | // Map of hashes to track e.g. job status 197 | Hash map[string]string `json:"hash,omitempty"` 198 | 199 | // Conditions 200 | Conditions condition.Conditions `json:"conditions,omitempty" optional:"true"` 201 | 202 | // Neutron Database Hostname 203 | DatabaseHostname string `json:"databaseHostname,omitempty"` 204 | 205 | // TransportURLSecret - Secret containing RabbitMQ transportURL 206 | TransportURLSecret string `json:"transportURLSecret,omitempty"` 207 | 208 | // NetworkAttachments status of the deployment pods 209 | NetworkAttachments map[string][]string `json:"networkAttachments,omitempty"` 210 | 211 | // ObservedGeneration - the most recent generation observed for this 212 | // service. If the observed generation is less than the spec generation, 213 | // then the controller has not processed the latest changes injected by 214 | // the opentack-operator in the top-level CR (e.g. the ContainerImage) 215 | ObservedGeneration int64 `json:"observedGeneration,omitempty"` 216 | 217 | // LastAppliedTopology - the last applied Topology 218 | LastAppliedTopology *topologyv1.TopoRef `json:"lastAppliedTopology,omitempty"` 219 | } 220 | 221 | // +kubebuilder:object:root=true 222 | // +kubebuilder:subresource:status 223 | // +kubebuilder:printcolumn:name="NetworkAttachments",type="string",JSONPath=".status.networkAttachments",description="NetworkAttachments" 224 | // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[0].status",description="Status" 225 | // +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[0].message",description="Message" 226 | 227 | // NeutronAPI is the Schema for the neutronapis API 228 | type NeutronAPI struct { 229 | metav1.TypeMeta `json:",inline"` 230 | metav1.ObjectMeta `json:"metadata,omitempty"` 231 | 232 | Spec NeutronAPISpec `json:"spec,omitempty"` 233 | Status NeutronAPIStatus `json:"status,omitempty"` 234 | } 235 | 236 | // +kubebuilder:object:root=true 237 | 238 | // NeutronAPIList contains a list of NeutronAPI 239 | type NeutronAPIList struct { 240 | metav1.TypeMeta `json:",inline"` 241 | metav1.ListMeta `json:"metadata,omitempty"` 242 | Items []NeutronAPI `json:"items"` 243 | } 244 | 245 | func init() { 246 | SchemeBuilder.Register(&NeutronAPI{}, &NeutronAPIList{}) 247 | } 248 | 249 | // IsReady - returns true if service is ready to server requests 250 | func (instance NeutronAPI) IsReady() bool { 251 | // Ready when: 252 | // NeutronAPI is reconciled succcessfully 253 | return instance.Status.Conditions.IsTrue(condition.ReadyCondition) 254 | } 255 | 256 | // NeutronExtraVolMounts exposes additional parameters processed by the neutron-operator 257 | // and defines the common VolMounts structure provided by the main storage module 258 | type NeutronExtraVolMounts struct { 259 | // +kubebuilder:validation:Optional 260 | Name string `json:"name,omitempty"` 261 | // +kubebuilder:validation:Optional 262 | Region string `json:"region,omitempty"` 263 | // +kubebuilder:validation:Required 264 | VolMounts []storage.VolMounts `json:"extraVol"` 265 | } 266 | 267 | // Propagate is a function used to filter VolMounts according to the specified 268 | // PropagationType array 269 | func (c *NeutronExtraVolMounts) Propagate(svc []storage.PropagationType) []storage.VolMounts { 270 | 271 | var vl []storage.VolMounts 272 | 273 | for _, gv := range c.VolMounts { 274 | vl = append(vl, gv.Propagate(svc)...) 275 | } 276 | 277 | return vl 278 | } 279 | 280 | // RbacConditionsSet - set the conditions for the rbac object 281 | func (instance NeutronAPI) RbacConditionsSet(c *condition.Condition) { 282 | instance.Status.Conditions.Set(c) 283 | } 284 | 285 | // RbacNamespace - return the namespace 286 | func (instance NeutronAPI) RbacNamespace() string { 287 | return instance.Namespace 288 | } 289 | 290 | // RbacResourceName - return the name to be used for rbac objects (serviceaccount, role, rolebinding) 291 | func (instance NeutronAPI) RbacResourceName() string { 292 | return "neutron-" + instance.Name 293 | } 294 | 295 | func (instance NeutronAPI) IsOVNEnabled() bool { 296 | for _, driver := range instance.Spec.Ml2MechanismDrivers { 297 | // TODO: use const 298 | if driver == "ovn" { 299 | return true 300 | } 301 | } 302 | return false 303 | } 304 | 305 | // SetupDefaults - initializes any CRD field defaults based on environment variables (the defaulting mechanism itself is implemented via webhooks) 306 | func SetupDefaults() { 307 | // Acquire environmental defaults and initialize Neutron defaults with them 308 | neutronDefaults := NeutronAPIDefaults{ 309 | ContainerImageURL: util.GetEnvVar("RELATED_IMAGE_NEUTRON_API_IMAGE_URL_DEFAULT", NeutronAPIContainerImage), 310 | APITimeout: 120, 311 | } 312 | 313 | SetupNeutronAPIDefaults(neutronDefaults) 314 | } 315 | 316 | // ValidateTopology - 317 | func (instance *NeutronAPISpecCore) ValidateTopology( 318 | basePath *field.Path, 319 | namespace string, 320 | ) field.ErrorList { 321 | var allErrs field.ErrorList 322 | allErrs = append(allErrs, topologyv1.ValidateTopologyRef( 323 | instance.TopologyRef, 324 | *basePath.Child("topologyRef"), namespace)...) 325 | return allErrs 326 | } 327 | -------------------------------------------------------------------------------- /api/v1beta1/neutronapi_webhook.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 | // 18 | // Generated by: 19 | // 20 | // operator-sdk create webhook --group neutron --version v1beta1 --kind NeutronAPI --programmatic-validation --defaulting 21 | // 22 | 23 | package v1beta1 24 | 25 | import ( 26 | "fmt" 27 | 28 | "github.com/openstack-k8s-operators/lib-common/modules/common/service" 29 | apierrors "k8s.io/apimachinery/pkg/api/errors" 30 | "k8s.io/apimachinery/pkg/runtime" 31 | "k8s.io/apimachinery/pkg/util/validation/field" 32 | ctrl "sigs.k8s.io/controller-runtime" 33 | logf "sigs.k8s.io/controller-runtime/pkg/log" 34 | "sigs.k8s.io/controller-runtime/pkg/webhook" 35 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission" 36 | ) 37 | 38 | // NeutronAPIDefaults - 39 | type NeutronAPIDefaults struct { 40 | ContainerImageURL string 41 | APITimeout int 42 | } 43 | 44 | var neutronAPIDefaults NeutronAPIDefaults 45 | 46 | // log is for logging in this package. 47 | var neutronapilog = logf.Log.WithName("neutronapi-resource") 48 | 49 | // SetupNeutronAPIDefaults - initialize NeutronAPI spec defaults for use with either internal or external webhooks 50 | func SetupNeutronAPIDefaults(defaults NeutronAPIDefaults) { 51 | neutronAPIDefaults = defaults 52 | neutronapilog.Info("NeutronAPI defaults initialized", "defaults", defaults) 53 | } 54 | 55 | // SetupWebhookWithManager sets up the webhook with the Manager 56 | func (r *NeutronAPI) SetupWebhookWithManager(mgr ctrl.Manager) error { 57 | return ctrl.NewWebhookManagedBy(mgr). 58 | For(r). 59 | Complete() 60 | } 61 | 62 | //+kubebuilder:webhook:path=/mutate-neutron-openstack-org-v1beta1-neutronapi,mutating=true,failurePolicy=fail,sideEffects=None,groups=neutron.openstack.org,resources=neutronapis,verbs=create;update,versions=v1beta1,name=mneutronapi.kb.io,admissionReviewVersions=v1 63 | 64 | var _ webhook.Defaulter = &NeutronAPI{} 65 | 66 | // Default implements webhook.Defaulter so a webhook will be registered for the type 67 | func (r *NeutronAPI) Default() { 68 | neutronapilog.Info("default", "name", r.Name) 69 | 70 | r.Spec.Default() 71 | } 72 | 73 | // Default - set defaults for this NeutronAPI spec 74 | func (spec *NeutronAPISpec) Default() { 75 | // only container image validations go here 76 | if spec.ContainerImage == "" { 77 | spec.ContainerImage = neutronAPIDefaults.ContainerImageURL 78 | } 79 | spec.NeutronAPISpecCore.Default() 80 | } 81 | 82 | // Default - set defaults for this NeutronAPI spec core. This version gets used by OpenStackControlplane 83 | func (spec *NeutronAPISpecCore) Default() { 84 | if spec.APITimeout == 0 { 85 | spec.APITimeout = neutronAPIDefaults.APITimeout 86 | } 87 | } 88 | 89 | // TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. 90 | //+kubebuilder:webhook:path=/validate-neutron-openstack-org-v1beta1-neutronapi,mutating=false,failurePolicy=fail,sideEffects=None,groups=neutron.openstack.org,resources=neutronapis,verbs=create;update,versions=v1beta1,name=vneutronapi.kb.io,admissionReviewVersions=v1 91 | 92 | var _ webhook.Validator = &NeutronAPI{} 93 | 94 | // ValidateCreate implements webhook.Validator so a webhook will be registered for the type 95 | func (r *NeutronAPI) ValidateCreate() (admission.Warnings, error) { 96 | neutronapilog.Info("validate create", "name", r.Name) 97 | 98 | allErrs := field.ErrorList{} 99 | basePath := field.NewPath("spec") 100 | 101 | if err := r.Spec.ValidateCreate(basePath, r.Namespace); err != nil { 102 | allErrs = append(allErrs, err...) 103 | } 104 | 105 | if len(allErrs) != 0 { 106 | return nil, apierrors.NewInvalid(GroupVersion.WithKind("NeutronAPI").GroupKind(), r.Name, allErrs) 107 | } 108 | 109 | return nil, nil 110 | } 111 | 112 | // ValidateCreate - Exported function wrapping non-exported validate functions, 113 | // this function can be called externally to validate an NeutronAPI spec. 114 | func (r *NeutronAPISpec) ValidateCreate(basePath *field.Path, namespace string) field.ErrorList { 115 | return r.NeutronAPISpecCore.ValidateCreate(basePath, namespace) 116 | } 117 | 118 | func (r *NeutronAPISpecCore) ValidateCreate(basePath *field.Path, namespace string) field.ErrorList { 119 | var allErrs field.ErrorList 120 | 121 | // validate the service override key is valid 122 | allErrs = append(allErrs, service.ValidateRoutedOverrides(basePath.Child("override").Child("service"), r.Override.Service)...) 123 | 124 | allErrs = append(allErrs, ValidateDefaultConfigOverwrite(basePath, r.DefaultConfigOverwrite)...) 125 | 126 | // When a TopologyRef CR is referenced, fail if a different Namespace is 127 | // referenced because is not supported 128 | allErrs = append(allErrs, r.ValidateTopology(basePath, namespace)...) 129 | 130 | return allErrs 131 | } 132 | 133 | // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type 134 | func (r *NeutronAPI) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { 135 | neutronapilog.Info("validate update", "name", r.Name) 136 | 137 | oldNeutronAPI, ok := old.(*NeutronAPI) 138 | if !ok || oldNeutronAPI == nil { 139 | return nil, apierrors.NewInternalError(fmt.Errorf("unable to convert existing object")) 140 | } 141 | 142 | allErrs := field.ErrorList{} 143 | basePath := field.NewPath("spec") 144 | 145 | if err := r.Spec.ValidateUpdate(oldNeutronAPI.Spec, basePath, r.Namespace); err != nil { 146 | allErrs = append(allErrs, err...) 147 | } 148 | 149 | if len(allErrs) != 0 { 150 | return nil, apierrors.NewInvalid(GroupVersion.WithKind("NeutronAPI").GroupKind(), r.Name, allErrs) 151 | } 152 | 153 | return nil, nil 154 | } 155 | 156 | // ValidateUpdate - Exported function wrapping non-exported validate functions, 157 | // this function can be called externally to validate an neutron spec. 158 | func (spec *NeutronAPISpec) ValidateUpdate(old NeutronAPISpec, basePath *field.Path, namespace string) field.ErrorList { 159 | return spec.NeutronAPISpecCore.ValidateUpdate(old.NeutronAPISpecCore, basePath, namespace) 160 | } 161 | 162 | func (spec *NeutronAPISpecCore) ValidateUpdate(old NeutronAPISpecCore, basePath *field.Path, namespace string) field.ErrorList { 163 | var allErrs field.ErrorList 164 | 165 | // validate the service override key is valid 166 | allErrs = append(allErrs, service.ValidateRoutedOverrides(basePath.Child("override").Child("service"), spec.Override.Service)...) 167 | // validate the defaultConfigOverwrite is valid 168 | allErrs = append(allErrs, ValidateDefaultConfigOverwrite(basePath, spec.DefaultConfigOverwrite)...) 169 | 170 | // When a TopologyRef CR is referenced, fail if a different Namespace is 171 | // referenced because is not supported 172 | allErrs = append(allErrs, spec.ValidateTopology(basePath, namespace)...) 173 | 174 | return allErrs 175 | } 176 | 177 | // ValidateDelete implements webhook.Validator so a webhook will be registered for the type 178 | func (r *NeutronAPI) ValidateDelete() (admission.Warnings, error) { 179 | neutronapilog.Info("validate delete", "name", r.Name) 180 | 181 | // TODO(user): fill in your validation logic upon object deletion. 182 | return nil, nil 183 | } 184 | 185 | func (spec *NeutronAPISpec) GetDefaultRouteAnnotations() (annotations map[string]string) { 186 | return spec.NeutronAPISpecCore.GetDefaultRouteAnnotations() 187 | } 188 | 189 | func (spec *NeutronAPISpecCore) GetDefaultRouteAnnotations() (annotations map[string]string) { 190 | return map[string]string{ 191 | "haproxy.router.openshift.io/timeout": fmt.Sprintf("%ds", neutronAPIDefaults.APITimeout), 192 | } 193 | } 194 | 195 | func ValidateDefaultConfigOverwrite( 196 | basePath *field.Path, 197 | validateConfigOverwrite map[string]string, 198 | ) field.ErrorList { 199 | var errors field.ErrorList 200 | for requested := range validateConfigOverwrite { 201 | if requested != "policy.yaml" { 202 | errors = append( 203 | errors, 204 | field.Invalid( 205 | basePath.Child("defaultConfigOverwrite"), 206 | requested, 207 | "Only the following keys are valid: policy.yaml", 208 | ), 209 | ) 210 | } 211 | } 212 | return errors 213 | } 214 | 215 | // SetDefaultRouteAnnotations sets HAProxy timeout values of the route 216 | func (spec *NeutronAPISpecCore) SetDefaultRouteAnnotations(annotations map[string]string) { 217 | const haProxyAnno = "haproxy.router.openshift.io/timeout" 218 | // Use a custom annotation to flag when the operator has set the default HAProxy timeout 219 | // With the annotation func determines when to overwrite existing HAProxy timeout with the APITimeout 220 | const neutronAnno = "api.neutron.openstack.org/timeout" 221 | valNeutronAPI, okNeutronAPI := annotations[neutronAnno] 222 | valHAProxy, okHAProxy := annotations[haProxyAnno] 223 | // Human operator set the HAProxy timeout manually 224 | if (!okNeutronAPI && okHAProxy) { 225 | return 226 | } 227 | // Human operator modified the HAProxy timeout manually without removing the NeutronAPI flag 228 | if (okNeutronAPI && okHAProxy && valNeutronAPI != valHAProxy) { 229 | delete(annotations, neutronAnno) 230 | return 231 | } 232 | timeout := fmt.Sprintf("%ds", spec.APITimeout) 233 | annotations[neutronAnno] = timeout 234 | annotations[haProxyAnno] = timeout 235 | } 236 | -------------------------------------------------------------------------------- /api/v1beta1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | 3 | /* 4 | Copyright 2022. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | // Code generated by controller-gen. DO NOT EDIT. 20 | 21 | package v1beta1 22 | 23 | import ( 24 | topologyv1beta1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1" 25 | "github.com/openstack-k8s-operators/lib-common/modules/common/condition" 26 | "github.com/openstack-k8s-operators/lib-common/modules/common/service" 27 | "github.com/openstack-k8s-operators/lib-common/modules/storage" 28 | "k8s.io/apimachinery/pkg/runtime" 29 | ) 30 | 31 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 32 | func (in *APIOverrideSpec) DeepCopyInto(out *APIOverrideSpec) { 33 | *out = *in 34 | if in.Service != nil { 35 | in, out := &in.Service, &out.Service 36 | *out = make(map[service.Endpoint]service.RoutedOverrideSpec, len(*in)) 37 | for key, val := range *in { 38 | (*out)[key] = *val.DeepCopy() 39 | } 40 | } 41 | } 42 | 43 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIOverrideSpec. 44 | func (in *APIOverrideSpec) DeepCopy() *APIOverrideSpec { 45 | if in == nil { 46 | return nil 47 | } 48 | out := new(APIOverrideSpec) 49 | in.DeepCopyInto(out) 50 | return out 51 | } 52 | 53 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 54 | func (in *NeutronAPI) DeepCopyInto(out *NeutronAPI) { 55 | *out = *in 56 | out.TypeMeta = in.TypeMeta 57 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 58 | in.Spec.DeepCopyInto(&out.Spec) 59 | in.Status.DeepCopyInto(&out.Status) 60 | } 61 | 62 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NeutronAPI. 63 | func (in *NeutronAPI) DeepCopy() *NeutronAPI { 64 | if in == nil { 65 | return nil 66 | } 67 | out := new(NeutronAPI) 68 | in.DeepCopyInto(out) 69 | return out 70 | } 71 | 72 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 73 | func (in *NeutronAPI) DeepCopyObject() runtime.Object { 74 | if c := in.DeepCopy(); c != nil { 75 | return c 76 | } 77 | return nil 78 | } 79 | 80 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 81 | func (in *NeutronAPIDefaults) DeepCopyInto(out *NeutronAPIDefaults) { 82 | *out = *in 83 | } 84 | 85 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NeutronAPIDefaults. 86 | func (in *NeutronAPIDefaults) DeepCopy() *NeutronAPIDefaults { 87 | if in == nil { 88 | return nil 89 | } 90 | out := new(NeutronAPIDefaults) 91 | in.DeepCopyInto(out) 92 | return out 93 | } 94 | 95 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 96 | func (in *NeutronAPIList) DeepCopyInto(out *NeutronAPIList) { 97 | *out = *in 98 | out.TypeMeta = in.TypeMeta 99 | in.ListMeta.DeepCopyInto(&out.ListMeta) 100 | if in.Items != nil { 101 | in, out := &in.Items, &out.Items 102 | *out = make([]NeutronAPI, len(*in)) 103 | for i := range *in { 104 | (*in)[i].DeepCopyInto(&(*out)[i]) 105 | } 106 | } 107 | } 108 | 109 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NeutronAPIList. 110 | func (in *NeutronAPIList) DeepCopy() *NeutronAPIList { 111 | if in == nil { 112 | return nil 113 | } 114 | out := new(NeutronAPIList) 115 | in.DeepCopyInto(out) 116 | return out 117 | } 118 | 119 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 120 | func (in *NeutronAPIList) DeepCopyObject() runtime.Object { 121 | if c := in.DeepCopy(); c != nil { 122 | return c 123 | } 124 | return nil 125 | } 126 | 127 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 128 | func (in *NeutronAPISpec) DeepCopyInto(out *NeutronAPISpec) { 129 | *out = *in 130 | in.NeutronAPISpecCore.DeepCopyInto(&out.NeutronAPISpecCore) 131 | } 132 | 133 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NeutronAPISpec. 134 | func (in *NeutronAPISpec) DeepCopy() *NeutronAPISpec { 135 | if in == nil { 136 | return nil 137 | } 138 | out := new(NeutronAPISpec) 139 | in.DeepCopyInto(out) 140 | return out 141 | } 142 | 143 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 144 | func (in *NeutronAPISpecCore) DeepCopyInto(out *NeutronAPISpecCore) { 145 | *out = *in 146 | if in.Replicas != nil { 147 | in, out := &in.Replicas, &out.Replicas 148 | *out = new(int32) 149 | **out = **in 150 | } 151 | out.PasswordSelectors = in.PasswordSelectors 152 | if in.NodeSelector != nil { 153 | in, out := &in.NodeSelector, &out.NodeSelector 154 | *out = new(map[string]string) 155 | if **in != nil { 156 | in, out := *in, *out 157 | *out = make(map[string]string, len(*in)) 158 | for key, val := range *in { 159 | (*out)[key] = val 160 | } 161 | } 162 | } 163 | if in.Ml2MechanismDrivers != nil { 164 | in, out := &in.Ml2MechanismDrivers, &out.Ml2MechanismDrivers 165 | *out = make([]string, len(*in)) 166 | copy(*out, *in) 167 | } 168 | if in.DefaultConfigOverwrite != nil { 169 | in, out := &in.DefaultConfigOverwrite, &out.DefaultConfigOverwrite 170 | *out = make(map[string]string, len(*in)) 171 | for key, val := range *in { 172 | (*out)[key] = val 173 | } 174 | } 175 | in.Resources.DeepCopyInto(&out.Resources) 176 | if in.NetworkAttachments != nil { 177 | in, out := &in.NetworkAttachments, &out.NetworkAttachments 178 | *out = make([]string, len(*in)) 179 | copy(*out, *in) 180 | } 181 | if in.ExtraMounts != nil { 182 | in, out := &in.ExtraMounts, &out.ExtraMounts 183 | *out = make([]NeutronExtraVolMounts, len(*in)) 184 | for i := range *in { 185 | (*in)[i].DeepCopyInto(&(*out)[i]) 186 | } 187 | } 188 | in.Override.DeepCopyInto(&out.Override) 189 | in.TLS.DeepCopyInto(&out.TLS) 190 | if in.TopologyRef != nil { 191 | in, out := &in.TopologyRef, &out.TopologyRef 192 | *out = new(topologyv1beta1.TopoRef) 193 | **out = **in 194 | } 195 | } 196 | 197 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NeutronAPISpecCore. 198 | func (in *NeutronAPISpecCore) DeepCopy() *NeutronAPISpecCore { 199 | if in == nil { 200 | return nil 201 | } 202 | out := new(NeutronAPISpecCore) 203 | in.DeepCopyInto(out) 204 | return out 205 | } 206 | 207 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 208 | func (in *NeutronAPIStatus) DeepCopyInto(out *NeutronAPIStatus) { 209 | *out = *in 210 | if in.Hash != nil { 211 | in, out := &in.Hash, &out.Hash 212 | *out = make(map[string]string, len(*in)) 213 | for key, val := range *in { 214 | (*out)[key] = val 215 | } 216 | } 217 | if in.Conditions != nil { 218 | in, out := &in.Conditions, &out.Conditions 219 | *out = make(condition.Conditions, len(*in)) 220 | for i := range *in { 221 | (*in)[i].DeepCopyInto(&(*out)[i]) 222 | } 223 | } 224 | if in.NetworkAttachments != nil { 225 | in, out := &in.NetworkAttachments, &out.NetworkAttachments 226 | *out = make(map[string][]string, len(*in)) 227 | for key, val := range *in { 228 | var outVal []string 229 | if val == nil { 230 | (*out)[key] = nil 231 | } else { 232 | inVal := (*in)[key] 233 | in, out := &inVal, &outVal 234 | *out = make([]string, len(*in)) 235 | copy(*out, *in) 236 | } 237 | (*out)[key] = outVal 238 | } 239 | } 240 | if in.LastAppliedTopology != nil { 241 | in, out := &in.LastAppliedTopology, &out.LastAppliedTopology 242 | *out = new(topologyv1beta1.TopoRef) 243 | **out = **in 244 | } 245 | } 246 | 247 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NeutronAPIStatus. 248 | func (in *NeutronAPIStatus) DeepCopy() *NeutronAPIStatus { 249 | if in == nil { 250 | return nil 251 | } 252 | out := new(NeutronAPIStatus) 253 | in.DeepCopyInto(out) 254 | return out 255 | } 256 | 257 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 258 | func (in *NeutronApiTLS) DeepCopyInto(out *NeutronApiTLS) { 259 | *out = *in 260 | in.API.DeepCopyInto(&out.API) 261 | out.Ca = in.Ca 262 | in.Ovn.DeepCopyInto(&out.Ovn) 263 | } 264 | 265 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NeutronApiTLS. 266 | func (in *NeutronApiTLS) DeepCopy() *NeutronApiTLS { 267 | if in == nil { 268 | return nil 269 | } 270 | out := new(NeutronApiTLS) 271 | in.DeepCopyInto(out) 272 | return out 273 | } 274 | 275 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 276 | func (in *NeutronExtraVolMounts) DeepCopyInto(out *NeutronExtraVolMounts) { 277 | *out = *in 278 | if in.VolMounts != nil { 279 | in, out := &in.VolMounts, &out.VolMounts 280 | *out = make([]storage.VolMounts, len(*in)) 281 | for i := range *in { 282 | (*in)[i].DeepCopyInto(&(*out)[i]) 283 | } 284 | } 285 | } 286 | 287 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NeutronExtraVolMounts. 288 | func (in *NeutronExtraVolMounts) DeepCopy() *NeutronExtraVolMounts { 289 | if in == nil { 290 | return nil 291 | } 292 | out := new(NeutronExtraVolMounts) 293 | in.DeepCopyInto(out) 294 | return out 295 | } 296 | 297 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 298 | func (in *PasswordSelector) DeepCopyInto(out *PasswordSelector) { 299 | *out = *in 300 | } 301 | 302 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PasswordSelector. 303 | func (in *PasswordSelector) DeepCopy() *PasswordSelector { 304 | if in == nil { 305 | return nil 306 | } 307 | out := new(PasswordSelector) 308 | in.DeepCopyInto(out) 309 | return out 310 | } 311 | -------------------------------------------------------------------------------- /config/certmanager/certificate.yaml: -------------------------------------------------------------------------------- 1 | # The following manifests contain a self-signed issuer CR and a certificate CR. 2 | # More document can be found at https://docs.cert-manager.io 3 | # WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes. 4 | apiVersion: cert-manager.io/v1 5 | kind: Issuer 6 | metadata: 7 | labels: 8 | app.kubernetes.io/name: issuer 9 | app.kubernetes.io/instance: selfsigned-issuer 10 | app.kubernetes.io/component: certificate 11 | app.kubernetes.io/created-by: neutron-operator 12 | app.kubernetes.io/part-of: neutron-operator 13 | app.kubernetes.io/managed-by: kustomize 14 | name: selfsigned-issuer 15 | namespace: system 16 | spec: 17 | selfSigned: {} 18 | --- 19 | apiVersion: cert-manager.io/v1 20 | kind: Certificate 21 | metadata: 22 | labels: 23 | app.kubernetes.io/name: certificate 24 | app.kubernetes.io/instance: serving-cert 25 | app.kubernetes.io/component: certificate 26 | app.kubernetes.io/created-by: neutron-operator 27 | app.kubernetes.io/part-of: neutron-operator 28 | app.kubernetes.io/managed-by: kustomize 29 | name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml 30 | namespace: system 31 | spec: 32 | # $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize 33 | dnsNames: 34 | - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc 35 | - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local 36 | issuerRef: 37 | kind: Issuer 38 | name: selfsigned-issuer 39 | secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize 40 | -------------------------------------------------------------------------------- /config/certmanager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - certificate.yaml 3 | 4 | configurations: 5 | - kustomizeconfig.yaml 6 | -------------------------------------------------------------------------------- /config/certmanager/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This configuration is for teaching kustomize how to update name ref and var substitution 2 | nameReference: 3 | - kind: Issuer 4 | group: cert-manager.io 5 | fieldSpecs: 6 | - kind: Certificate 7 | group: cert-manager.io 8 | path: spec/issuerRef/name 9 | 10 | varReference: 11 | - kind: Certificate 12 | group: cert-manager.io 13 | path: spec/commonName 14 | - kind: Certificate 15 | group: cert-manager.io 16 | path: spec/dnsNames 17 | -------------------------------------------------------------------------------- /config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # This kustomization.yaml is not intended to be run by itself, 2 | # since it depends on service name and namespace that are out of this kustomize package. 3 | # It should be run by config/default 4 | resources: 5 | - bases/neutron.openstack.org_neutronapis.yaml 6 | #+kubebuilder:scaffold:crdkustomizeresource 7 | 8 | patchesStrategicMerge: 9 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. 10 | # patches here are for enabling the conversion webhook for each CRD 11 | #- patches/webhook_in_neutronapis.yaml 12 | #+kubebuilder:scaffold:crdkustomizewebhookpatch 13 | 14 | # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. 15 | # patches here are for enabling the CA injection for each CRD 16 | #- patches/cainjection_in_neutronapis.yaml 17 | #+kubebuilder:scaffold:crdkustomizecainjectionpatch 18 | 19 | # the following config is for teaching kustomize how to do kustomization for CRDs. 20 | configurations: 21 | - kustomizeconfig.yaml 22 | -------------------------------------------------------------------------------- /config/crd/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD 2 | nameReference: 3 | - kind: Service 4 | version: v1 5 | fieldSpecs: 6 | - kind: CustomResourceDefinition 7 | version: v1 8 | group: apiextensions.k8s.io 9 | path: spec/conversion/webhook/clientConfig/service/name 10 | 11 | namespace: 12 | - kind: CustomResourceDefinition 13 | version: v1 14 | group: apiextensions.k8s.io 15 | path: spec/conversion/webhook/clientConfig/service/namespace 16 | create: false 17 | 18 | varReference: 19 | - path: metadata/annotations 20 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_neutronapis.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 7 | name: neutronapis.neutron.openstack.org 8 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_neutronapis.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables a conversion webhook for the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: neutronapis.neutron.openstack.org 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: system 13 | name: webhook-service 14 | path: /convert 15 | conversionReviewVersions: 16 | - v1 17 | -------------------------------------------------------------------------------- /config/default/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Adds namespace to all resources. 2 | namespace: neutron-operator-system 3 | 4 | # Value of this field is prepended to the 5 | # names of all resources, e.g. a deployment named 6 | # "wordpress" becomes "alices-wordpress". 7 | # Note that it should also match with the prefix (text before '-') of the namespace 8 | # field above. 9 | namePrefix: neutron-operator- 10 | 11 | # Labels to add to all resources and selectors. 12 | #commonLabels: 13 | # someName: someValue 14 | 15 | bases: 16 | - ../crd 17 | - ../rbac 18 | - ../manager 19 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in 20 | # crd/kustomization.yaml 21 | - ../webhook 22 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. 23 | #- ../certmanager 24 | # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. 25 | #- ../prometheus 26 | 27 | patchesStrategicMerge: 28 | # Protect the /metrics endpoint by putting it behind auth. 29 | # If you want your controller-manager to expose the /metrics 30 | # endpoint w/o any authn/z, please comment the following line. 31 | - manager_auth_proxy_patch.yaml 32 | 33 | # Mount the controller config file for loading manager configurations 34 | # through a ComponentConfig type 35 | #- manager_config_patch.yaml 36 | 37 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in 38 | # crd/kustomization.yaml 39 | - manager_webhook_patch.yaml 40 | 41 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 42 | # Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. 43 | # 'CERTMANAGER' needs to be enabled to use ca injection 44 | #- webhookcainjection_patch.yaml 45 | 46 | # Injects our custom images (ENV variable settings) 47 | - manager_default_images.yaml 48 | 49 | # the following config is for teaching kustomize how to do var substitution 50 | vars: 51 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. 52 | #- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR 53 | # objref: 54 | # kind: Certificate 55 | # group: cert-manager.io 56 | # version: v1 57 | # name: serving-cert # this name should match the one in certificate.yaml 58 | # fieldref: 59 | # fieldpath: metadata.namespace 60 | #- name: CERTIFICATE_NAME 61 | # objref: 62 | # kind: Certificate 63 | # group: cert-manager.io 64 | # version: v1 65 | # name: serving-cert # this name should match the one in certificate.yaml 66 | #- name: SERVICE_NAMESPACE # namespace of the service 67 | # objref: 68 | # kind: Service 69 | # version: v1 70 | # name: webhook-service 71 | # fieldref: 72 | # fieldpath: metadata.namespace 73 | #- name: SERVICE_NAME 74 | # objref: 75 | # kind: Service 76 | # version: v1 77 | # name: webhook-service 78 | -------------------------------------------------------------------------------- /config/default/manager_auth_proxy_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch inject a sidecar container which is a HTTP proxy for the 2 | # controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: controller-manager 7 | namespace: system 8 | spec: 9 | template: 10 | spec: 11 | containers: 12 | - name: kube-rbac-proxy 13 | securityContext: 14 | allowPrivilegeEscalation: false 15 | # TODO(user): uncomment for common cases that do not require escalating privileges 16 | # capabilities: 17 | # drop: 18 | # - "ALL" 19 | image: quay.io/openstack-k8s-operators/kube-rbac-proxy:v0.16.0 20 | args: 21 | - "--secure-listen-address=0.0.0.0:8443" 22 | - "--upstream=http://127.0.0.1:8080/" 23 | - "--logtostderr=true" 24 | - "--v=0" 25 | ports: 26 | - containerPort: 8443 27 | protocol: TCP 28 | name: https 29 | resources: 30 | limits: 31 | cpu: 500m 32 | memory: 128Mi 33 | requests: 34 | cpu: 5m 35 | memory: 64Mi 36 | - name: manager 37 | args: 38 | - "--health-probe-bind-address=:8081" 39 | - "--metrics-bind-address=127.0.0.1:8080" 40 | - "--leader-elect" 41 | -------------------------------------------------------------------------------- /config/default/manager_config_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: manager 11 | args: 12 | - "--config=controller_manager_config.yaml" 13 | volumeMounts: 14 | - name: manager-config 15 | mountPath: /controller_manager_config.yaml 16 | subPath: controller_manager_config.yaml 17 | volumes: 18 | - name: manager-config 19 | configMap: 20 | name: manager-config 21 | -------------------------------------------------------------------------------- /config/default/manager_default_images.yaml: -------------------------------------------------------------------------------- 1 | # This patch inject custom ENV settings to the manager container 2 | # Used to set our default image locations 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: controller-manager 7 | namespace: system 8 | spec: 9 | template: 10 | spec: 11 | containers: 12 | - name: manager 13 | env: 14 | - name: RELATED_IMAGE_NEUTRON_API_IMAGE_URL_DEFAULT 15 | value: quay.io/podified-antelope-centos9/openstack-neutron-server:current-podified 16 | -------------------------------------------------------------------------------- /config/default/manager_webhook_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: manager 11 | ports: 12 | - containerPort: 9443 13 | name: webhook-server 14 | protocol: TCP 15 | volumeMounts: 16 | - mountPath: /tmp/k8s-webhook-server/serving-certs 17 | name: cert 18 | readOnly: true 19 | volumes: 20 | - name: cert 21 | secret: 22 | defaultMode: 420 23 | secretName: webhook-server-cert 24 | -------------------------------------------------------------------------------- /config/default/webhookcainjection_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch add annotation to admission webhook config and 2 | # the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize. 3 | apiVersion: admissionregistration.k8s.io/v1 4 | kind: MutatingWebhookConfiguration 5 | metadata: 6 | labels: 7 | app.kubernetes.io/name: mutatingwebhookconfiguration 8 | app.kubernetes.io/instance: mutating-webhook-configuration 9 | app.kubernetes.io/component: webhook 10 | app.kubernetes.io/created-by: neutron-operator 11 | app.kubernetes.io/part-of: neutron-operator 12 | app.kubernetes.io/managed-by: kustomize 13 | name: mutating-webhook-configuration 14 | annotations: 15 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 16 | --- 17 | apiVersion: admissionregistration.k8s.io/v1 18 | kind: ValidatingWebhookConfiguration 19 | metadata: 20 | labels: 21 | app.kubernetes.io/name: validatingwebhookconfiguration 22 | app.kubernetes.io/instance: validating-webhook-configuration 23 | app.kubernetes.io/component: webhook 24 | app.kubernetes.io/created-by: neutron-operator 25 | app.kubernetes.io/part-of: neutron-operator 26 | app.kubernetes.io/managed-by: kustomize 27 | name: validating-webhook-configuration 28 | annotations: 29 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 30 | -------------------------------------------------------------------------------- /config/manager/controller_manager_config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 2 | kind: ControllerManagerConfig 3 | health: 4 | healthProbeBindAddress: :8081 5 | metrics: 6 | bindAddress: 127.0.0.1:8080 7 | webhook: 8 | port: 9443 9 | leaderElection: 10 | leaderElect: true 11 | resourceName: 972c7522.openstack.org 12 | -------------------------------------------------------------------------------- /config/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manager.yaml 3 | 4 | generatorOptions: 5 | disableNameSuffixHash: true 6 | 7 | configMapGenerator: 8 | - files: 9 | - controller_manager_config.yaml 10 | name: manager-config 11 | apiVersion: kustomize.config.k8s.io/v1beta1 12 | kind: Kustomization 13 | images: 14 | - name: controller 15 | newName: quay.io/openstack-k8s-operators/neutron-operator 16 | newTag: latest 17 | -------------------------------------------------------------------------------- /config/manager/manager.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | openstack.org/operator-name: neutron 7 | name: system 8 | --- 9 | apiVersion: apps/v1 10 | kind: Deployment 11 | metadata: 12 | name: controller-manager 13 | namespace: system 14 | labels: 15 | control-plane: controller-manager 16 | openstack.org/operator-name: neutron 17 | spec: 18 | selector: 19 | matchLabels: 20 | openstack.org/operator-name: neutron 21 | replicas: 1 22 | template: 23 | metadata: 24 | annotations: 25 | kubectl.kubernetes.io/default-container: manager 26 | labels: 27 | control-plane: controller-manager 28 | openstack.org/operator-name: neutron 29 | spec: 30 | securityContext: 31 | runAsNonRoot: true 32 | # TODO(user): For common cases that do not require escalating privileges 33 | # it is recommended to ensure that all your Pods/Containers are restrictive. 34 | # More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted 35 | # Please uncomment the following code if your project does NOT have to work on old Kubernetes 36 | # versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ). 37 | # seccompProfile: 38 | # type: RuntimeDefault 39 | containers: 40 | - command: 41 | - /manager 42 | args: 43 | - --leader-elect 44 | image: controller:latest 45 | name: manager 46 | securityContext: 47 | allowPrivilegeEscalation: false 48 | # TODO(user): uncomment for common cases that do not require escalating privileges 49 | # capabilities: 50 | # drop: 51 | # - "ALL" 52 | livenessProbe: 53 | httpGet: 54 | path: /healthz 55 | port: 8081 56 | initialDelaySeconds: 15 57 | periodSeconds: 20 58 | readinessProbe: 59 | httpGet: 60 | path: /readyz 61 | port: 8081 62 | initialDelaySeconds: 5 63 | periodSeconds: 10 64 | # TODO(user): Configure the resources accordingly based on the project requirements. 65 | # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ 66 | resources: 67 | limits: 68 | cpu: 500m 69 | memory: 256Mi 70 | requests: 71 | cpu: 10m 72 | memory: 128Mi 73 | serviceAccountName: controller-manager 74 | terminationGracePeriodSeconds: 10 75 | -------------------------------------------------------------------------------- /config/manifests/bases/neutron-operator.clusterserviceversion.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: operators.coreos.com/v1alpha1 2 | kind: ClusterServiceVersion 3 | metadata: 4 | annotations: 5 | alm-examples: '[]' 6 | capabilities: Basic Install 7 | features.operators.openshift.io/disconnected: "true" 8 | features.operators.openshift.io/fips-compliant: "true" 9 | features.operators.openshift.io/proxy-aware: "false" 10 | features.operators.openshift.io/tls-profiles: "false" 11 | features.operators.openshift.io/token-auth-aws: "false" 12 | features.operators.openshift.io/token-auth-azure: "false" 13 | features.operators.openshift.io/token-auth-gcp: "false" 14 | operatorframework.io/suggested-namespace: openstack 15 | operators.operatorframework.io/operator-type: non-standalone 16 | name: neutron-operator.v0.0.0 17 | namespace: placeholder 18 | spec: 19 | apiservicedefinitions: {} 20 | customresourcedefinitions: 21 | owned: 22 | - description: NeutronAPI is the Schema for the neutronapis API 23 | displayName: Neutron API 24 | kind: NeutronAPI 25 | name: neutronapis.neutron.openstack.org 26 | specDescriptors: 27 | - description: TLS - Parameters related to the TLS 28 | displayName: TLS 29 | path: tls 30 | - description: API tls type which encapsulates for API services 31 | displayName: API 32 | path: tls.api 33 | - description: Ovn GenericService - holds the secret for the OvnDb client cert 34 | displayName: Ovn 35 | path: tls.ovn 36 | version: v1beta1 37 | description: Neutron Operator 38 | displayName: Neutron Operator 39 | install: 40 | spec: 41 | deployments: null 42 | strategy: "" 43 | installModes: 44 | - supported: true 45 | type: OwnNamespace 46 | - supported: true 47 | type: SingleNamespace 48 | - supported: false 49 | type: MultiNamespace 50 | - supported: true 51 | type: AllNamespaces 52 | keywords: 53 | - OpenStack 54 | - Network 55 | - Neutron 56 | links: 57 | - name: Neutron Operator 58 | url: https://github.com/openstack-k8s-operators/neutron-operator 59 | maturity: alpha 60 | provider: 61 | name: Red Hat Inc. 62 | url: https://redhat.com/ 63 | version: 0.0.0 64 | -------------------------------------------------------------------------------- /config/manifests/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # These resources constitute the fully configured set of manifests 2 | # used to generate the 'manifests/' directory in a bundle. 3 | resources: 4 | - bases/neutron-operator.clusterserviceversion.yaml 5 | - ../default 6 | - ../samples 7 | - ../scorecard 8 | 9 | # [WEBHOOK] To enable webhooks, uncomment all the sections with [WEBHOOK] prefix. 10 | # Do NOT uncomment sections with prefix [CERTMANAGER], as OLM does not support cert-manager. 11 | # These patches remove the unnecessary "cert" volume and its manager container volumeMount. 12 | #patchesJson6902: 13 | #- target: 14 | # group: apps 15 | # version: v1 16 | # kind: Deployment 17 | # name: controller-manager 18 | # namespace: system 19 | # patch: |- 20 | # # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs. 21 | # # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment. 22 | # - op: remove 23 | # path: /spec/template/spec/containers/1/volumeMounts/0 24 | # # Remove the "cert" volume, since OLM will create and mount a set of certs. 25 | # # Update the indices in this path if adding or removing volumes in the manager's Deployment. 26 | # - op: remove 27 | # path: /spec/template/spec/volumes/0 28 | -------------------------------------------------------------------------------- /config/prometheus/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - monitor.yaml 3 | -------------------------------------------------------------------------------- /config/prometheus/monitor.yaml: -------------------------------------------------------------------------------- 1 | 2 | # Prometheus Monitor Service (Metrics) 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: ServiceMonitor 5 | metadata: 6 | labels: 7 | control-plane: controller-manager 8 | name: controller-manager-metrics-monitor 9 | namespace: system 10 | spec: 11 | endpoints: 12 | - path: /metrics 13 | port: https 14 | scheme: https 15 | bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 16 | tlsConfig: 17 | insecureSkipVerify: true 18 | selector: 19 | matchLabels: 20 | openstack.org/operator-name: neutron 21 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_client_clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics-reader 5 | rules: 6 | - nonResourceURLs: 7 | - "/metrics" 8 | verbs: 9 | - get 10 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: proxy-role 5 | rules: 6 | - apiGroups: 7 | - authentication.k8s.io 8 | resources: 9 | - tokenreviews 10 | verbs: 11 | - create 12 | - apiGroups: 13 | - authorization.k8s.io 14 | resources: 15 | - subjectaccessreviews 16 | verbs: 17 | - create 18 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: proxy-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: proxy-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | name: controller-manager-metrics-service 7 | namespace: system 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | protocol: TCP 13 | targetPort: https 14 | selector: 15 | openstack.org/operator-name: neutron 16 | -------------------------------------------------------------------------------- /config/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | # All RBAC will be applied under this service account in 3 | # the deployment namespace. You may comment out this resource 4 | # if your manager will use a service account that exists at 5 | # runtime. Be sure to update RoleBinding and ClusterRoleBinding 6 | # subjects if changing service account names. 7 | - service_account.yaml 8 | - role.yaml 9 | - role_binding.yaml 10 | - leader_election_role.yaml 11 | - leader_election_role_binding.yaml 12 | # Comment the following 4 lines if you want to disable 13 | # the auth proxy (https://github.com/brancz/kube-rbac-proxy) 14 | # which protects your /metrics endpoint. 15 | - auth_proxy_service.yaml 16 | - auth_proxy_role.yaml 17 | - auth_proxy_role_binding.yaml 18 | - auth_proxy_client_clusterrole.yaml 19 | -------------------------------------------------------------------------------- /config/rbac/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: leader-election-role 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - configmaps 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - create 16 | - update 17 | - patch 18 | - delete 19 | - apiGroups: 20 | - coordination.k8s.io 21 | resources: 22 | - leases 23 | verbs: 24 | - get 25 | - list 26 | - watch 27 | - create 28 | - update 29 | - patch 30 | - delete 31 | - apiGroups: 32 | - "" 33 | resources: 34 | - events 35 | verbs: 36 | - create 37 | - patch 38 | -------------------------------------------------------------------------------- /config/rbac/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: leader-election-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: leader-election-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/rbac/neutronapi_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit neutronapis. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: neutronapi-editor-role 6 | rules: 7 | - apiGroups: 8 | - neutron.openstack.org 9 | resources: 10 | - neutronapis 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - neutron.openstack.org 21 | resources: 22 | - neutronapis/status 23 | verbs: 24 | - get 25 | -------------------------------------------------------------------------------- /config/rbac/neutronapi_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view neutronapis. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: neutronapi-viewer-role 6 | rules: 7 | - apiGroups: 8 | - neutron.openstack.org 9 | resources: 10 | - neutronapis 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - apiGroups: 16 | - neutron.openstack.org 17 | resources: 18 | - neutronapis/status 19 | verbs: 20 | - get 21 | -------------------------------------------------------------------------------- /config/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: manager-role 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - pods 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - "" 21 | resources: 22 | - serviceaccounts 23 | verbs: 24 | - create 25 | - get 26 | - list 27 | - patch 28 | - update 29 | - watch 30 | - apiGroups: 31 | - apps 32 | resources: 33 | - deployments 34 | verbs: 35 | - create 36 | - delete 37 | - get 38 | - list 39 | - patch 40 | - update 41 | - watch 42 | - apiGroups: 43 | - batch 44 | resources: 45 | - jobs 46 | verbs: 47 | - create 48 | - delete 49 | - get 50 | - list 51 | - patch 52 | - update 53 | - watch 54 | - apiGroups: 55 | - "" 56 | resources: 57 | - pods 58 | verbs: 59 | - get 60 | - list 61 | - apiGroups: 62 | - "" 63 | resources: 64 | - secrets 65 | verbs: 66 | - create 67 | - delete 68 | - get 69 | - list 70 | - patch 71 | - update 72 | - watch 73 | - apiGroups: 74 | - "" 75 | resources: 76 | - services 77 | verbs: 78 | - create 79 | - delete 80 | - get 81 | - list 82 | - patch 83 | - update 84 | - watch 85 | - apiGroups: 86 | - k8s.cni.cncf.io 87 | resources: 88 | - network-attachment-definitions 89 | verbs: 90 | - get 91 | - list 92 | - watch 93 | - apiGroups: 94 | - keystone.openstack.org 95 | resources: 96 | - keystoneapis 97 | verbs: 98 | - get 99 | - list 100 | - watch 101 | - apiGroups: 102 | - keystone.openstack.org 103 | resources: 104 | - keystoneendpoints 105 | verbs: 106 | - create 107 | - delete 108 | - get 109 | - list 110 | - patch 111 | - update 112 | - watch 113 | - apiGroups: 114 | - keystone.openstack.org 115 | resources: 116 | - keystoneservices 117 | verbs: 118 | - create 119 | - delete 120 | - get 121 | - list 122 | - patch 123 | - update 124 | - watch 125 | - apiGroups: 126 | - mariadb.openstack.org 127 | resources: 128 | - mariadbaccounts 129 | verbs: 130 | - create 131 | - delete 132 | - get 133 | - list 134 | - patch 135 | - update 136 | - watch 137 | - apiGroups: 138 | - mariadb.openstack.org 139 | resources: 140 | - mariadbaccounts/finalizers 141 | verbs: 142 | - patch 143 | - update 144 | - apiGroups: 145 | - mariadb.openstack.org 146 | resources: 147 | - mariadbdatabases 148 | verbs: 149 | - create 150 | - delete 151 | - get 152 | - list 153 | - patch 154 | - update 155 | - watch 156 | - apiGroups: 157 | - memcached.openstack.org 158 | resources: 159 | - memcacheds 160 | verbs: 161 | - get 162 | - list 163 | - watch 164 | - apiGroups: 165 | - neutron.openstack.org 166 | resources: 167 | - neutronapis 168 | verbs: 169 | - create 170 | - delete 171 | - get 172 | - list 173 | - patch 174 | - update 175 | - watch 176 | - apiGroups: 177 | - neutron.openstack.org 178 | resources: 179 | - neutronapis/finalizers 180 | verbs: 181 | - patch 182 | - update 183 | - apiGroups: 184 | - neutron.openstack.org 185 | resources: 186 | - neutronapis/status 187 | verbs: 188 | - get 189 | - patch 190 | - update 191 | - apiGroups: 192 | - ovn.openstack.org 193 | resources: 194 | - ovndbclusters 195 | verbs: 196 | - get 197 | - list 198 | - watch 199 | - apiGroups: 200 | - rabbitmq.openstack.org 201 | resources: 202 | - transporturls 203 | verbs: 204 | - create 205 | - delete 206 | - get 207 | - list 208 | - patch 209 | - update 210 | - watch 211 | - apiGroups: 212 | - rbac.authorization.k8s.io 213 | resources: 214 | - rolebindings 215 | verbs: 216 | - create 217 | - get 218 | - list 219 | - patch 220 | - update 221 | - watch 222 | - apiGroups: 223 | - rbac.authorization.k8s.io 224 | resources: 225 | - roles 226 | verbs: 227 | - create 228 | - get 229 | - list 230 | - patch 231 | - update 232 | - watch 233 | - apiGroups: 234 | - security.openshift.io 235 | resourceNames: 236 | - anyuid 237 | resources: 238 | - securitycontextconstraints 239 | verbs: 240 | - use 241 | - apiGroups: 242 | - topology.openstack.org 243 | resources: 244 | - topologies 245 | verbs: 246 | - get 247 | - list 248 | - update 249 | - watch 250 | -------------------------------------------------------------------------------- /config/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: manager-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: manager-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | -------------------------------------------------------------------------------- /config/samples/kustomization.yaml: -------------------------------------------------------------------------------- 1 | ## Append samples you want in your CSV to this file as resources ## 2 | resources: 3 | - neutron_v1beta1_neutronapi.yaml 4 | #+kubebuilder:scaffold:manifestskustomizesamples 5 | -------------------------------------------------------------------------------- /config/samples/neutron-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: neutron-secret 5 | stringData: 6 | DatabasePassword: "12345678" 7 | NeutronPassword: foobar123 8 | TransportUrl: "amqp://osp:passw0rd@amq-interconnect.openstack.svc:5672" 9 | -------------------------------------------------------------------------------- /config/samples/neutron_v1beta1_neutronapi.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: neutron.openstack.org/v1beta1 2 | kind: NeutronAPI 3 | metadata: 4 | name: neutron 5 | namespace: openstack 6 | spec: 7 | serviceUser: neutron 8 | customServiceConfig: | 9 | [DEFAULT] 10 | debug = true 11 | databaseInstance: openstack 12 | databaseAccount: neutron 13 | rabbitMqClusterName: rabbitmq 14 | memcachedInstance: memcached 15 | preserveJobs: false 16 | secret: neutron-secret 17 | -------------------------------------------------------------------------------- /config/samples/neutron_v1beta1_neutronapi_openvswitch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: neutron.openstack.org/v1beta1 2 | kind: NeutronAPI 3 | metadata: 4 | name: neutron 5 | namespace: openstack 6 | spec: 7 | serviceUser: neutron 8 | databaseInstance: openstack 9 | databaseAccount: neutron 10 | rabbitMqClusterName: rabbitmq 11 | memcachedInstance: memcached 12 | preserveJobs: false 13 | secret: neutron-secret 14 | ml2MechanismDrivers: 15 | - openvswitch 16 | -------------------------------------------------------------------------------- /config/samples/neutron_v1beta1_neutronapi_tls.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: neutron.openstack.org/v1beta1 2 | kind: NeutronAPI 3 | metadata: 4 | name: neutron 5 | namespace: openstack 6 | spec: 7 | serviceUser: neutron 8 | customServiceConfig: | 9 | [DEFAULT] 10 | debug = true 11 | databaseInstance: openstack 12 | databaseAccount: neutron 13 | rabbitMqClusterName: rabbitmq 14 | memcachedInstance: memcached 15 | preserveJobs: false 16 | secret: neutron-secret 17 | tls: 18 | api: 19 | # secret holding tls.crt and tls.key for the APIs internal k8s service 20 | internal: 21 | secretName: cert-neutron-internal-svc 22 | # secret holding tls.crt and tls.key for the APIs public k8s service 23 | public: 24 | secretName: cert-neutron-public-svc 25 | # secret holding the tls-ca-bundle.pem to be used as a deploymend env CA bundle 26 | caBundleSecretName: combined-ca-bundle 27 | -------------------------------------------------------------------------------- /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.22.2 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.22.2 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.22.2 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.22.2 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.22.2 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.22.2 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/manifests.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: admissionregistration.k8s.io/v1 3 | kind: MutatingWebhookConfiguration 4 | metadata: 5 | name: mutating-webhook-configuration 6 | webhooks: 7 | - admissionReviewVersions: 8 | - v1 9 | clientConfig: 10 | service: 11 | name: webhook-service 12 | namespace: system 13 | path: /mutate-neutron-openstack-org-v1beta1-neutronapi 14 | failurePolicy: Fail 15 | name: mneutronapi.kb.io 16 | rules: 17 | - apiGroups: 18 | - neutron.openstack.org 19 | apiVersions: 20 | - v1beta1 21 | operations: 22 | - CREATE 23 | - UPDATE 24 | resources: 25 | - neutronapis 26 | sideEffects: None 27 | --- 28 | apiVersion: admissionregistration.k8s.io/v1 29 | kind: ValidatingWebhookConfiguration 30 | metadata: 31 | name: validating-webhook-configuration 32 | webhooks: 33 | - admissionReviewVersions: 34 | - v1 35 | clientConfig: 36 | service: 37 | name: webhook-service 38 | namespace: system 39 | path: /validate-neutron-openstack-org-v1beta1-neutronapi 40 | failurePolicy: Fail 41 | name: vneutronapi.kb.io 42 | rules: 43 | - apiGroups: 44 | - neutron.openstack.org 45 | apiVersions: 46 | - v1beta1 47 | operations: 48 | - CREATE 49 | - UPDATE 50 | resources: 51 | - neutronapis 52 | sideEffects: None 53 | -------------------------------------------------------------------------------- /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: neutron-operator 10 | app.kubernetes.io/part-of: neutron-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: 9443 19 | selector: 20 | openstack.org/operator-name: neutron 21 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/openstack-k8s-operators/neutron-operator 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/go-logr/logr v1.4.2 7 | github.com/google/uuid v1.6.0 8 | github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.7.6 9 | github.com/onsi/ginkgo/v2 v2.20.1 10 | github.com/onsi/gomega v1.34.1 11 | github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20250530085921-2b2be72badf4 12 | github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20250528115713-faa7ebf8f7fc 13 | github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20250508141203-be026d3164f7 14 | github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20250508141203-be026d3164f7 15 | github.com/openstack-k8s-operators/lib-common/modules/test v0.6.1-0.20250508141203-be026d3164f7 16 | github.com/openstack-k8s-operators/mariadb-operator/api v0.6.1-0.20250524131103-7ebaceec882b 17 | github.com/openstack-k8s-operators/neutron-operator/api v0.0.0-00010101000000-000000000000 18 | github.com/openstack-k8s-operators/ovn-operator/api v0.6.1-0.20250514092209-affa224e4cad 19 | go.uber.org/zap v1.27.0 20 | k8s.io/api v0.29.15 21 | k8s.io/apimachinery v0.29.15 22 | k8s.io/client-go v0.29.15 23 | k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 24 | sigs.k8s.io/controller-runtime v0.17.6 25 | ) 26 | 27 | require ( 28 | github.com/beorn7/perks v1.0.1 // indirect 29 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 30 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 31 | github.com/emicklei/go-restful/v3 v3.12.0 // indirect 32 | github.com/evanphx/json-patch/v5 v5.9.0 // indirect 33 | github.com/fsnotify/fsnotify v1.7.0 // indirect 34 | github.com/go-logr/zapr v1.3.0 // indirect 35 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 36 | github.com/go-openapi/jsonreference v0.21.0 // indirect 37 | github.com/go-openapi/swag v0.23.0 // indirect 38 | github.com/go-task/slim-sprig/v3 v3.0.0 // indirect 39 | github.com/gogo/protobuf v1.3.2 // indirect 40 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 41 | github.com/golang/protobuf v1.5.4 // indirect 42 | github.com/google/gnostic-models v0.6.8 // indirect 43 | github.com/google/go-cmp v0.6.0 // indirect 44 | github.com/google/gofuzz v1.2.0 // indirect 45 | github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect 46 | github.com/gophercloud/gophercloud v1.14.1 // indirect 47 | github.com/imdario/mergo v0.3.16 // indirect 48 | github.com/josharian/intern v1.0.0 // indirect 49 | github.com/json-iterator/go v1.1.12 // indirect 50 | github.com/mailru/easyjson v0.7.7 // indirect 51 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 52 | github.com/modern-go/reflect2 v1.0.2 // indirect 53 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 54 | github.com/openshift/api v3.9.0+incompatible // indirect 55 | github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20250508141203-be026d3164f7 // indirect 56 | github.com/pkg/errors v0.9.1 // indirect 57 | github.com/prometheus/client_golang v1.19.0 // indirect 58 | github.com/prometheus/client_model v0.6.0 // indirect 59 | github.com/prometheus/common v0.51.1 // indirect 60 | github.com/prometheus/procfs v0.13.0 // indirect 61 | github.com/rabbitmq/cluster-operator/v2 v2.9.0 // indirect 62 | github.com/spf13/pflag v1.0.5 // indirect 63 | go.uber.org/multierr v1.11.0 // indirect 64 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect 65 | golang.org/x/mod v0.20.0 // indirect 66 | golang.org/x/net v0.28.0 // indirect 67 | golang.org/x/oauth2 v0.18.0 // indirect 68 | golang.org/x/sys v0.23.0 // indirect 69 | golang.org/x/term v0.23.0 // indirect 70 | golang.org/x/text v0.17.0 // indirect 71 | golang.org/x/time v0.5.0 // indirect 72 | golang.org/x/tools v0.24.0 // indirect 73 | gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect 74 | google.golang.org/appengine v1.6.8 // indirect 75 | google.golang.org/protobuf v1.34.1 // indirect 76 | gopkg.in/inf.v0 v0.9.1 // indirect 77 | gopkg.in/yaml.v2 v2.4.0 // indirect 78 | gopkg.in/yaml.v3 v3.0.1 // 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/neutron-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 vneutronapi.kb.io --ignore-not-found 5 | oc delete mutatingwebhookconfiguration mneutronapi.kb.io --ignore-not-found 6 | -------------------------------------------------------------------------------- /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/run_with_local_webhook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Define a cleanup function 4 | cleanup() { 5 | echo "Caught signal, cleaning up local webhooks..." 6 | ./hack/clean_local_webhook.sh 7 | exit 0 8 | } 9 | 10 | # Set trap to catch SIGINT and SIGTERM 11 | trap cleanup SIGINT SIGTERM 12 | 13 | #!/bin/bash 14 | set -ex 15 | 16 | TMPDIR=${TMPDIR:-"/tmp/k8s-webhook-server/serving-certs"} 17 | SKIP_CERT=${SKIP_CERT:-false} 18 | CRC_IP=${CRC_IP:-$(/sbin/ip -o -4 addr list crc | awk '{print $4}' | cut -d/ -f1)} 19 | FIREWALL_ZONE=${FIREWALL_ZONE:-"libvirt"} 20 | 21 | #Open 9443 22 | if command -v firewall-cmd &> /dev/null; then 23 | sudo firewall-cmd --zone="${FIREWALL_ZONE}" --add-port=9443/tcp 24 | sudo firewall-cmd --runtime-to-permanent 25 | fi 26 | 27 | # Generate the certs and the ca bundle 28 | if [ "$SKIP_CERT" = false ] ; then 29 | mkdir -p "${TMPDIR}" 30 | rm -rf "${TMPDIR}"/* || true 31 | 32 | openssl req -newkey rsa:2048 -days 3650 -nodes -x509 \ 33 | -subj "/CN=${HOSTNAME}" \ 34 | -addext "subjectAltName = IP:${CRC_IP}" \ 35 | -keyout "${TMPDIR}"/tls.key \ 36 | -out "${TMPDIR}"/tls.crt 37 | 38 | cat "${TMPDIR}"/tls.crt "${TMPDIR}"/tls.key | base64 -w 0 > "${TMPDIR}"/bundle.pem 39 | fi 40 | 41 | CA_BUNDLE=$(cat "${TMPDIR}"/bundle.pem) 42 | 43 | # Patch the webhook(s) 44 | cat >> "${TMPDIR}"/patch_webhook_configurations.yaml < "${CSV_FILE}" 116 | 117 | printf \ 118 | "\n\tNow patching operator CSV to remove its OLM deployment and associated webhooks. 119 | The original OLM version of the operator's CSV has been copied to %s. To restore it, use: 120 | oc patch -n openstack-operators %s --type=merge --patch-file=%s\n\n" "${CSV_FILE}" "${CSV_NAME}" "${CSV_FILE}" 121 | fi 122 | 123 | oc patch "${CSV_NAME}" -n openstack-operators --type=json -p="[{'op': 'replace', 'path': '/spec/install/spec/deployments/0/spec/replicas', 'value': 0}]" 124 | oc patch "${CSV_NAME}" -n openstack-operators --type=json -p="[{'op': 'replace', 'path': '/spec/webhookdefinitions', 'value': []}]" 125 | else 126 | # Handle operator deployed by Openstack Initialization resource 127 | CSV_NAME="$(oc get csv -n openstack-operators -l operators.coreos.com/openstack-operator.openstack-operators -o name)" 128 | 129 | printf \ 130 | "\n\tNow patching openstack operator CSV to scale down deployment resource. 131 | To restore it, use: 132 | oc patch "${CSV_NAME}" -n openstack-operators --type=json -p=\"[{'op': 'replace', 'path': '/spec/install/spec/deployments/0/spec/replicas', 'value': 1}]\"" 133 | 134 | oc patch "${CSV_NAME}" -n openstack-operators --type=json -p="[{'op': 'replace', 'path': '/spec/install/spec/deployments/0/spec/replicas', 'value': 0}]" 135 | oc scale --replicas=0 -n openstack-operators deploy/neutron-operator-controller-manager 136 | fi 137 | 138 | go run ./main.go -metrics-bind-address ":${METRICS_PORT}" -health-probe-bind-address ":${HEALTH_PORT}" 139 | -------------------------------------------------------------------------------- /kuttl-test.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # EXECUTION (from install_yamls repo root): 3 | # 4 | # make neutron_kuttl 5 | # 6 | # ASSUMPTIONS: 7 | # 8 | # 1. Latest version of kuttl is installed at /usr/local/bin/kubectl-kuttl 9 | # - wget https://github.com/kudobuilder/kuttl/releases/download/v0.11.1/kubectl-kuttl_0.11.1_linux_x86_64 10 | # - mv kubectl-kuttl_0.11.1_linux_x86_64 /usr/local/bin/kubectl-kuttl 11 | # - chmod 755 /usr/local/bin/kubectl-kuttl 12 | # 2. An OCP 4.10+ CRC cluster with Podified Operators has been deployed 13 | # 3. CLI user has access to $KUBECONFIG 14 | # 4. The environment variable INSTALL_YAMLS is set to the the path of the 15 | # install_yamls repo 16 | 17 | apiVersion: kuttl.dev/v1beta1 18 | kind: TestSuite 19 | namespace: neutron-kuttl-tests 20 | reportFormat: JSON 21 | reportName: kuttl-test-neutron 22 | timeout: 180 23 | parallel: 1 24 | suppress: 25 | - events # Remove spammy event logs 26 | -------------------------------------------------------------------------------- /main.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 main 18 | 19 | import ( 20 | "context" 21 | "crypto/tls" 22 | "flag" 23 | "os" 24 | "strings" 25 | 26 | // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) 27 | // to ensure that exec-entrypoint and run can make use of them. 28 | _ "k8s.io/client-go/plugin/pkg/client/auth" 29 | 30 | "go.uber.org/zap/zapcore" 31 | 32 | "k8s.io/apimachinery/pkg/runtime" 33 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 34 | "k8s.io/client-go/kubernetes" 35 | clientgoscheme "k8s.io/client-go/kubernetes/scheme" 36 | ctrl "sigs.k8s.io/controller-runtime" 37 | "sigs.k8s.io/controller-runtime/pkg/client/config" 38 | "sigs.k8s.io/controller-runtime/pkg/healthz" 39 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 40 | "sigs.k8s.io/controller-runtime/pkg/webhook" 41 | 42 | metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" 43 | 44 | networkv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" 45 | memcachedv1 "github.com/openstack-k8s-operators/infra-operator/apis/memcached/v1beta1" 46 | rabbitmqv1 "github.com/openstack-k8s-operators/infra-operator/apis/rabbitmq/v1beta1" 47 | topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1" 48 | keystonev1beta1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1" 49 | "github.com/openstack-k8s-operators/lib-common/modules/common/operator" 50 | mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" 51 | ovnv1alpha1 "github.com/openstack-k8s-operators/ovn-operator/api/v1beta1" 52 | 53 | neutronv1beta1 "github.com/openstack-k8s-operators/neutron-operator/api/v1beta1" 54 | "github.com/openstack-k8s-operators/neutron-operator/controllers" 55 | //+kubebuilder:scaffold:imports 56 | ) 57 | 58 | var ( 59 | scheme = runtime.NewScheme() 60 | setupLog = ctrl.Log.WithName("setup") 61 | ) 62 | 63 | func init() { 64 | utilruntime.Must(clientgoscheme.AddToScheme(scheme)) 65 | 66 | utilruntime.Must(keystonev1beta1.AddToScheme(scheme)) 67 | utilruntime.Must(mariadbv1.AddToScheme(scheme)) 68 | utilruntime.Must(memcachedv1.AddToScheme(scheme)) 69 | utilruntime.Must(rabbitmqv1.AddToScheme(scheme)) 70 | utilruntime.Must(ovnv1alpha1.AddToScheme(scheme)) 71 | 72 | utilruntime.Must(neutronv1beta1.AddToScheme(scheme)) 73 | utilruntime.Must(networkv1.AddToScheme(scheme)) 74 | utilruntime.Must(topologyv1.AddToScheme(scheme)) 75 | //+kubebuilder:scaffold:scheme 76 | } 77 | 78 | func main() { 79 | var metricsAddr string 80 | var enableLeaderElection bool 81 | var probeAddr string 82 | var enableHTTP2 bool 83 | flag.BoolVar(&enableHTTP2, "enable-http2", enableHTTP2, "If HTTP/2 should be enabled for the metrics and webhook servers.") 84 | flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") 85 | flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") 86 | flag.BoolVar(&enableLeaderElection, "leader-elect", false, 87 | "Enable leader election for controller manager. "+ 88 | "Enabling this will ensure there is only one active controller manager.") 89 | opts := zap.Options{ 90 | Development: true, 91 | TimeEncoder: zapcore.ISO8601TimeEncoder, 92 | } 93 | opts.BindFlags(flag.CommandLine) 94 | flag.Parse() 95 | 96 | ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) 97 | 98 | disableHTTP2 := func(c *tls.Config) { 99 | if enableHTTP2 { 100 | return 101 | } 102 | c.NextProtos = []string{"http/1.1"} 103 | } 104 | 105 | options := ctrl.Options{ 106 | Scheme: scheme, 107 | Metrics: metricsserver.Options{ 108 | BindAddress: metricsAddr, 109 | }, 110 | HealthProbeBindAddress: probeAddr, 111 | LeaderElection: enableLeaderElection, 112 | LeaderElectionID: "972c7522.openstack.org", 113 | WebhookServer: webhook.NewServer( 114 | webhook.Options{ 115 | Port: 9443, 116 | TLSOpts: []func(config *tls.Config){disableHTTP2}, 117 | }), 118 | // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily 119 | // when the Manager ends. This requires the binary to immediately end when the 120 | // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly 121 | // speeds up voluntary leader transitions as the new leader don't have to wait 122 | // LeaseDuration time first. 123 | // 124 | // In the default scaffold provided, the program ends immediately after 125 | // the manager stops, so would be fine to enable this option. However, 126 | // if you are doing or is intended to do any operation such as perform cleanups 127 | // after the manager stops then its usage might be unsafe. 128 | // LeaderElectionReleaseOnCancel: true, 129 | } 130 | 131 | err := operator.SetManagerOptions(&options, setupLog) 132 | if err != nil { 133 | setupLog.Error(err, "unable to set manager options") 134 | os.Exit(1) 135 | } 136 | 137 | mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), options) 138 | if err != nil { 139 | setupLog.Error(err, "unable to start manager") 140 | os.Exit(1) 141 | } 142 | cfg, err := config.GetConfig() 143 | if err != nil { 144 | setupLog.Error(err, "") 145 | os.Exit(1) 146 | } 147 | kclient, err := kubernetes.NewForConfig(cfg) 148 | if err != nil { 149 | setupLog.Error(err, "") 150 | os.Exit(1) 151 | } 152 | if err = (&controllers.NeutronAPIReconciler{ 153 | Client: mgr.GetClient(), 154 | Scheme: mgr.GetScheme(), 155 | Kclient: kclient, 156 | }).SetupWithManager(context.Background(), mgr); err != nil { 157 | setupLog.Error(err, "unable to create controller", "controller", "NeutronAPI") 158 | os.Exit(1) 159 | } 160 | 161 | // Acquire environmental defaults and initialize operator defaults with them 162 | neutronv1beta1.SetupDefaults() 163 | 164 | // Setup webhooks if requested 165 | checker := healthz.Ping 166 | if strings.ToLower(os.Getenv("ENABLE_WEBHOOKS")) != "false" { 167 | 168 | if err = (&neutronv1beta1.NeutronAPI{}).SetupWebhookWithManager(mgr); err != nil { 169 | setupLog.Error(err, "unable to create webhook", "webhook", "NeutronAPI") 170 | os.Exit(1) 171 | } 172 | checker = mgr.GetWebhookServer().StartedChecker() 173 | } 174 | 175 | //+kubebuilder:scaffold:builder 176 | 177 | if err := mgr.AddHealthzCheck("healthz", checker); err != nil { 178 | setupLog.Error(err, "unable to set up health check") 179 | os.Exit(1) 180 | } 181 | if err := mgr.AddReadyzCheck("readyz", checker); err != nil { 182 | setupLog.Error(err, "unable to set up ready check") 183 | os.Exit(1) 184 | } 185 | 186 | setupLog.Info("starting manager") 187 | if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { 188 | setupLog.Error(err, "problem running manager") 189 | os.Exit(1) 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /pkg/neutronapi/const.go: -------------------------------------------------------------------------------- 1 | package neutronapi 2 | 3 | import ( 4 | "github.com/openstack-k8s-operators/lib-common/modules/storage" 5 | ) 6 | 7 | const ( 8 | // ServiceName - 9 | ServiceName = "neutron" 10 | // ServiceType - 11 | ServiceType = "network" 12 | // Database - Name of the database used in CREATE DATABASE statement 13 | Database = "neutron" 14 | 15 | // DatabaseCRName - Name of the MariaDBDatabase CR 16 | DatabaseCRName = "neutron" 17 | 18 | // DatabaseUsernamePrefix - used by EnsureMariaDBAccount when a new username 19 | // is to be generated, e.g. "neutron_e5a4", "neutron_78bc", etc 20 | DatabaseUsernamePrefix = "neutron" 21 | 22 | // neutron:neutron 23 | NeutronUID int64 = 42435 24 | NeutronGID int64 = 42435 25 | 26 | // NeutronPublicPort - 27 | NeutronPublicPort int32 = 9696 28 | // NeutronInternalPort - 29 | NeutronInternalPort int32 = 9696 30 | 31 | // NeutronExtraVolTypeUndefined can be used to label an extraMount which 32 | // is not associated with a specific backend 33 | NeutronExtraVolTypeUndefined storage.ExtraVolType = "Undefined" 34 | // NeutronAPI is the definition of the neutron-api group 35 | NeutronAPI storage.PropagationType = "NeutronAPI" 36 | // Neutron is the global ServiceType that refers to all the components deployed 37 | // by the neutron-operator 38 | Neutron storage.PropagationType = "Neutron" 39 | 40 | // Key in external Secret for Neutron OVN Metadata Agent with agent config 41 | NeutronOVNMetadataAgentSecretKey = "10-neutron-metadata.conf" 42 | 43 | // Key in external Secret for Neutron OVN Agent with agent config 44 | NeutronOVNAgentSecretKey = "10-neutron-ovn.conf" // #nosec 45 | 46 | // Key in external Secret for Neutron SR-IOV Agent with agent config 47 | NeutronSriovAgentSecretKey = "10-neutron-sriov.conf" 48 | 49 | // Key in external Secret for Neutron DHCP Agent with agent config 50 | NeutronDhcpAgentSecretKey = "10-neutron-dhcp.conf" 51 | ) 52 | 53 | // DbsyncPropagation keeps track of the DBSync Service Propagation Type 54 | var DbsyncPropagation = []storage.PropagationType{storage.DBSync} 55 | 56 | // NeutronAPIPropagation is the definition of the NeutronAPI propagation group 57 | // It allows the NeutronAPI pod to mount volumes destined to Neutron and NeutronAPI 58 | // ServiceTypes 59 | var NeutronAPIPropagation = []storage.PropagationType{Neutron, NeutronAPI} 60 | -------------------------------------------------------------------------------- /pkg/neutronapi/dbsync.go: -------------------------------------------------------------------------------- 1 | package neutronapi 2 | 3 | import ( 4 | "github.com/openstack-k8s-operators/lib-common/modules/common/env" 5 | neutronv1beta1 "github.com/openstack-k8s-operators/neutron-operator/api/v1beta1" 6 | batchv1 "k8s.io/api/batch/v1" 7 | corev1 "k8s.io/api/core/v1" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | // DbSyncJob func 12 | func DbSyncJob( 13 | cr *neutronv1beta1.NeutronAPI, 14 | labels map[string]string, 15 | annotations map[string]string, 16 | ) *batchv1.Job { 17 | dbSyncExtraMounts := []neutronv1beta1.NeutronExtraVolMounts{} 18 | 19 | volumes := GetVolumes(cr.Name, dbSyncExtraMounts, DbsyncPropagation) 20 | volumeMounts := GetVolumeMounts("db-sync", dbSyncExtraMounts, DbsyncPropagation) 21 | 22 | // add CA cert if defined 23 | if cr.Spec.TLS.CaBundleSecretName != "" { 24 | volumes = append(volumes, cr.Spec.TLS.CreateVolume()) 25 | volumeMounts = append(volumeMounts, cr.Spec.TLS.CreateVolumeMounts(nil)...) 26 | } 27 | 28 | envVars := map[string]env.Setter{} 29 | envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") 30 | 31 | job := &batchv1.Job{ 32 | ObjectMeta: metav1.ObjectMeta{ 33 | Name: cr.Name + "-db-sync", 34 | Namespace: cr.Namespace, 35 | Annotations: annotations, 36 | Labels: labels, 37 | }, 38 | Spec: batchv1.JobSpec{ 39 | Template: corev1.PodTemplateSpec{ 40 | Spec: corev1.PodSpec{ 41 | RestartPolicy: corev1.RestartPolicyOnFailure, 42 | ServiceAccountName: cr.RbacResourceName(), 43 | Containers: []corev1.Container{ 44 | { 45 | Name: cr.Name + "-db-sync", 46 | Image: cr.Spec.ContainerImage, 47 | SecurityContext: getNeutronSecurityContext(), 48 | Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), 49 | VolumeMounts: volumeMounts, 50 | }, 51 | }, 52 | Volumes: volumes, 53 | }, 54 | }, 55 | }, 56 | } 57 | 58 | if cr.Spec.NodeSelector != nil { 59 | job.Spec.Template.Spec.NodeSelector = *cr.Spec.NodeSelector 60 | } 61 | 62 | return job 63 | } 64 | -------------------------------------------------------------------------------- /pkg/neutronapi/deployment.go: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | */ 12 | 13 | package neutronapi 14 | 15 | import ( 16 | "fmt" 17 | 18 | topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1" 19 | "github.com/openstack-k8s-operators/lib-common/modules/common" 20 | "github.com/openstack-k8s-operators/lib-common/modules/common/affinity" 21 | "github.com/openstack-k8s-operators/lib-common/modules/common/env" 22 | "github.com/openstack-k8s-operators/lib-common/modules/common/service" 23 | "github.com/openstack-k8s-operators/lib-common/modules/common/tls" 24 | neutronv1 "github.com/openstack-k8s-operators/neutron-operator/api/v1beta1" 25 | 26 | appsv1 "k8s.io/api/apps/v1" 27 | corev1 "k8s.io/api/core/v1" 28 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 | "k8s.io/apimachinery/pkg/util/intstr" 30 | "k8s.io/utils/ptr" 31 | ) 32 | 33 | const ( 34 | ServiceCommand = "/usr/local/bin/kolla_start" 35 | ) 36 | 37 | // Deployment func 38 | func Deployment( 39 | instance *neutronv1.NeutronAPI, 40 | configHash string, 41 | labels map[string]string, 42 | annotations map[string]string, 43 | topology *topologyv1.Topology, 44 | ) (*appsv1.Deployment, error) { 45 | // TODO(lucasagomes): Look into how to implement separated probes 46 | // for the httpd and neutron-api containers. Right now the code uses 47 | // the same liveness and readiness probes for both containers which 48 | // only checks the port 9696 (NeutronPublicPort) which is the port 49 | // that httpd is listening to. Ideally, we should also include a 50 | // probe on port 9697 which is the port that neutron-api binds to 51 | livenessProbe := &corev1.Probe{ 52 | TimeoutSeconds: 30, 53 | PeriodSeconds: 30, 54 | InitialDelaySeconds: 5, 55 | } 56 | readinessProbe := &corev1.Probe{ 57 | TimeoutSeconds: 30, 58 | PeriodSeconds: 30, 59 | InitialDelaySeconds: 5, 60 | } 61 | args := []string{"-c", ServiceCommand} 62 | 63 | // 64 | // https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ 65 | // 66 | livenessProbe.HTTPGet = &corev1.HTTPGetAction{ 67 | Path: "/", 68 | Port: intstr.IntOrString{Type: intstr.Int, IntVal: int32(NeutronPublicPort)}, 69 | } 70 | readinessProbe.HTTPGet = &corev1.HTTPGetAction{ 71 | Path: "/", 72 | Port: intstr.IntOrString{Type: intstr.Int, IntVal: int32(NeutronPublicPort)}, 73 | } 74 | 75 | if instance.Spec.TLS.API.Enabled(service.EndpointPublic) { 76 | livenessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS 77 | readinessProbe.HTTPGet.Scheme = corev1.URISchemeHTTPS 78 | } 79 | 80 | envVars := map[string]env.Setter{} 81 | envVars["KOLLA_CONFIG_STRATEGY"] = env.SetValue("COPY_ALWAYS") 82 | envVars["CONFIG_HASH"] = env.SetValue(configHash) 83 | 84 | // create Volume and VolumeMounts 85 | volumes := GetVolumes(instance.Name, instance.Spec.ExtraMounts, NeutronAPIPropagation) 86 | apiVolumeMounts := GetVolumeMounts("neutron-api", instance.Spec.ExtraMounts, NeutronAPIPropagation) 87 | httpdVolumeMounts := GetHttpdVolumeMount() 88 | 89 | // add CA cert if defined 90 | if instance.Spec.TLS.CaBundleSecretName != "" { 91 | volumes = append(volumes, instance.Spec.TLS.CreateVolume()) 92 | apiVolumeMounts = append(apiVolumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) 93 | httpdVolumeMounts = append(httpdVolumeMounts, instance.Spec.TLS.CreateVolumeMounts(nil)...) 94 | } 95 | 96 | for _, endpt := range []service.Endpoint{service.EndpointInternal, service.EndpointPublic} { 97 | if instance.Spec.TLS.API.Enabled(endpt) { 98 | var tlsEndptCfg tls.GenericService 99 | switch endpt { 100 | case service.EndpointPublic: 101 | tlsEndptCfg = instance.Spec.TLS.API.Public 102 | case service.EndpointInternal: 103 | tlsEndptCfg = instance.Spec.TLS.API.Internal 104 | } 105 | 106 | svc, err := tlsEndptCfg.ToService() 107 | if err != nil { 108 | return nil, err 109 | } 110 | // httpd container is not using kolla, mount the certs to its dst 111 | svc.CertMount = ptr.To(fmt.Sprintf("/etc/pki/tls/certs/%s.crt", endpt.String())) 112 | svc.KeyMount = ptr.To(fmt.Sprintf("/etc/pki/tls/private/%s.key", endpt.String())) 113 | 114 | volumes = append(volumes, svc.CreateVolume(endpt.String())) 115 | httpdVolumeMounts = append(httpdVolumeMounts, svc.CreateVolumeMounts(endpt.String())...) 116 | } 117 | } 118 | 119 | if instance.IsOVNEnabled() && instance.Spec.TLS.Ovn.Enabled() { 120 | svc := tls.Service{ 121 | SecretName: *instance.Spec.TLS.Ovn.SecretName, 122 | CaMount: ptr.To("/var/lib/config-data/tls/certs/ovndbca.crt"), 123 | } 124 | volumes = append(volumes, svc.CreateVolume("ovndb")) 125 | apiVolumeMounts = append(apiVolumeMounts, svc.CreateVolumeMounts("ovndb")...) 126 | } 127 | 128 | deployment := &appsv1.Deployment{ 129 | ObjectMeta: metav1.ObjectMeta{ 130 | Name: ServiceName, 131 | Namespace: instance.Namespace, 132 | }, 133 | Spec: appsv1.DeploymentSpec{ 134 | Selector: &metav1.LabelSelector{ 135 | MatchLabels: labels, 136 | }, 137 | Replicas: instance.Spec.Replicas, 138 | Template: corev1.PodTemplateSpec{ 139 | ObjectMeta: metav1.ObjectMeta{ 140 | Annotations: annotations, 141 | Labels: labels, 142 | }, 143 | Spec: corev1.PodSpec{ 144 | SecurityContext: &corev1.PodSecurityContext{ 145 | FSGroup: ptr.To(NeutronUID), 146 | }, 147 | ServiceAccountName: instance.RbacResourceName(), 148 | Containers: []corev1.Container{ 149 | { 150 | Name: ServiceName + "-api", 151 | Command: []string{"/bin/bash"}, 152 | Args: args, 153 | Image: instance.Spec.ContainerImage, 154 | SecurityContext: getNeutronSecurityContext(), 155 | Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), 156 | VolumeMounts: apiVolumeMounts, 157 | Resources: instance.Spec.Resources, 158 | LivenessProbe: livenessProbe, 159 | TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError, 160 | }, 161 | { 162 | Name: ServiceName + "-httpd", 163 | Command: []string{"/bin/bash"}, 164 | Args: args, 165 | Image: instance.Spec.ContainerImage, 166 | SecurityContext: getNeutronSecurityContext(), 167 | Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), 168 | VolumeMounts: httpdVolumeMounts, 169 | Resources: instance.Spec.Resources, 170 | ReadinessProbe: readinessProbe, 171 | LivenessProbe: livenessProbe, 172 | TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError, 173 | }, 174 | }, 175 | Volumes: volumes, 176 | }, 177 | }, 178 | }, 179 | } 180 | 181 | if instance.Spec.NodeSelector != nil { 182 | deployment.Spec.Template.Spec.NodeSelector = *instance.Spec.NodeSelector 183 | } 184 | 185 | if topology != nil { 186 | topology.ApplyTo(&deployment.Spec.Template) 187 | } else { 188 | // If possible two pods of the same service should not 189 | // run on the same worker node. If this is not possible 190 | // the get still created on the same worker node. 191 | deployment.Spec.Template.Spec.Affinity = affinity.DistributePods( 192 | common.AppSelector, 193 | []string{ 194 | ServiceName, 195 | }, 196 | corev1.LabelHostname, 197 | ) 198 | } 199 | 200 | return deployment, nil 201 | } 202 | -------------------------------------------------------------------------------- /pkg/neutronapi/scc.go: -------------------------------------------------------------------------------- 1 | package neutronapi 2 | 3 | import ( 4 | corev1 "k8s.io/api/core/v1" 5 | "k8s.io/utils/ptr" 6 | ) 7 | 8 | func getNeutronSecurityContext() *corev1.SecurityContext { 9 | 10 | return &corev1.SecurityContext{ 11 | RunAsUser: ptr.To(NeutronUID), 12 | RunAsGroup: ptr.To(NeutronGID), 13 | RunAsNonRoot: ptr.To(true), 14 | Capabilities: &corev1.Capabilities{ 15 | Drop: []corev1.Capability{ 16 | "MKNOD", 17 | }, 18 | }, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /pkg/neutronapi/volumes.go: -------------------------------------------------------------------------------- 1 | package neutronapi 2 | 3 | import ( 4 | "github.com/openstack-k8s-operators/lib-common/modules/storage" 5 | neutronv1beta1 "github.com/openstack-k8s-operators/neutron-operator/api/v1beta1" 6 | corev1 "k8s.io/api/core/v1" 7 | ) 8 | 9 | // GetVolumes - 10 | // TODO: merge to GetVolumes when other controllers also switched to current config 11 | // 12 | // mechanism. 13 | func GetVolumes(name string, extraVol []neutronv1beta1.NeutronExtraVolMounts, svc []storage.PropagationType) []corev1.Volume { 14 | res := []corev1.Volume{ 15 | { 16 | Name: "config", 17 | VolumeSource: corev1.VolumeSource{ 18 | Secret: &corev1.SecretVolumeSource{ 19 | SecretName: name + "-config", 20 | }, 21 | }, 22 | }, 23 | { 24 | Name: "httpd-config", 25 | VolumeSource: corev1.VolumeSource{ 26 | Secret: &corev1.SecretVolumeSource{ 27 | SecretName: name + "-httpd-config", 28 | }, 29 | }, 30 | }, 31 | } 32 | for _, exv := range extraVol { 33 | for _, vol := range exv.Propagate(svc) { 34 | for _, v := range vol.Volumes { 35 | volumeSource, _ := v.ToCoreVolumeSource() 36 | convertedVolume := corev1.Volume{ 37 | Name: v.Name, 38 | VolumeSource: *volumeSource, 39 | } 40 | res = append(res, convertedVolume) 41 | } 42 | } 43 | } 44 | return res 45 | 46 | } 47 | 48 | // GetVolumeMounts - Neutron API VolumeMounts 49 | func GetVolumeMounts(serviceName string, extraVol []neutronv1beta1.NeutronExtraVolMounts, svc []storage.PropagationType) []corev1.VolumeMount { 50 | res := []corev1.VolumeMount{ 51 | { 52 | Name: "config", 53 | MountPath: "/var/lib/config-data/default", 54 | ReadOnly: true, 55 | }, 56 | { 57 | Name: "config", 58 | MountPath: "/var/lib/kolla/config_files/config.json", 59 | SubPath: serviceName + "-config.json", 60 | ReadOnly: true, 61 | }, 62 | } 63 | for _, exv := range extraVol { 64 | for _, vol := range exv.Propagate(svc) { 65 | res = append(res, vol.Mounts...) 66 | } 67 | } 68 | return res 69 | 70 | } 71 | 72 | // GetHttpdVolumeMount - Returns the VolumeMounts used by the httpd sidecar 73 | func GetHttpdVolumeMount() []corev1.VolumeMount { 74 | return []corev1.VolumeMount{ 75 | { 76 | Name: "httpd-config", 77 | MountPath: "/var/lib/config-data/default", 78 | ReadOnly: true, 79 | }, 80 | { 81 | Name: "config", 82 | MountPath: "/var/lib/kolla/config_files/config.json", 83 | SubPath: "neutron-httpd-config.json", 84 | ReadOnly: true, 85 | }, 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /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/neutron-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/dhcp-agent.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | transport_url = {{ .transportURL }} 3 | -------------------------------------------------------------------------------- /templates/neutronapi/config/01-neutron.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | bind_host = localhost 3 | bind_port = 9697 4 | transport_url={{ .TransportURL }} 5 | core_plugin = {{ .CorePlugin }} 6 | {{ if .IsOVN }} 7 | service_plugins = qos,ovn-router,trunk,segments,port_forwarding,log 8 | {{ else }} 9 | service_plugins = qos,trunk,segments,port_forwarding,log 10 | {{ end }} 11 | dns_domain = openstackgate.local 12 | dhcp_agent_notification = false 13 | api_workers = 2 14 | rpc_workers = 1 15 | 16 | [database] 17 | connection=mysql+pymysql://{{ .DbUser }}:{{ .DbPassword }}@{{ .DbHost }}/{{ .Db }}?read_default_file=/etc/my.cnf 18 | # NOTE(ykarel): It is required to be set for multi master galera, without it set 19 | # there can be reads from not up to date db instance and that leads to various issues. 20 | mysql_wsrep_sync_wait = 1 21 | 22 | {{ if eq .CorePlugin "ml2" }} 23 | [ml2] 24 | mechanism_drivers = {{ .Ml2MechanismDrivers }} 25 | type_drivers = local,flat,vlan,geneve 26 | tenant_network_types = geneve 27 | extension_drivers = qos,port_security,dns_domain_ports 28 | 29 | [ml2_type_geneve] 30 | vni_ranges = 1:65536 31 | max_header_size = 38 32 | 33 | [ml2_type_vlan] 34 | network_vlan_ranges = datacentre 35 | 36 | {{ if .IsOVN }} 37 | [ovn] 38 | ovn_nb_connection = {{ .NBConnection }} 39 | ovn_sb_connection = {{ .SBConnection }} 40 | ovn_metadata_enabled = True 41 | enable_distributed_floating_ip=True 42 | ovn_emit_need_to_frag = True 43 | {{- if .OVNDB_TLS }} 44 | ovn_nb_private_key = /etc/pki/tls/private/ovndb.key 45 | ovn_nb_certificate = /etc/pki/tls/certs/ovndb.crt 46 | ovn_nb_ca_cert = /etc/pki/tls/certs/ovndbca.crt 47 | ovn_sb_private_key = /etc/pki/tls/private/ovndb.key 48 | ovn_sb_certificate = /etc/pki/tls/certs/ovndb.crt 49 | ovn_sb_ca_cert = /etc/pki/tls/certs/ovndbca.crt 50 | {{- end }} 51 | {{- end }} 52 | {{- end }} 53 | 54 | [keystone_authtoken] 55 | www_authenticate_uri = {{ .KeystonePublicURL }} 56 | auth_url = {{ .KeystoneInternalURL }} 57 | memcached_servers={{ .MemcachedServersWithInet }} 58 | memcache_pool_dead_retry = 10 59 | memcache_pool_conn_get_timeout = 2 60 | auth_type = password 61 | project_domain_name = Default 62 | user_domain_name = Default 63 | project_name = service 64 | username = {{ .ServiceUser }} 65 | password = {{ .ServicePassword }} 66 | interface = internal 67 | 68 | [nova] 69 | auth_url = {{ .KeystoneInternalURL }} 70 | auth_type = password 71 | project_domain_name = Default 72 | user_domain_name = Default 73 | region_name = regionOne 74 | project_name = service 75 | username = {{ .ServiceUser }} 76 | endpoint_type = internal 77 | password = {{ .ServicePassword }} 78 | 79 | [placement] 80 | auth_url = {{ .KeystoneInternalURL }} 81 | auth_type = password 82 | project_domain_name = Default 83 | user_domain_name = Default 84 | region_name = regionOne 85 | project_name = service 86 | username = {{ .ServiceUser }} 87 | endpoint_type = internal 88 | password = {{ .ServicePassword }} 89 | 90 | [oslo_concurrency] 91 | lock_path = /var/lib/neutron/tmp 92 | 93 | [cache] 94 | {{if .MemcachedTLS}} 95 | backend = oslo_cache.memcache_pool 96 | memcache_servers = {{ .MemcachedServers }} 97 | memcache_socket_timeout = 0.5 98 | memcache_pool_connection_get_timeout = 1 99 | {{else}} 100 | backend = dogpile.cache.memcached 101 | memcache_servers = {{ .MemcachedServersWithInet }} 102 | {{end}} 103 | enabled=true 104 | tls_enabled={{ .MemcachedTLS }} 105 | memcache_dead_retry = 30 106 | 107 | [oslo_policy] 108 | policy_file = /etc/neutron/policy.yaml 109 | enforce_scope = True 110 | enforce_new_defaults = True 111 | -------------------------------------------------------------------------------- /templates/neutronapi/config/db-sync-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "neutron-db-manage --config-file /usr/share/neutron/neutron-dist.conf --config-file /etc/neutron/neutron.conf --config-dir /etc/neutron/neutron.conf.d upgrade heads", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/config-data/default/01-neutron.conf", 6 | "dest": "/etc/neutron/neutron.conf.d/01-neutron.conf", 7 | "owner": "root:neutron", 8 | "perm": "0640" 9 | }, 10 | { 11 | "source": "/var/lib/config-data/default/02-neutron-custom.conf", 12 | "dest": "/etc/neutron/neutron.conf.d/02-neutron-custom.conf", 13 | "owner": "root:neutron", 14 | "perm": "0640" 15 | }, 16 | { 17 | "source": "/var/lib/config-data/default/my.cnf", 18 | "dest": "/etc/my.cnf", 19 | "owner": "neutron", 20 | "perm": "0644" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /templates/neutronapi/config/neutron-api-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/usr/bin/neutron-server --config-file /usr/share/neutron/neutron-dist.conf --config-file /etc/neutron/neutron.conf --config-dir /etc/neutron/neutron.conf.d", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/config-data/default/01-neutron.conf", 6 | "dest": "/etc/neutron/neutron.conf.d/01-neutron.conf", 7 | "owner": "root:neutron", 8 | "perm": "0640" 9 | }, 10 | { 11 | "source": "/var/lib/config-data/default/02-neutron-custom.conf", 12 | "dest": "/etc/neutron/neutron.conf.d/02-neutron-custom.conf", 13 | "owner": "root:neutron", 14 | "perm": "0640" 15 | }, 16 | { 17 | "source": "/var/lib/config-data/default/policy.yaml", 18 | "dest": "/etc/neutron/policy.yaml", 19 | "owner": "root:neutron", 20 | "perm": "0640", 21 | "optional": true 22 | }, 23 | { 24 | "source": "/var/lib/config-data/default/my.cnf", 25 | "dest": "/etc/my.cnf", 26 | "owner": "neutron", 27 | "perm": "0644" 28 | }, 29 | { 30 | "source": "/var/lib/config-data/tls/certs/*", 31 | "dest": "/etc/pki/tls/certs/", 32 | "owner": "neutron:neutron", 33 | "perm": "0640", 34 | "optional": true, 35 | "merge": true 36 | }, 37 | { 38 | "source": "/var/lib/config-data/tls/private/*", 39 | "dest": "/etc/pki/tls/private/", 40 | "owner": "neutron:neutron", 41 | "perm": "0640", 42 | "optional": true, 43 | "merge": true 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /templates/neutronapi/config/neutron-httpd-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": "/usr/sbin/httpd -DFOREGROUND", 3 | "config_files": [ 4 | { 5 | "source": "/var/lib/config-data/tls/certs/*", 6 | "dest": "/etc/pki/tls/certs/", 7 | "owner": "neutron:neutron", 8 | "perm": "0640", 9 | "optional": true, 10 | "merge": true 11 | }, 12 | { 13 | "source": "/var/lib/config-data/tls/private/*", 14 | "dest": "/etc/pki/tls/private/", 15 | "owner": "neutron:neutron", 16 | "perm": "0640", 17 | "optional": true, 18 | "merge": true 19 | }, 20 | { 21 | "source": "/var/lib/config-data/default/httpd.conf", 22 | "dest": "/etc/httpd/conf/httpd.conf", 23 | "owner": "neutron:apache", 24 | "optional": true, 25 | "perm": "0644" 26 | }, 27 | { 28 | "source": "/var/lib/config-data/default/10-neutron-httpd.conf", 29 | "dest": "/etc/httpd/conf.d/10-neutron.conf", 30 | "owner": "neutron:apache", 31 | "optional": true, 32 | "perm": "0644" 33 | }, 34 | { 35 | "source": "/var/lib/config-data/default/ssl.conf", 36 | "dest": "/etc/httpd/conf.d/ssl.conf", 37 | "owner": "neutron:apache", 38 | "optional": true, 39 | "perm": "0644" 40 | } 41 | ], 42 | "permissions": [ 43 | { 44 | "path": "/etc/httpd/run", 45 | "owner": "neutron:apache", 46 | "recurse": true 47 | } 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /templates/neutronapi/httpd/10-neutron-httpd.conf: -------------------------------------------------------------------------------- 1 | {{ range $endpt, $vhost := .VHosts }} 2 | # {{ $endpt }} vhost {{ $vhost.ServerName }} configuration 3 | 4 | ServerName {{ $vhost.ServerName }} 5 | 6 | TimeOut {{ $.TimeOut }} 7 | 8 | ## Logging 9 | ErrorLog /dev/stdout 10 | ServerSignature Off 11 | CustomLog /dev/stdout combined 12 | 13 | ## Request header rules 14 | ## as per http://httpd.apache.org/docs/2.2/mod/mod_headers.html#requestheader 15 | {{- if $vhost.TLS }} 16 | RequestHeader setIfEmpty X-Forwarded-Proto "https" 17 | {{- else }} 18 | RequestHeader setIfEmpty X-Forwarded-Proto "http" 19 | {{- end }} 20 | 21 | ## Proxy rules 22 | ProxyRequests Off 23 | ProxyPreserveHost On 24 | ProxyPass / http://localhost:9697/ retry=10 25 | ProxyPassReverse / http://localhost:9697/ 26 | 27 | {{- if $vhost.TLS }} 28 | SetEnvIf X-Forwarded-Proto https HTTPS=1 29 | 30 | ## SSL directives 31 | SSLEngine on 32 | SSLCertificateFile "{{ $vhost.SSLCertificateFile }}" 33 | SSLCertificateKeyFile "{{ $vhost.SSLCertificateKeyFile }}" 34 | {{- end }} 35 | 36 | {{ end }} 37 | -------------------------------------------------------------------------------- /templates/neutronapi/httpd/httpd.conf: -------------------------------------------------------------------------------- 1 | ServerTokens Prod 2 | ServerSignature Off 3 | TraceEnable Off 4 | ServerRoot "/etc/httpd" 5 | ServerName "neutron.openstack.svc" 6 | 7 | User apache 8 | Group apache 9 | 10 | Listen 9696 11 | 12 | TypesConfig /etc/mime.types 13 | 14 | Include conf.modules.d/*.conf 15 | Include conf.d/*.conf 16 | 17 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined 18 | LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" proxy 19 | 20 | SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded 21 | CustomLog /dev/stdout combined env=!forwarded 22 | CustomLog /dev/stdout proxy env=forwarded 23 | ErrorLog /dev/stdout 24 | 25 | Include conf.d/10-neutron.conf 26 | -------------------------------------------------------------------------------- /templates/neutronapi/httpd/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/ovn-agent.conf: -------------------------------------------------------------------------------- 1 | [ovn] 2 | ovn_nb_connection = {{ .NBConnection }} 3 | ovn_sb_connection = {{ .SBConnection }} 4 | {{- if .OVNDB_TLS }} 5 | ovn_nb_private_key = /etc/pki/tls/private/ovndb.key 6 | ovn_nb_certificate = /etc/pki/tls/certs/ovndb.crt 7 | ovn_nb_ca_cert = /etc/pki/tls/certs/ovndbca.crt 8 | ovn_sb_private_key = /etc/pki/tls/private/ovndb.key 9 | ovn_sb_certificate = /etc/pki/tls/certs/ovndb.crt 10 | ovn_sb_ca_cert = /etc/pki/tls/certs/ovndbca.crt 11 | {{- end }} 12 | -------------------------------------------------------------------------------- /templates/ovn-metadata-agent.conf: -------------------------------------------------------------------------------- 1 | # NOTE: some necessary metadata agent options are set by nova. 2 | # Specifically, nova_metadata_host and metadata_proxy_shared_secret. 3 | # 4 | # The final metadata agent deployment will have to merge settings from multiple 5 | # sources. 6 | 7 | [ovn] 8 | ovn_sb_connection = {{ .SBConnection }} 9 | {{- if .OVNDB_TLS }} 10 | ovn_sb_private_key = /etc/pki/tls/private/ovndb.key 11 | ovn_sb_certificate = /etc/pki/tls/certs/ovndb.crt 12 | ovn_sb_ca_cert = /etc/pki/tls/certs/ovndbca.crt 13 | {{- end }} 14 | -------------------------------------------------------------------------------- /templates/sriov-agent.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | transport_url = {{ .transportURL }} 3 | -------------------------------------------------------------------------------- /test/functional/base_test.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 functional_test 18 | 19 | import ( 20 | "time" 21 | 22 | "github.com/google/uuid" 23 | . "github.com/onsi/gomega" //revive:disable:dot-imports 24 | condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition" 25 | neutronv1 "github.com/openstack-k8s-operators/neutron-operator/api/v1beta1" 26 | "github.com/openstack-k8s-operators/neutron-operator/pkg/neutronapi" 27 | ovnv1 "github.com/openstack-k8s-operators/ovn-operator/api/v1beta1" 28 | corev1 "k8s.io/api/core/v1" 29 | k8s_errors "k8s.io/apimachinery/pkg/api/errors" 30 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 31 | "k8s.io/apimachinery/pkg/types" 32 | "sigs.k8s.io/controller-runtime/pkg/client" 33 | ) 34 | 35 | const ( 36 | SecretName = "test-secret" 37 | 38 | PublicCertSecretName = "public-tls-certs" 39 | InternalCertSecretName = "internal-tls-certs" 40 | CABundleSecretName = "combined-ca-bundle" 41 | OVNDbCertSecretName = "ovndb-tls-certs" 42 | 43 | timeout = time.Second * 10 44 | interval = timeout / 100 45 | ) 46 | 47 | func SetExternalDBEndpoint(name types.NamespacedName, endpoint string) { 48 | Eventually(func(g Gomega) { 49 | cluster := GetOVNDBCluster(name) 50 | cluster.Status.DBAddress = endpoint 51 | g.Expect(k8sClient.Status().Update(ctx, cluster)).To(Succeed()) 52 | }, timeout, interval).Should(Succeed()) 53 | } 54 | 55 | func SimulateTransportURLReady(name types.NamespacedName) { 56 | Eventually(func(g Gomega) { 57 | transport := infra.GetTransportURL(name) 58 | // To avoid another secret creation and cleanup 59 | transport.Status.SecretName = SecretName 60 | transport.Status.Conditions.MarkTrue("TransportURLReady", "Ready") 61 | g.Expect(k8sClient.Status().Update(ctx, transport)).To(Succeed()) 62 | 63 | }, timeout, interval).Should(Succeed()) 64 | logger.Info("Simulated TransportURL ready", "on", name) 65 | } 66 | 67 | func GetDefaultNeutronAPISpec() map[string]interface{} { 68 | return map[string]interface{}{ 69 | "databaseInstance": "test-neutron-db-instance", 70 | "secret": SecretName, 71 | } 72 | } 73 | 74 | func CreateNeutronAPI(namespace string, NeutronAPIName string, spec map[string]interface{}) client.Object { 75 | 76 | raw := map[string]interface{}{ 77 | "apiVersion": "neutron.openstack.org/v1beta1", 78 | "kind": "NeutronAPI", 79 | "metadata": map[string]interface{}{ 80 | "name": NeutronAPIName, 81 | "namespace": namespace, 82 | }, 83 | "spec": spec, 84 | } 85 | 86 | return th.CreateUnstructured(raw) 87 | } 88 | 89 | func GetNeutronAPI(name types.NamespacedName) *neutronv1.NeutronAPI { 90 | instance := &neutronv1.NeutronAPI{} 91 | Eventually(func(g Gomega) { 92 | g.Expect(k8sClient.Get(ctx, name, instance)).Should(Succeed()) 93 | }, timeout, interval).Should(Succeed()) 94 | return instance 95 | } 96 | 97 | func NeutronAPIConditionGetter(name types.NamespacedName) condition.Conditions { 98 | instance := GetNeutronAPI(name) 99 | return instance.Status.Conditions 100 | } 101 | 102 | // CreateOVNDBClusters Creates NB and SB OVNDBClusters 103 | func CreateOVNDBClusters(namespace string) []types.NamespacedName { 104 | dbs := []types.NamespacedName{} 105 | for _, db := range []string{"NB", "SB"} { 106 | ovndbcluster := &ovnv1.OVNDBCluster{ 107 | TypeMeta: metav1.TypeMeta{ 108 | APIVersion: "ovn.openstack.org/v1beta1", 109 | Kind: "OVNDBCluster", 110 | }, 111 | ObjectMeta: metav1.ObjectMeta{ 112 | Name: "ovn-" + uuid.New().String(), 113 | Namespace: namespace, 114 | }, 115 | Spec: ovnv1.OVNDBClusterSpec{ 116 | OVNDBClusterSpecCore: ovnv1.OVNDBClusterSpecCore{ 117 | DBType: db, 118 | }, 119 | }, 120 | } 121 | 122 | Expect(k8sClient.Create(ctx, ovndbcluster.DeepCopy())).Should(Succeed()) 123 | name := types.NamespacedName{Namespace: namespace, Name: ovndbcluster.Name} 124 | 125 | dbaddr := "tcp:10.1.1.1:6641" 126 | if db == "SB" { 127 | dbaddr = "tcp:10.1.1.1:6642" 128 | } 129 | 130 | // the Status field needs to be written via a separate client 131 | ovndbcluster = GetOVNDBCluster(name) 132 | ovndbcluster.Status = ovnv1.OVNDBClusterStatus{ 133 | InternalDBAddress: dbaddr, 134 | } 135 | Expect(k8sClient.Status().Update(ctx, ovndbcluster.DeepCopy())).Should(Succeed()) 136 | dbs = append(dbs, name) 137 | 138 | } 139 | 140 | logger.Info("OVNDBClusters created", "OVNDBCluster", dbs) 141 | return dbs 142 | } 143 | 144 | // DeleteOVNDBClusters Delete OVN DBClusters 145 | func DeleteOVNDBClusters(names []types.NamespacedName) { 146 | for _, db := range names { 147 | Eventually(func(g Gomega) { 148 | ovndbcluster := &ovnv1.OVNDBCluster{} 149 | err := k8sClient.Get(ctx, db, ovndbcluster) 150 | // if it is already gone that is OK 151 | if k8s_errors.IsNotFound(err) { 152 | return 153 | } 154 | g.Expect(err).ShouldNot(HaveOccurred()) 155 | 156 | g.Expect(k8sClient.Delete(ctx, ovndbcluster)).Should(Succeed()) 157 | 158 | err = k8sClient.Get(ctx, db, ovndbcluster) 159 | g.Expect(k8s_errors.IsNotFound(err)).To(BeTrue()) 160 | }, timeout, interval).Should(Succeed()) 161 | } 162 | } 163 | 164 | // GetOVNDBCluster Get OVNDBCluster 165 | func GetOVNDBCluster(name types.NamespacedName) *ovnv1.OVNDBCluster { 166 | instance := &ovnv1.OVNDBCluster{} 167 | Eventually(func(g Gomega) { 168 | g.Expect(k8sClient.Get(ctx, name, instance)).Should(Succeed()) 169 | }, timeout, interval).Should(Succeed()) 170 | return instance 171 | } 172 | 173 | func CreateNeutronAPISecret(namespace string, name string) *corev1.Secret { 174 | return th.CreateSecret( 175 | types.NamespacedName{Namespace: namespace, Name: name}, 176 | map[string][]byte{ 177 | "NeutronPassword": []byte("12345678"), 178 | "transport_url": []byte("rabbit://user@svc:1234"), 179 | }, 180 | ) 181 | } 182 | 183 | // GetSampleTopologySpec - A sample (and opinionated) Topology Spec used to 184 | // test NeutronAPI 185 | // Note this is just an example that should not be used in production for 186 | // multiple reasons: 187 | // 1. It uses ScheduleAnyway as strategy, which is something we might 188 | // want to avoid by default 189 | // 2. Usually a topologySpreadConstraints is used to take care about 190 | // multi AZ, which is not applicable in this context 191 | func GetSampleTopologySpec(label string) (map[string]interface{}, []corev1.TopologySpreadConstraint) { 192 | // Build the topology Spec 193 | topologySpec := map[string]interface{}{ 194 | "topologySpreadConstraints": []map[string]interface{}{ 195 | { 196 | "maxSkew": 1, 197 | "topologyKey": corev1.LabelHostname, 198 | "whenUnsatisfiable": "ScheduleAnyway", 199 | "labelSelector": map[string]interface{}{ 200 | "matchLabels": map[string]interface{}{ 201 | "service": neutronapi.ServiceName, 202 | "component": label, 203 | }, 204 | }, 205 | }, 206 | }, 207 | } 208 | // Build the topologyObj representation 209 | topologySpecObj := []corev1.TopologySpreadConstraint{ 210 | { 211 | MaxSkew: 1, 212 | TopologyKey: corev1.LabelHostname, 213 | WhenUnsatisfiable: corev1.ScheduleAnyway, 214 | LabelSelector: &metav1.LabelSelector{ 215 | MatchLabels: map[string]string{ 216 | "service": neutronapi.ServiceName, 217 | "component": label, 218 | }, 219 | }, 220 | }, 221 | } 222 | return topologySpec, topologySpecObj 223 | } 224 | 225 | // GetExtraMounts - Utility function that simulates extraMounts pointing 226 | // to a secret 227 | func GetExtraMounts(nemName string, nemPath string) []map[string]interface{} { 228 | return []map[string]interface{}{ 229 | { 230 | "name": nemName, 231 | "region": "az0", 232 | "extraVol": []map[string]interface{}{ 233 | { 234 | "extraVolType": nemName, 235 | "propagation": []string{ 236 | "Neutron", 237 | }, 238 | "volumes": []map[string]interface{}{ 239 | { 240 | "name": nemName, 241 | "secret": map[string]interface{}{ 242 | "secretName": nemName, 243 | }, 244 | }, 245 | }, 246 | "mounts": []map[string]interface{}{ 247 | { 248 | "name": nemName, 249 | "mountPath": nemPath, 250 | "readOnly": true, 251 | }, 252 | }, 253 | }, 254 | }, 255 | }, 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /test/functional/suite_test.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 functional_test 18 | 19 | import ( 20 | "context" 21 | "crypto/tls" 22 | "fmt" 23 | "net" 24 | "path/filepath" 25 | "testing" 26 | "time" 27 | 28 | "github.com/go-logr/logr" 29 | "github.com/google/uuid" 30 | . "github.com/onsi/ginkgo/v2" //revive:disable:dot-imports 31 | . "github.com/onsi/gomega" //revive:disable:dot-imports 32 | "k8s.io/client-go/kubernetes" 33 | "k8s.io/client-go/kubernetes/scheme" 34 | "k8s.io/client-go/rest" 35 | ctrl "sigs.k8s.io/controller-runtime" 36 | "sigs.k8s.io/controller-runtime/pkg/client" 37 | "sigs.k8s.io/controller-runtime/pkg/envtest" 38 | logf "sigs.k8s.io/controller-runtime/pkg/log" 39 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 40 | "sigs.k8s.io/controller-runtime/pkg/webhook" 41 | 42 | metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" 43 | 44 | appsv1 "k8s.io/api/apps/v1" 45 | batchv1 "k8s.io/api/batch/v1" 46 | corev1 "k8s.io/api/core/v1" 47 | 48 | networkv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" 49 | memcachedv1 "github.com/openstack-k8s-operators/infra-operator/apis/memcached/v1beta1" 50 | rabbitmqv1 "github.com/openstack-k8s-operators/infra-operator/apis/rabbitmq/v1beta1" 51 | keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1" 52 | test "github.com/openstack-k8s-operators/lib-common/modules/test" 53 | mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" 54 | neutronv1 "github.com/openstack-k8s-operators/neutron-operator/api/v1beta1" 55 | "github.com/openstack-k8s-operators/neutron-operator/controllers" 56 | ovnv1 "github.com/openstack-k8s-operators/ovn-operator/api/v1beta1" 57 | 58 | infra_test "github.com/openstack-k8s-operators/infra-operator/apis/test/helpers" 59 | topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1" 60 | keystone_test "github.com/openstack-k8s-operators/keystone-operator/api/test/helpers" 61 | common_test "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers" 62 | mariadb_test "github.com/openstack-k8s-operators/mariadb-operator/api/test/helpers" 63 | //+kubebuilder:scaffold:imports 64 | ) 65 | 66 | // These tests use Ginkgo (BDD-style Go testing framework). Refer to 67 | // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. 68 | 69 | var ( 70 | cfg *rest.Config 71 | k8sClient client.Client // You'll be using this client in your tests. 72 | testEnv *envtest.Environment 73 | ctx context.Context 74 | cancel context.CancelFunc 75 | logger logr.Logger 76 | th *common_test.TestHelper 77 | keystone *keystone_test.TestHelper 78 | mariadb *mariadb_test.TestHelper 79 | infra *infra_test.TestHelper 80 | namespace string 81 | ) 82 | 83 | func TestAPIs(t *testing.T) { 84 | RegisterFailHandler(Fail) 85 | 86 | RunSpecs(t, "Controller Suite") 87 | } 88 | 89 | var _ = BeforeSuite(func() { 90 | logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) 91 | 92 | ctx, cancel = context.WithCancel(context.TODO()) 93 | 94 | networkv1CRD, err := test.GetCRDDirFromModule( 95 | "github.com/k8snetworkplumbingwg/network-attachment-definition-client", "../../go.mod", "artifacts/networks-crd.yaml") 96 | Expect(err).ShouldNot(HaveOccurred()) 97 | keystoneCRDs, err := test.GetCRDDirFromModule( 98 | "github.com/openstack-k8s-operators/keystone-operator/api", "../../go.mod", "bases") 99 | Expect(err).ShouldNot(HaveOccurred()) 100 | mariaDBCRDs, err := test.GetCRDDirFromModule( 101 | "github.com/openstack-k8s-operators/mariadb-operator/api", "../../go.mod", "bases") 102 | Expect(err).ShouldNot(HaveOccurred()) 103 | ovnCRDs, err := test.GetCRDDirFromModule( 104 | "github.com/openstack-k8s-operators/ovn-operator/api", "../../go.mod", "bases") 105 | Expect(err).ShouldNot(HaveOccurred()) 106 | infraCRDs, err := test.GetCRDDirFromModule( 107 | "github.com/openstack-k8s-operators/infra-operator/apis", "../../go.mod", "bases") 108 | Expect(err).ShouldNot(HaveOccurred()) 109 | 110 | By("bootstrapping test environment") 111 | testEnv = &envtest.Environment{ 112 | CRDDirectoryPaths: []string{ 113 | filepath.Join("..", "..", "config", "crd", "bases"), 114 | // NOTE(gibi): we need to list all the external CRDs our operator depends on 115 | keystoneCRDs, 116 | mariaDBCRDs, 117 | ovnCRDs, 118 | infraCRDs, 119 | }, 120 | CRDInstallOptions: envtest.CRDInstallOptions{ 121 | Paths: []string{ 122 | networkv1CRD, 123 | }, 124 | }, 125 | ErrorIfCRDPathMissing: true, 126 | WebhookInstallOptions: envtest.WebhookInstallOptions{ 127 | Paths: []string{filepath.Join("..", "..", "config", "webhook")}, 128 | }, 129 | } 130 | 131 | // cfg is defined in this file globally. 132 | cfg, err = testEnv.Start() 133 | Expect(err).NotTo(HaveOccurred()) 134 | Expect(cfg).NotTo(BeNil()) 135 | 136 | // NOTE(gibi): Need to add all API schemas our operator can own. 137 | // Keep this in synch with NeutronAPIReconciler.SetupWithManager, 138 | // otherwise the reconciler loop will silently not start 139 | // in the test env. 140 | err = neutronv1.AddToScheme(scheme.Scheme) 141 | Expect(err).NotTo(HaveOccurred()) 142 | err = mariadbv1.AddToScheme(scheme.Scheme) 143 | Expect(err).NotTo(HaveOccurred()) 144 | err = keystonev1.AddToScheme(scheme.Scheme) 145 | Expect(err).NotTo(HaveOccurred()) 146 | err = ovnv1.AddToScheme(scheme.Scheme) 147 | Expect(err).NotTo(HaveOccurred()) 148 | err = memcachedv1.AddToScheme(scheme.Scheme) 149 | Expect(err).NotTo(HaveOccurred()) 150 | err = rabbitmqv1.AddToScheme(scheme.Scheme) 151 | Expect(err).NotTo(HaveOccurred()) 152 | err = batchv1.AddToScheme(scheme.Scheme) 153 | Expect(err).NotTo(HaveOccurred()) 154 | err = corev1.AddToScheme(scheme.Scheme) 155 | Expect(err).NotTo(HaveOccurred()) 156 | err = appsv1.AddToScheme(scheme.Scheme) 157 | Expect(err).NotTo(HaveOccurred()) 158 | err = networkv1.AddToScheme(scheme.Scheme) 159 | Expect(err).NotTo(HaveOccurred()) 160 | err = topologyv1.AddToScheme(scheme.Scheme) 161 | Expect(err).NotTo(HaveOccurred()) 162 | //+kubebuilder:scaffold:scheme 163 | 164 | logger = ctrl.Log.WithName("---Test---") 165 | 166 | k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) 167 | Expect(err).NotTo(HaveOccurred()) 168 | Expect(k8sClient).NotTo(BeNil()) 169 | th = common_test.NewTestHelper(ctx, k8sClient, timeout, interval, logger) 170 | Expect(th).NotTo(BeNil()) 171 | keystone = keystone_test.NewTestHelper(ctx, k8sClient, timeout, interval, logger) 172 | Expect(keystone).NotTo(BeNil()) 173 | mariadb = mariadb_test.NewTestHelper(ctx, k8sClient, timeout, interval, logger) 174 | Expect(mariadb).NotTo(BeNil()) 175 | infra = infra_test.NewTestHelper(ctx, k8sClient, timeout, interval, logger) 176 | Expect(infra).NotTo(BeNil()) 177 | 178 | // Start the controller-manager if goroutine 179 | webhookInstallOptions := &testEnv.WebhookInstallOptions 180 | k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{ 181 | Scheme: scheme.Scheme, 182 | Metrics: metricsserver.Options{ 183 | BindAddress: "0", 184 | }, 185 | WebhookServer: webhook.NewServer( 186 | webhook.Options{ 187 | Host: webhookInstallOptions.LocalServingHost, 188 | Port: webhookInstallOptions.LocalServingPort, 189 | CertDir: webhookInstallOptions.LocalServingCertDir, 190 | }), 191 | LeaderElection: false, 192 | }) 193 | Expect(err).ToNot(HaveOccurred()) 194 | 195 | err = (&neutronv1.NeutronAPI{}).SetupWebhookWithManager(k8sManager) 196 | Expect(err).NotTo(HaveOccurred()) 197 | 198 | kclient, err := kubernetes.NewForConfig(cfg) 199 | Expect(err).ToNot(HaveOccurred(), "failed to create kclient") 200 | 201 | err = (&controllers.NeutronAPIReconciler{ 202 | Client: k8sManager.GetClient(), 203 | Scheme: k8sManager.GetScheme(), 204 | Kclient: kclient, 205 | }).SetupWithManager(context.Background(), k8sManager) 206 | Expect(err).ToNot(HaveOccurred()) 207 | 208 | // Acquire environmental defaults and initialize operator defaults with them 209 | neutronv1.SetupDefaults() 210 | 211 | go func() { 212 | defer GinkgoRecover() 213 | err = k8sManager.Start(ctx) 214 | Expect(err).ToNot(HaveOccurred(), "failed to run manager") 215 | }() 216 | 217 | // wait for the webhook server to get ready 218 | dialer := &net.Dialer{Timeout: time.Second} 219 | addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort) 220 | Eventually(func() error { 221 | conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true}) 222 | if err != nil { 223 | return err 224 | } 225 | conn.Close() 226 | return nil 227 | }).Should(Succeed()) 228 | }) 229 | 230 | var _ = AfterSuite(func() { 231 | By("tearing down the test environment") 232 | cancel() 233 | err := testEnv.Stop() 234 | Expect(err).NotTo(HaveOccurred()) 235 | }) 236 | 237 | var _ = BeforeEach(func() { 238 | // NOTE(gibi): We need to create a unique namespace for each test run 239 | // as namespaces cannot be deleted in a locally running envtest. See 240 | // https://book.kubebuilder.io/reference/envtest.html#namespace-usage-limitation 241 | namespace = uuid.New().String() 242 | th.CreateNamespace(namespace) 243 | // We still request the delete of the Namespace to properly cleanup if 244 | // we run the test in an existing cluster. 245 | DeferCleanup(th.DeleteNamespace, namespace) 246 | }) 247 | -------------------------------------------------------------------------------- /test/kuttl/common/assert_sample_deployment.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Check for: 3 | # 4 | # - 1 NeutronAPI CR 5 | # - Deployment with 1 Pod for NeutronAPI CR 6 | # - Neutron-internal Service 7 | # - Neutron-public Service 8 | 9 | apiVersion: neutron.openstack.org/v1beta1 10 | kind: NeutronAPI 11 | metadata: 12 | finalizers: 13 | - openstack.org/neutronapi 14 | name: neutron 15 | spec: 16 | customServiceConfig: | 17 | [DEFAULT] 18 | debug = true 19 | databaseInstance: openstack 20 | databaseAccount: neutron 21 | passwordSelectors: 22 | service: NeutronPassword 23 | preserveJobs: false 24 | rabbitMqClusterName: rabbitmq 25 | replicas: 1 26 | secret: osp-secret 27 | serviceUser: neutron 28 | status: 29 | transportURLSecret: rabbitmq-transport-url-neutron-neutron-transport 30 | readyCount: 1 31 | --- 32 | apiVersion: apps/v1 33 | kind: Deployment 34 | metadata: 35 | name: neutron 36 | spec: 37 | progressDeadlineSeconds: 600 38 | replicas: 1 39 | revisionHistoryLimit: 10 40 | selector: 41 | matchLabels: 42 | service: neutron 43 | strategy: 44 | rollingUpdate: 45 | maxSurge: 25% 46 | maxUnavailable: 25% 47 | type: RollingUpdate 48 | template: 49 | metadata: 50 | labels: 51 | service: neutron 52 | spec: 53 | affinity: 54 | podAntiAffinity: 55 | preferredDuringSchedulingIgnoredDuringExecution: 56 | - podAffinityTerm: 57 | labelSelector: 58 | matchExpressions: 59 | - key: service 60 | operator: In 61 | values: 62 | - neutron 63 | topologyKey: kubernetes.io/hostname 64 | weight: 100 65 | containers: 66 | - command: 67 | - /bin/bash 68 | args: 69 | - -c 70 | - /usr/local/bin/kolla_start 71 | imagePullPolicy: IfNotPresent 72 | livenessProbe: 73 | failureThreshold: 3 74 | httpGet: 75 | path: / 76 | port: 9696 77 | scheme: HTTP 78 | initialDelaySeconds: 5 79 | periodSeconds: 30 80 | successThreshold: 1 81 | timeoutSeconds: 30 82 | name: neutron-api 83 | resources: {} 84 | securityContext: 85 | runAsUser: 42435 86 | terminationMessagePath: /dev/termination-log 87 | terminationMessagePolicy: FallbackToLogsOnError 88 | - command: 89 | - /bin/bash 90 | args: 91 | - -c 92 | - /usr/local/bin/kolla_start 93 | imagePullPolicy: IfNotPresent 94 | livenessProbe: 95 | failureThreshold: 3 96 | httpGet: 97 | path: / 98 | port: 9696 99 | scheme: HTTP 100 | initialDelaySeconds: 5 101 | periodSeconds: 30 102 | successThreshold: 1 103 | timeoutSeconds: 30 104 | name: neutron-httpd 105 | readinessProbe: 106 | failureThreshold: 3 107 | httpGet: 108 | path: / 109 | port: 9696 110 | scheme: HTTP 111 | initialDelaySeconds: 5 112 | periodSeconds: 30 113 | successThreshold: 1 114 | timeoutSeconds: 30 115 | resources: {} 116 | securityContext: 117 | runAsUser: 42435 118 | terminationMessagePath: /dev/termination-log 119 | terminationMessagePolicy: FallbackToLogsOnError 120 | schedulerName: default-scheduler 121 | securityContext: {} 122 | serviceAccount: neutron-neutron 123 | serviceAccountName: neutron-neutron 124 | terminationGracePeriodSeconds: 30 125 | status: 126 | availableReplicas: 1 127 | readyReplicas: 1 128 | replicas: 1 129 | updatedReplicas: 1 130 | --- 131 | # the openshift annotations can't be checked through the deployment above 132 | apiVersion: v1 133 | kind: Pod 134 | metadata: 135 | annotations: 136 | openshift.io/scc: anyuid 137 | labels: 138 | service: neutron 139 | --- 140 | apiVersion: v1 141 | kind: Service 142 | metadata: 143 | labels: 144 | endpoint: internal 145 | service: neutron 146 | name: neutron-internal 147 | spec: 148 | internalTrafficPolicy: Cluster 149 | ipFamilies: 150 | - IPv4 151 | ipFamilyPolicy: SingleStack 152 | ports: 153 | - name: neutron-internal 154 | port: 9696 155 | protocol: TCP 156 | targetPort: 9696 157 | selector: 158 | service: neutron 159 | sessionAffinity: None 160 | type: ClusterIP 161 | --- 162 | apiVersion: v1 163 | kind: Service 164 | metadata: 165 | labels: 166 | endpoint: public 167 | service: neutron 168 | name: neutron-public 169 | spec: 170 | internalTrafficPolicy: Cluster 171 | ipFamilies: 172 | - IPv4 173 | ipFamilyPolicy: SingleStack 174 | ports: 175 | - name: neutron-public 176 | port: 9696 177 | protocol: TCP 178 | targetPort: 9696 179 | selector: 180 | service: neutron 181 | sessionAffinity: None 182 | type: ClusterIP 183 | --- 184 | apiVersion: keystone.openstack.org/v1beta1 185 | kind: KeystoneEndpoint 186 | metadata: 187 | name: neutron 188 | ownerReferences: 189 | - apiVersion: neutron.openstack.org/v1beta1 190 | blockOwnerDeletion: true 191 | controller: true 192 | kind: NeutronAPI 193 | name: neutron 194 | --- 195 | # the actual addresses of the api endpoints are platform specific, so we can't rely on 196 | # kuttl asserts to check them. This short script gathers the addresses and checks that 197 | # the two endpoints are defined and their addresses follow the default pattern 198 | apiVersion: kuttl.dev/v1beta1 199 | kind: TestAssert 200 | commands: 201 | - script: | 202 | template='{{.spec.endpoints.internal}}{{":"}}{{.spec.endpoints.public}}{{"\n"}}' 203 | regex="http:\/\/neutron-internal.$NAMESPACE.*:http:\/\/neutron-public.$NAMESPACE.*" 204 | apiEndpoints=$(oc get -n $NAMESPACE KeystoneEndpoint neutron -o go-template="$template") 205 | matches=$(echo "$apiEndpoints" | sed -e "s?$regex??") 206 | if [[ -n "$matches" ]]; then 207 | exit 1 208 | fi 209 | 210 | # when using image digests the containerImage URLs are SHA's so we verify them with a script 211 | tupleTemplate='{{ range (index .spec.template.spec.containers 1).env }}{{ .name }}{{ "#" }}{{ .value}}{{"\n"}}{{ end }}' 212 | imageTuples=$(oc get -n openstack-operators deployment neutron-operator-controller-manager -o go-template="$tupleTemplate") 213 | # format of imageTuple is: RELATED_IMAGE_NEUTRON_# separated by newlines 214 | for ITEM in $(echo $imageTuples); do 215 | # it is an image 216 | if echo $ITEM | grep 'RELATED_IMAGE' &> /dev/null; then 217 | NAME=$(echo $ITEM | sed -e 's|^RELATED_IMAGE_NEUTRON_\([^_]*\)_.*|\1|') 218 | IMG_FROM_ENV=$(echo $ITEM | sed -e 's|^.*#\(.*\)|\1|') 219 | template='{{.spec.containerImage}}' 220 | case $NAME in 221 | API) 222 | SERVICE_IMAGE=$(oc get -n $NAMESPACE neutronapi neutron -o go-template="$template") 223 | ;; 224 | esac 225 | if [ "$SERVICE_IMAGE" != "$IMG_FROM_ENV" ]; then 226 | echo "$NAME image does not equal $VALUE" 227 | exit 1 228 | fi 229 | fi 230 | done 231 | 232 | exit 0 233 | -------------------------------------------------------------------------------- /test/kuttl/common/assert_tls_cert.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Check for: 3 | # 4 | # - 2 tls cert secrets 5 | # - 1 tls ca bundle secrets 6 | 7 | apiVersion: v1 8 | kind: Secret 9 | metadata: 10 | name: cert-neutron-internal-svc 11 | --- 12 | apiVersion: v1 13 | kind: Secret 14 | metadata: 15 | name: cert-neutron-public-svc 16 | --- 17 | apiVersion: v1 18 | kind: Secret 19 | metadata: 20 | name: combined-ca-bundle 21 | -------------------------------------------------------------------------------- /test/kuttl/common/cleanup-neutron.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | oc kustomize deploy | oc delete -n $NAMESPACE -f - 6 | rm deploy/neutron_v1beta1_neutronapi*.yaml 7 | -------------------------------------------------------------------------------- /test/kuttl/common/errors_cleanup_neutron.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Check for: 3 | # 4 | # No NeutronAPI CR 5 | # No Deployment for NeutronAPI CR 6 | # No Pods in neutron Deployment 7 | # No Neutron Services 8 | # 9 | apiVersion: neutron.openstack.org/v1beta1 10 | kind: NeutronAPI 11 | metadata: 12 | finalizers: 13 | - openstack.org/neutronapi 14 | name: neutron 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: neutron 20 | --- 21 | # the openshift annotations can't be checked through the deployment above 22 | apiVersion: v1 23 | kind: Pod 24 | metadata: 25 | annotations: 26 | openshift.io/scc: anyuid 27 | labels: 28 | service: neutron 29 | --- 30 | apiVersion: v1 31 | kind: Service 32 | metadata: 33 | labels: 34 | endpoint: internal 35 | service: neutron 36 | name: neutron-internal 37 | --- 38 | apiVersion: v1 39 | kind: Service 40 | metadata: 41 | labels: 42 | endpoint: public 43 | service: neutron 44 | name: neutron-public 45 | -------------------------------------------------------------------------------- /test/kuttl/common/scripts/check_debug_in_neutron_pod_logs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | pod=$(oc get pods -n $NAMESPACE -l service=neutron --field-selector=status.phase=Running -o name|head -1) 4 | 5 | # Check if the neutron pod logs contain DEBUG messages 6 | oc logs -n $NAMESPACE "$pod" | grep -q "DEBUG" 7 | exit $? 8 | -------------------------------------------------------------------------------- /test/kuttl/common/tls_ca_bundle.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Internal CA created with: 3 | # 4 | # apiVersion: cert-manager.io/v1 5 | # kind: Issuer 6 | # metadata: 7 | # name: rootca-kuttl-internal 8 | # namespace: openstack 9 | # spec: 10 | # ca: 11 | # secretName: rootca-kuttl-internal 12 | # 13 | # apiVersion: cert-manager.io/v1 14 | # kind: Certificate 15 | # metadata: 16 | # name: rootca-kuttl-internal 17 | # namespace: openstack 18 | # spec: 19 | # commonName: rootca-kuttl-internal 20 | # duration: 87600h0m0s 21 | # isCA: true 22 | # issuerRef: 23 | # name: selfsigned-issuer 24 | # privateKey: 25 | # algorithm: ECDSA 26 | # size: 256 27 | # secretName: rootca-kuttl-internal 28 | # 29 | # External CA created with: 30 | # 31 | # apiVersion: cert-manager.io/v1 32 | # kind: Issuer 33 | # metadata: 34 | # name: rootca-kuttl-public 35 | # namespace: openstack 36 | # spec: 37 | # ca: 38 | # secretName: rootca-kuttl-public 39 | # 40 | # apiVersion: cert-manager.io/v1 41 | # kind: Certificate 42 | # metadata: 43 | # name: rootca-kuttl-public 44 | # namespace: openstack 45 | # spec: 46 | # commonName: rootca-kuttl-public 47 | # duration: 87600h0m0s 48 | # isCA: true 49 | # issuerRef: 50 | # name: selfsigned-issuer 51 | # privateKey: 52 | # algorithm: ECDSA 53 | # size: 256 54 | # secretName: rootca-kuttl-public 55 | # 56 | # Then extracted both CAs and created added them as the bundle: 57 | apiVersion: v1 58 | data: 59 | tls-ca-bundle.pem: IyByb290Y2EtaW50ZXJuYWwKLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmekNDQVNhZ0F3SUJBZ0lRUWxlcTNZcDBtU2kwVDNiTm03Q29UVEFLQmdncWhrak9QUVFEQWpBZ01SNHcKSEFZRFZRUURFeFZ5YjI5MFkyRXRhM1YwZEd3dGFXNTBaWEp1WVd3d0hoY05NalF3TVRFMU1URTBOelUwV2hjTgpNelF3TVRFeU1URTBOelUwV2pBZ01SNHdIQVlEVlFRREV4VnliMjkwWTJFdGEzVjBkR3d0YVc1MFpYSnVZV3d3CldUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTRk9rNHJPUldVUGhoTjUrK09EN1I2MW5Gb1lBY0QKenpvUS91SW93NktjeGhwRWNQTDFxb3ZZUGxUYUJabEh3c2FpNE50VHA4aDA1RHVRSGZKOE9JNXFvMEl3UURBTwpCZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVXE3TGtFSk1TCm1MOVpKWjBSOUluKzZkclhycEl3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnVlN1K00ydnZ3QlF3eTJHMVlhdkkKQld2RGtSNlRla0I5U0VqdzJIblRSMWtDSUZSNFNkWGFPQkFGWjVHa2RLWCtSY2IzaDFIZm52eFJEVW96bTl2agphenp3Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KIyByb290Y2EtcHVibGljCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlCZXpDQ0FTS2dBd0lCQWdJUU5IREdZc0JzNzk4aWJERDdxL28ybGpBS0JnZ3Foa2pPUFFRREFqQWVNUnd3CkdnWURWUVFERXhOeWIyOTBZMkV0YTNWMGRHd3RjSFZpYkdsak1CNFhEVEkwTURFeE5URXdNVFV6TmxvWERUTTAKTURFeE1qRXdNVFV6Tmxvd0hqRWNNQm9HQTFVRUF4TVRjbTl2ZEdOaExXdDFkSFJzTFhCMVlteHBZekJaTUJNRwpCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkQ3OGF2WHFocmhDNXc4czlXa2Q0SXBiZUV1MDNDUitYWFVkCmtEek9SeXhhOXdjY0lkRGl2YkdKakpGWlRUY1ZtYmpxMUJNWXNqcjEyVUlFNUVUM1ZscWpRakJBTUE0R0ExVWQKRHdFQi93UUVBd0lDcERBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJUS0ppeldVSjllVUtpMQpkczBscjZjNnNEN0VCREFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUJJWndZcTYxQnFNSmFCNlVjRm9Sc3hlY3dICjV6L3pNT2RyT3llMG1OaThKZ0lnUUxCNHdES3JwZjl0WDJsb00rMHVUb3BBRFNZSW5yY2ZWdTRGQnVZVTNJZz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= 60 | kind: Secret 61 | metadata: 62 | labels: 63 | combined-ca-bundle: "" 64 | name: combined-ca-bundle 65 | type: Opaque 66 | -------------------------------------------------------------------------------- /test/kuttl/common/tls_cert_neutron-internal-svc.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Cert created with: 3 | # 4 | # apiVersion: cert-manager.io/v1 5 | # kind: Certificate 6 | # metadata: 7 | # name: neutron-kuttl-internal-svc 8 | # namespace: openstack 9 | # spec: 10 | # dnsNames: 11 | # - neutron-internal.openstack.svc 12 | # duration: 87600h0m0s 13 | # issuerRef: 14 | # group: cert-manager.io 15 | # kind: Issuer 16 | # name: rootca-kuttl-internal 17 | # secretName: cert-neutron-internal-svc 18 | # secretTemplate: {} 19 | # usages: 20 | # - key encipherment 21 | # - digital signature 22 | # - server auth 23 | # 24 | 25 | apiVersion: v1 26 | data: 27 | ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmekNDQVNhZ0F3SUJBZ0lRUWxlcTNZcDBtU2kwVDNiTm03Q29UVEFLQmdncWhrak9QUVFEQWpBZ01SNHcKSEFZRFZRUURFeFZ5YjI5MFkyRXRhM1YwZEd3dGFXNTBaWEp1WVd3d0hoY05NalF3TVRFMU1URTBOelUwV2hjTgpNelF3TVRFeU1URTBOelUwV2pBZ01SNHdIQVlEVlFRREV4VnliMjkwWTJFdGEzVjBkR3d0YVc1MFpYSnVZV3d3CldUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTRk9rNHJPUldVUGhoTjUrK09EN1I2MW5Gb1lBY0QKenpvUS91SW93NktjeGhwRWNQTDFxb3ZZUGxUYUJabEh3c2FpNE50VHA4aDA1RHVRSGZKOE9JNXFvMEl3UURBTwpCZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVXE3TGtFSk1TCm1MOVpKWjBSOUluKzZkclhycEl3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnVlN1K00ydnZ3QlF3eTJHMVlhdkkKQld2RGtSNlRla0I5U0VqdzJIblRSMWtDSUZSNFNkWGFPQkFGWjVHa2RLWCtSY2IzaDFIZm52eFJEVW96bTl2agphenp3Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K 28 | tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNiekNDQWhXZ0F3SUJBZ0lRWG5aNTN4Wlpkd1gyTmo2NVkyR2xpekFLQmdncWhrak9QUVFEQWpBZ01SNHcKSEFZRFZRUURFeFZ5YjI5MFkyRXRhM1YwZEd3dGFXNTBaWEp1WVd3d0hoY05NalF3TVRFMk1UQTFNVFF4V2hjTgpNelF3TVRFek1UQTFNVFF4V2pBQU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBCnc4YVRnM0xnV1JoQXlxdGZLUlJVWWMyQjBRTExJY2hiRlF2M05kOE82VEdzc1htdldBdGF5ZTZZOUxuWXBZbXMKMW54ZDJ5U0tyaHVobllGVXlHdE1WZTJEb3R1cG45VEE1TS91TXJOeDd4Z2ZueFpuM3JoQ09tTGJTaVdTUkFLUQpwTCt5ZnNGUnVXck9Ob3VKVUpPMElJdmErbzJHK0t5Z0xVaGZaYWhwWHJrN3BNVzZ2RStQQVZxSmVkdmMrVEt5ClJrV1BYNlNyUk91aTlnNjVSZGlKbW9BdTkva1M2T3FTMGVOMnV6bjJwVHVLOElSZTMvRXBMQ0s4bmpsUW9LUWIKdUZkSEZyU3NWMGs4SFk4OXhLeTF3N1dzSFEwSTd4T1F0OFR5SGwwdHRxcWlWc200aTZDYStSa01LV0NDR2JXZgpwSDE1eVN4MWcvUFRNQkRubW5DdGx3SURBUUFCbzRHRk1JR0NNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WCkhTVUVEREFLQmdnckJnRUZCUWNEQVRBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZEl3UVlNQmFBRkt1eTVCQ1QKRXBpL1dTV2RFZlNKL3VuYTE2NlNNQ3dHQTFVZEVRRUIvd1FpTUNDQ0htNWxkWFJ5YjI0dGFXNTBaWEp1WVd3dQpiM0JsYm5OMFlXTnJMbk4yWXpBS0JnZ3Foa2pPUFFRREFnTklBREJGQWlFQWh6Zk8yUkMxQ0lBazgvMHpCb3ZWCmJldHBQbUI5aDlmL01ZcUlJVW1wVCtNQ0lEL0JXWlJyVWtFbVhkS2txcFVZbklCeTluUE5rMVhmM2hHOEE4VUcKUnA4bQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== 29 | tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBdzhhVGczTGdXUmhBeXF0ZktSUlVZYzJCMFFMTEljaGJGUXYzTmQ4TzZUR3NzWG12CldBdGF5ZTZZOUxuWXBZbXMxbnhkMnlTS3JodWhuWUZVeUd0TVZlMkRvdHVwbjlUQTVNL3VNck54N3hnZm54Wm4KM3JoQ09tTGJTaVdTUkFLUXBMK3lmc0ZSdVdyT05vdUpVSk8wSUl2YStvMkcrS3lnTFVoZlphaHBYcms3cE1XNgp2RStQQVZxSmVkdmMrVEt5UmtXUFg2U3JST3VpOWc2NVJkaUptb0F1OS9rUzZPcVMwZU4ydXpuMnBUdUs4SVJlCjMvRXBMQ0s4bmpsUW9LUWJ1RmRIRnJTc1YwazhIWTg5eEt5MXc3V3NIUTBJN3hPUXQ4VHlIbDB0dHFxaVZzbTQKaTZDYStSa01LV0NDR2JXZnBIMTV5U3gxZy9QVE1CRG5tbkN0bHdJREFRQUJBb0lCQUZuczRaODBhaGFpakVoTApsVWRTUGp3NllGRzRQY1FEdXNxZEYyMVlTd29VTmlYREppYUQrS3plZXNXV2hBdnRoRVYxRk10dktvQTAwdlI5CkRvdU10YUNXbTZ0M3lKOVE0MVYycVF3QzN1ZWJKaE0yQUhvT0d1V2t1T09EQkg5V3lrZlNnZE8xU3F1bmdwY04KV3dKM0Jmc1pJbm1KL3FCRThzSTZCdyt6M3NxUjd6ajJKT0dzSEtaUXorazFBbldWVklub1o0c09rY3laOEt0cgpSdzUrVFdFM0x2NWN2UVkzcjZaTHZ1TzBobnVMREZ4cDVlTVZYUmdjQk1RUFVGRGlpMS93L3lHdS9OaXdvUWJSCnhIZUxQd296LzJRVFFXUFQyK3czWWdRRTZENU42cm5ZbFNJSXBWSDRZckw4TEtKVDVYQk1TMlZ1Vi9RV2dISk8KTTYvZ3B0a0NnWUVBMm9HTDNNTmZZc09IbGxmb2cvRTlVcEY2UGN0YzZhcFozeGx5ZUNOdnJac0xXaVFESVBEYQo5ckFNbXlaSXB6QWVydk1HKythTGIzOTZGWTZwOVdVYXNvMzVqNk1RNWpYeDJVdjFWVXl4L3NZSkllWUtxNFhLCklFZ01ldS9aQW9zTGpoM1ZOcU9Db1d1U2I2bEZlRnJ5QkpUbklmRVZvRGN2VjN0ZGFjdm51V1VDZ1lFQTVWNksKRGMwZHphTktuQWg1RFhtdGRqdE4reHJ4UElWbm9oOXZzbnpzc1FvQlZiek9aYzNmMmc4NGFtVjhhMkEvWU9GaApwTUQ4djZ5aDREZG10QkxXVDc0VWF6a3VhWkRDTE1NOVRkb3lNTm55b21yQ2laS1NoSElzK0dHeDRFb29qRSszCjBuWU5rVHhod2RqdzNvbzJaNitOWmo1eWVxQUhFeGJ4bzhUQW1Vc0NnWUEwUStCc2dkOERCTG9kNEJFaDNrWkkKeGJ0enBIMG85ekpnQnZvMmVtTndKekhqOGRFOXc5N2NPdWdKQkhORWFtSXNmcjBnNjloV1p5dVFsSHRhMDBBNwpqWEl3UlZUNWU5WEpvRDJpbGFITnl4ak1IdlpXYUw0Y1VwK0ptRzFVQ21aTkxCMmY0Q1NTNytRckNWWXduN0JjCklESFpFSTJYc1J1RjFXQld1Z3RIY1FLQmdRQ01uc2crcTlrd3dJSzJaSTlxam9XbExiaWlVU05DdW5zTnJ2NDQKekZRRU9pRVZZbHFibVhzNjRnZnhXdVRMbzhkWGF2WUZIdmdWdnczRE85UHdaSGdWalhCUlNFNUhGQ09uYzg4NgowcUhneDAzMCswVG5PUUF3eVJyKzhFNHdOdWJqRnVDWTNCMTNSRENldXBUNXFueXVWcmQyenFRNnY2OTJxYU5kCmh2dVpQd0tCZ0VFNUpIL0l4ZCtLQXVhbS92QTJXbFhuZU5RcW1JMG5iZlQxRlRsWmNLR0xzRjN6aVRGV2RzV2IKdk5abVFOUzlsWE4rZDVUTUxLVndKME5DRU43azhKdy9ZWCtVemdUZGtPZ21WL2ZycmpvMzAzWVN5VlljSE9MTgpINFFoeUU2VVBUM2FQSnFCcWFtQndxSTdtOW1YTVlsN3NWOGMvMzhjbE9zOUxUbHBxV1ZvCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== 30 | kind: Secret 31 | metadata: 32 | annotations: 33 | cert-manager.io/alt-names: neutron-internal.openstack.svc 34 | cert-manager.io/certificate-name: neutron-kuttl-internal-svc 35 | cert-manager.io/common-name: "" 36 | cert-manager.io/ip-sans: "" 37 | cert-manager.io/issuer-group: cert-manager.io 38 | cert-manager.io/issuer-kind: Issuer 39 | cert-manager.io/issuer-name: rootca-kuttl-internal 40 | cert-manager.io/uri-sans: "" 41 | labels: 42 | controller.cert-manager.io/fao: "true" 43 | name: cert-neutron-internal-svc 44 | type: kubernetes.io/tls 45 | -------------------------------------------------------------------------------- /test/kuttl/common/tls_cert_neutron-public-svc.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Cert created with: 3 | # 4 | # apiVersion: cert-manager.io/v1 5 | # kind: Certificate 6 | # metadata: 7 | # name: kuttl-neutron-public-svc 8 | # namespace: openstack 9 | # spec: 10 | # dnsNames: 11 | # - neutron-public.openstack.svc 12 | # duration: 87600h0m0s 13 | # issuerRef: 14 | # group: cert-manager.io 15 | # kind: Issuer 16 | # name: rootca-kuttl-public 17 | # secretName: cert-neutron-public-svc 18 | # secretTemplate: {} 19 | # usages: 20 | # - key encipherment 21 | # - digital signature 22 | # - server auth 23 | 24 | apiVersion: v1 25 | data: 26 | ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlekNDQVNLZ0F3SUJBZ0lRTkhER1lzQnM3OThpYkREN3EvbzJsakFLQmdncWhrak9QUVFEQWpBZU1Sd3cKR2dZRFZRUURFeE55YjI5MFkyRXRhM1YwZEd3dGNIVmliR2xqTUI0WERUSTBNREV4TlRFd01UVXpObG9YRFRNMApNREV4TWpFd01UVXpObG93SGpFY01Cb0dBMVVFQXhNVGNtOXZkR05oTFd0MWRIUnNMWEIxWW14cFl6QlpNQk1HCkJ5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCRDc4YXZYcWhyaEM1dzhzOVdrZDRJcGJlRXUwM0NSK1hYVWQKa0R6T1J5eGE5d2NjSWREaXZiR0pqSkZaVFRjVm1ianExQk1Zc2pyMTJVSUU1RVQzVmxxalFqQkFNQTRHQTFVZApEd0VCL3dRRUF3SUNwREFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQjBHQTFVZERnUVdCQlRLSml6V1VKOWVVS2kxCmRzMGxyNmM2c0Q3RUJEQUtCZ2dxaGtqT1BRUURBZ05IQURCRUFpQklad1lxNjFCcU1KYUI2VWNGb1JzeGVjd0gKNXovek1PZHJPeWUwbU5pOEpnSWdRTEI0d0RLcnBmOXRYMmxvTSswdVRvcEFEU1lJbnJjZlZ1NEZCdVlVM0lnPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== 27 | tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNiRENDQWhLZ0F3SUJBZ0lSQUw2YW8zbUFKVmV0OUFPMlpPSzIrQVF3Q2dZSUtvWkl6ajBFQXdJd0hqRWMKTUJvR0ExVUVBeE1UY205dmRHTmhMV3QxZEhSc0xYQjFZbXhwWXpBZUZ3MHlOREF4TVRZeE1UQXlNamhhRncwegpOREF4TVRNeE1UQXlNamhhTUFBd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURRCmNkT0s0bVRiYTBJazB1V1E1RTFucEY2V3ppam15aXlUNS80dHlGRWpkeEdlaExTdjRlSHJOdm5ldEVBRnRFQlAKNjBwMGZkSzRZL05SRmxCL2czeERzNGFwdW5NTDhoR1BJbnFaYnZsa2tTT1h1ZXRHK29hL1gzMXVyUlBIT2tWbgpKbis0RWtBTmZEdExnQ21jRWViVDZHYkFPUnpuMWNGc1UwWENQazJOWFZOTEwrUVZGazhjNmRJV2M5eVpBbG85ClhIMitzN0hENXk0bWJDejV2dHpLKzV6akZkeHVGZ2QweExtZzduZ0NxMkorYm5TZ3dndm9Wb3dGZ3Q0Y21Yb1cKZjI4QU5Bb1E2citvUlFEZmVyaVRhbGxRSWZ1QzVJcW40ZDAxMWpGZ2thZWxRaVVCS1Z2NTZPTkdhdHM1b0IweApPbVo5NVpKMk1lMFRNTFhUYUpHSEFnTUJBQUdqZ1lNd2dZQXdEZ1lEVlIwUEFRSC9CQVFEQWdXZ01CTUdBMVVkCkpRUU1NQW9HQ0NzR0FRVUZCd01CTUF3R0ExVWRFd0VCL3dRQ01BQXdId1lEVlIwakJCZ3dGb0FVeWlZczFsQ2YKWGxDb3RYYk5KYStuT3JBK3hBUXdLZ1lEVlIwUkFRSC9CQ0F3SG9JY2JtVjFkSEp2Ymkxd2RXSnNhV011YjNCbApibk4wWVdOckxuTjJZekFLQmdncWhrak9QUVFEQWdOSUFEQkZBaUI1Z3EwTXpQeEFHNnVscFFNVjE3VHdSNld3CnJERGROTEpsclhkL0cvak56Z0loQUtGODRTQ2ZOQ2ZjdmowTTM3NitvemVZLzdlZVJ1SmNkVHVkVEhRaTV2Q1YKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= 28 | tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBMEhIVGl1SmsyMnRDSk5MbGtPUk5aNlJlbHM0bzVzb3NrK2YrTGNoUkkzY1Jub1MwCnIrSGg2emI1M3JSQUJiUkFUK3RLZEgzU3VHUHpVUlpRZjROOFE3T0dxYnB6Qy9JUmp5SjZtVzc1WkpFamw3bnIKUnZxR3YxOTlicTBUeHpwRlp5Wi91QkpBRFh3N1M0QXBuQkhtMCtobXdEa2M1OVhCYkZORndqNU5qVjFUU3kvawpGUlpQSE9uU0ZuUGNtUUphUFZ4OXZyT3h3K2N1Sm13cytiN2N5dnVjNHhYY2JoWUhkTVM1b081NEFxdGlmbTUwCm9NSUw2RmFNQllMZUhKbDZGbjl2QURRS0VPcS9xRVVBMzNxNGsycFpVQ0g3Z3VTS3ArSGROZFl4WUpHbnBVSWwKQVNsYitlampSbXJiT2FBZE1UcG1mZVdTZGpIdEV6QzEwMmlSaHdJREFRQUJBb0lCQVFDb0JxbU04aFIxSDVBUgpHUVErK1JwQWFxcHBERVRDVGNVRGNXWmV4M1JJajJuZmk0QVBxNWt1djRGS2VhaUdNSmdMRkZOUGRrSFBxNXB2CkNmclgzMGpqVmlzK1ZITDY5U1ljYUtIRlgwU2dRYk1jVXAySytOWjRHK1NEdS9jT2lUVjdBZmpBaTgyZ1VUMkgKRGdmOHJCMlRRbXJabHZCckhjOHVvQzNDZC9DUisyMStzZGovZFh1UUlaSk1LbHRHTGJDcUVTek5laDBpaTFZKwpTNE91ekV6eGNUb01tT0U4eWs0VlgydUtZOWpTNEd0VE51bkp0Z1lsSVZ0Q3ZOMThCL0R2RGtHRVhDSVkyNVltCmMxTHBMbzZXcThkckk2T3N4S2s2VXQ3blpEVkU4QlFXZFMxT0NNbGhvdy9xTVYvTFlvRXFxbGhLd29qeHJsN3oKQzhJY3dpZTVBb0dCQU9RMDdGaUM1angvR3NVTGcwVlhrYTE0SHpxeElwdUR3MjJzNWZrT2NCNzNHazJWMnh2cgp5bnBONXl0VHNhcmY2OVRFaDdjZkFSeURpYlA2V3NOUVlGdCs3Nmc0bno5Y282SFpQSzNBVGh4M0YzbVA3bDFZCnZkaGhYVldjY0QxNWNPVGsxaUorWkxiUnR1eDdZVzV6YVVUcHE1ZmlQWENsNjJXV3YyMXJJTTNOQW9HQkFPblUKd2FBVStXYnJ6VG9TUnk3K3djWjlDWTJDd1BJMnZJbHV5cnBLMXBYeW9ZSGRKVjBDNHRmcmFobUY3QXlxY3hOcgpXK3dFMVlhV2FNYVpJUVRkdGFyQjZ3VkRkaWVBZEFoSFR2Tm8wdHRJMXl5Y1hKU2FGQTh5OUdKOUZxSVRXQ3d3CmR6dmY2TVlKNlZaR0k0S1JMaHJySUVuZ0pnSTFSQXBQeG03UlU2aWpBb0dBR2hQV0lqTXJIaVNrS1hvc1VRTTEKdVczdG02WmNQd3Nxak9EaUVyak1wUzAxaTBJaG5Lb3dKQk84NDkyWGd1QTlzYjJYaUp4NVl3bkE5WmtaUUJKeQpRR0piL293aDNucTJsQ3NmM1BjSnRnVUI0TGxLMHMzdU84aThncWp5eG9PWEhBRHVXMWk0SjVBRmFEYWRKcUwzCmw1RmdNMlgrQVY1a2JPSnlFNDNYWE0wQ2dZRUFqem9weS9Ocy9QVHN4V2hTdjk5K05DVjh4M2hTMVVwZjI5TEkKVEtud25QSjhxVDRiVjhpZnlHQkRvaFNkRFBrTytkTW1BQURLQmVGMWxraFBxRnBobjVHZWNwL3E3TEZLNFpORQpNZWFBV1o5WlpkTDFCblVHV25UOHFxTXlUTjZLZ0s3REtpS3h3elJvLzlhQWc4YUh0aWRWcE1xdW5XV2hJcXZRCndTcHBFdjhDZ1lFQW9BWlRnclNSUlhpcncrVVlXY00zQ2trYXdsWGFkQmdRN0h4bFFrL281QnZRNy9HdXR4RDEKT25OM0lhK2g1eVVPRm0yZHRoNEJWeW9iUnJ5SHA2NkptamZFRjF0Y2lkUWoyVDJwM0hBU1hqeXN5cXlOWkFDVApkVHVHYnUrMHVkNFA2emMydVUwbWJMdHkrNUgwN3M5cXRZTVdnRDQ0VWhmbGNwd3BrSE9lbHJjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= 29 | kind: Secret 30 | metadata: 31 | annotations: 32 | cert-manager.io/alt-names: neutron-public.openstack.svc 33 | cert-manager.io/certificate-name: cert-neutron-kuttl-public-svc 34 | cert-manager.io/common-name: "" 35 | cert-manager.io/ip-sans: "" 36 | cert-manager.io/issuer-group: cert-manager.io 37 | cert-manager.io/issuer-kind: Issuer 38 | cert-manager.io/issuer-name: rootca-kuttl-public 39 | cert-manager.io/uri-sans: "" 40 | labels: 41 | controller.cert-manager.io/fao: "true" 42 | name: cert-neutron-public-svc 43 | type: kubernetes.io/tls 44 | -------------------------------------------------------------------------------- /test/kuttl/tests/change_neutron_config/00-assert.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Check for: 3 | # 4 | # - Secret 5 | # - ConfigMap 6 | 7 | apiVersion: v1 8 | kind: Secret 9 | metadata: 10 | name: test-secret-vol 11 | --- 12 | apiVersion: v1 13 | kind: ConfigMap 14 | metadata: 15 | name: test-configmap-vol 16 | -------------------------------------------------------------------------------- /test/kuttl/tests/change_neutron_config/00-test-resources.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # test-secret-vol Secret 3 | # test-configmap-vol ConfiMap 4 | # 5 | apiVersion: v1 6 | kind: Secret 7 | metadata: 8 | name: test-secret-vol 9 | data: 10 | testsecret.conf: W0RFRkFVTFRdCnJwY193b3JrZXJzID0gMAo= 11 | --- 12 | apiVersion: v1 13 | kind: ConfigMap 14 | metadata: 15 | name: test-configmap-vol 16 | data: 17 | testcm.conf: | 18 | [DEFAULT] 19 | api_workers = 1 20 | -------------------------------------------------------------------------------- /test/kuttl/tests/change_neutron_config/01-assert.yaml: -------------------------------------------------------------------------------- 1 | ../../common/assert_sample_deployment.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/change_neutron_config/01-deploy-neutron.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | cp ../../../../config/samples/neutron_v1beta1_neutronapi.yaml deploy 6 | oc kustomize deploy | oc apply -n $NAMESPACE -f - 7 | -------------------------------------------------------------------------------- /test/kuttl/tests/change_neutron_config/02-assert.yaml: -------------------------------------------------------------------------------- 1 | # check that by default, debug is set in neutron config 2 | apiVersion: kuttl.dev/v1beta1 3 | kind: TestAssert 4 | commands: 5 | - script: | 6 | ../../common/scripts/check_debug_in_neutron_pod_logs.sh 7 | - script: | 8 | neutron_pod=$(oc get pods -n $NAMESPACE -l service=neutron --field-selector=status.phase=Running -o name|head -1) 9 | oc rsh -n $NAMESPACE ${neutron_pod} crudini --get /etc/neutron/neutron.conf.d/testcm.conf DEFAULT api_workers 10 | oc rsh -n $NAMESPACE ${neutron_pod} crudini --get /etc/neutron/neutron.conf.d/testsecret.conf DEFAULT rpc_workers 11 | # Check config in pod logs 12 | oc logs -n $NAMESPACE ${neutron_pod} | grep -q "api_workers.*= 1" 13 | oc logs -n $NAMESPACE ${neutron_pod} | grep -q "rpc_workers.*= 0" 14 | -------------------------------------------------------------------------------- /test/kuttl/tests/change_neutron_config/02-extramounts.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: neutron.openstack.org/v1beta1 2 | kind: NeutronAPI 3 | metadata: 4 | name: neutron 5 | spec: 6 | extraMounts: 7 | - extraVol: 8 | - volumes: 9 | - name: test-configmap-vol 10 | configMap: 11 | name: test-configmap-vol 12 | - name: test-secret-vol 13 | secret: 14 | secretName: test-secret-vol 15 | mounts: 16 | - name: test-configmap-vol 17 | mountPath: /etc/neutron/neutron.conf.d/testcm.conf 18 | subPath: testcm.conf 19 | readOnly: true 20 | - name: test-secret-vol 21 | mountPath: /etc/neutron/neutron.conf.d/testsecret.conf 22 | subPath: testsecret.conf 23 | readOnly: false 24 | -------------------------------------------------------------------------------- /test/kuttl/tests/change_neutron_config/03-assert.yaml: -------------------------------------------------------------------------------- 1 | # check that now, debug is not set in neutron config 2 | apiVersion: kuttl.dev/v1beta1 3 | kind: TestAssert 4 | commands: 5 | - script: | 6 | ../../common/scripts/check_debug_in_neutron_pod_logs.sh 7 | test $? -ne 0 8 | -------------------------------------------------------------------------------- /test/kuttl/tests/change_neutron_config/03-change_neutron_debug_config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: neutron.openstack.org/v1beta1 2 | kind: NeutronAPI 3 | metadata: 4 | name: neutron 5 | spec: 6 | customServiceConfig: | 7 | [DEFAULT] 8 | debug = false 9 | -------------------------------------------------------------------------------- /test/kuttl/tests/change_neutron_config/04-cleanup-neutron.yaml: -------------------------------------------------------------------------------- 1 | ../../common/cleanup-neutron.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/change_neutron_config/04-errors.yaml: -------------------------------------------------------------------------------- 1 | ../../common/errors_cleanup_neutron.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/change_neutron_config/deploy/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ./neutron_v1beta1_neutronapi.yaml 5 | patches: 6 | - patch: |- 7 | - op: replace 8 | path: /spec/secret 9 | value: osp-secret 10 | - op: remove 11 | path: /metadata/namespace 12 | target: 13 | kind: NeutronAPI 14 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_no_ovn/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: neutron.openstack.org/v1beta1 2 | kind: NeutronAPI 3 | metadata: 4 | finalizers: 5 | - openstack.org/neutronapi 6 | name: neutron 7 | spec: 8 | replicas: 1 9 | ml2MechanismDrivers: 10 | - openvswitch 11 | status: 12 | readyCount: 1 13 | --- 14 | apiVersion: apps/v1 15 | kind: Deployment 16 | metadata: 17 | name: neutron 18 | spec: 19 | replicas: 1 20 | status: 21 | availableReplicas: 1 22 | readyReplicas: 1 23 | replicas: 1 24 | updatedReplicas: 1 25 | --- 26 | apiVersion: v1 27 | kind: Pod 28 | metadata: 29 | labels: 30 | service: neutron 31 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_no_ovn/01-deploy-neutron.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | cp ../../../../config/samples/neutron_v1beta1_neutronapi_openvswitch.yaml deploy 6 | oc kustomize deploy | oc apply -n $NAMESPACE -f - 7 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_no_ovn/02-cleanup-neutron.yaml: -------------------------------------------------------------------------------- 1 | ../../common/cleanup-neutron.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_no_ovn/02-errors.yaml: -------------------------------------------------------------------------------- 1 | ../../common/errors_cleanup_neutron.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_no_ovn/deploy/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ./neutron_v1beta1_neutronapi_openvswitch.yaml 5 | patches: 6 | - patch: |- 7 | - op: replace 8 | path: /spec/secret 9 | value: osp-secret 10 | - op: remove 11 | path: /metadata/namespace 12 | target: 13 | kind: NeutronAPI 14 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_scale/01-assert.yaml: -------------------------------------------------------------------------------- 1 | ../../common/assert_sample_deployment.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_scale/01-deploy-neutron.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | cp ../../../../config/samples/neutron_v1beta1_neutronapi.yaml deploy 6 | oc kustomize deploy | oc apply -n $NAMESPACE -f - 7 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_scale/02-assert.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Check for: 3 | # 4 | # - 1 NeutronAPI CR 5 | # - 3 Pods for NeutronAPI CR 6 | # 7 | 8 | apiVersion: neutron.openstack.org/v1beta1 9 | kind: NeutronAPI 10 | metadata: 11 | finalizers: 12 | - openstack.org/neutronapi 13 | name: neutron 14 | spec: 15 | replicas: 3 16 | status: 17 | readyCount: 3 18 | --- 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | name: neutron 23 | spec: 24 | replicas: 3 25 | status: 26 | availableReplicas: 3 27 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_scale/02-scale-neutronapi.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | oc patch neutronapi -n $NAMESPACE neutron --type='json' -p='[{"op": "replace", "path": "/spec/replicas", "value":3}]' 6 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_scale/03-assert.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Check for: 3 | # 4 | # - 1 NeutronAPI CR 5 | # - 1 Pods for NeutronAPI CR 6 | # 7 | 8 | apiVersion: neutron.openstack.org/v1beta1 9 | kind: NeutronAPI 10 | metadata: 11 | finalizers: 12 | - openstack.org/neutronapi 13 | name: neutron 14 | spec: 15 | replicas: 1 16 | status: 17 | readyCount: 1 18 | --- 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | name: neutron 23 | spec: 24 | replicas: 1 25 | status: 26 | availableReplicas: 1 27 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_scale/03-scale-down-neutronapi.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | oc patch neutronapi -n $NAMESPACE neutron --type='json' -p='[{"op": "replace", "path": "/spec/replicas", "value":1}]' 6 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_scale/04-assert.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Check for: 3 | # 4 | # - NeutronAPI CR with no replicas 5 | # - Neutron Deployment with 0 Pods 6 | # 7 | 8 | apiVersion: neutron.openstack.org/v1beta1 9 | kind: NeutronAPI 10 | metadata: 11 | finalizers: 12 | - openstack.org/neutronapi 13 | name: neutron 14 | spec: 15 | replicas: 0 16 | --- 17 | apiVersion: apps/v1 18 | kind: Deployment 19 | metadata: 20 | name: neutron 21 | spec: 22 | replicas: 0 23 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_scale/04-errors.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | annotations: 5 | openshift.io/scc: anyuid 6 | labels: 7 | service: neutron 8 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_scale/04-scale-down-zero-neutronapi.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | oc patch neutronapi -n $NAMESPACE neutron --type='json' -p='[{"op": "replace", "path": "/spec/replicas", "value":0}]' 6 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_scale/05-cleanup-neutron.yaml: -------------------------------------------------------------------------------- 1 | ../../common/cleanup-neutron.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_scale/05-errors.yaml: -------------------------------------------------------------------------------- 1 | ../../common/errors_cleanup_neutron.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_scale/deploy/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ./neutron_v1beta1_neutronapi.yaml 5 | patches: 6 | - patch: |- 7 | - op: replace 8 | path: /spec/secret 9 | value: osp-secret 10 | - op: remove 11 | path: /metadata/namespace 12 | target: 13 | kind: NeutronAPI 14 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_tls/00-assert.yaml: -------------------------------------------------------------------------------- 1 | ../../common/assert_tls_cert.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_tls/00-tls_ca_bundle.yaml: -------------------------------------------------------------------------------- 1 | ../../common/tls_ca_bundle.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_tls/00-tls_cert_neutron-internal-svc.yaml: -------------------------------------------------------------------------------- 1 | ../../common/tls_cert_neutron-internal-svc.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_tls/00-tls_cert_neutron-public-svc.yaml: -------------------------------------------------------------------------------- 1 | ../../common/tls_cert_neutron-public-svc.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_tls/01-assert.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Check for: 3 | # 4 | # - 1 NeutronAPI CR 5 | # - Deployment with tls volumes 6 | 7 | apiVersion: neutron.openstack.org/v1beta1 8 | kind: NeutronAPI 9 | metadata: 10 | name: neutron 11 | spec: 12 | tls: 13 | api: 14 | internal: 15 | secretName: cert-neutron-internal-svc 16 | public: 17 | secretName: cert-neutron-public-svc 18 | caBundleSecretName: combined-ca-bundle 19 | status: 20 | readyCount: 1 21 | --- 22 | apiVersion: apps/v1 23 | kind: Deployment 24 | metadata: 25 | name: neutron 26 | spec: 27 | replicas: 1 28 | template: 29 | metadata: 30 | labels: 31 | service: neutron 32 | spec: 33 | containers: 34 | - args: 35 | - -c 36 | - /usr/local/bin/kolla_start 37 | volumeMounts: 38 | - mountPath: /var/lib/config-data/default 39 | name: config 40 | readOnly: true 41 | - mountPath: /var/lib/kolla/config_files/config.json 42 | name: config 43 | readOnly: true 44 | subPath: neutron-api-config.json 45 | - mountPath: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem 46 | name: combined-ca-bundle 47 | readOnly: true 48 | subPath: tls-ca-bundle.pem 49 | - args: 50 | - -c 51 | - /usr/local/bin/kolla_start 52 | volumeMounts: 53 | - mountPath: /var/lib/config-data/default 54 | name: httpd-config 55 | readOnly: true 56 | - mountPath: /var/lib/kolla/config_files/config.json 57 | name: config 58 | readOnly: true 59 | subPath: neutron-httpd-config.json 60 | - mountPath: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem 61 | name: combined-ca-bundle 62 | readOnly: true 63 | subPath: tls-ca-bundle.pem 64 | - mountPath: /etc/pki/tls/certs/internal.crt 65 | name: internal-tls-certs 66 | readOnly: true 67 | subPath: tls.crt 68 | - mountPath: /etc/pki/tls/private/internal.key 69 | name: internal-tls-certs 70 | readOnly: true 71 | subPath: tls.key 72 | - mountPath: /etc/pki/tls/certs/public.crt 73 | name: public-tls-certs 74 | readOnly: true 75 | subPath: tls.crt 76 | - mountPath: /etc/pki/tls/private/public.key 77 | name: public-tls-certs 78 | readOnly: true 79 | subPath: tls.key 80 | volumes: 81 | - name: config 82 | secret: 83 | defaultMode: 420 84 | secretName: neutron-config 85 | - name: httpd-config 86 | secret: 87 | defaultMode: 420 88 | secretName: neutron-httpd-config 89 | - name: combined-ca-bundle 90 | secret: 91 | defaultMode: 292 92 | secretName: combined-ca-bundle 93 | - name: internal-tls-certs 94 | secret: 95 | defaultMode: 256 96 | secretName: cert-neutron-internal-svc 97 | - name: public-tls-certs 98 | secret: 99 | defaultMode: 256 100 | secretName: cert-neutron-public-svc 101 | --- 102 | # the actual addresses of the api endpoints are platform specific, so we can't rely on 103 | # kuttl asserts to check them. This short script gathers the addresses and checks that 104 | # the two endpoints are defined and their addresses follow the default pattern 105 | apiVersion: kuttl.dev/v1beta1 106 | kind: TestAssert 107 | commands: 108 | - script: | 109 | template='{{.spec.endpoints.internal}}{{":"}}{{.spec.endpoints.public}}{{"\n"}}' 110 | regex="https:\/\/neutron-internal.$NAMESPACE.*:https:\/\/neutron-public.$NAMESPACE.*" 111 | apiEndpoints=$(oc get -n $NAMESPACE KeystoneEndpoint neutron -o go-template="$template") 112 | matches=$(echo "$apiEndpoints" | sed -e "s?$regex??") 113 | if [[ -n "$matches" ]]; then 114 | exit 1 115 | fi 116 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_tls/01-deploy-neutron.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | - script: | 5 | cp ../../../../config/samples/neutron_v1beta1_neutronapi_tls.yaml deploy 6 | oc kustomize deploy | oc apply -n $NAMESPACE -f - 7 | -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_tls/02-cleanup-neutron.yaml: -------------------------------------------------------------------------------- 1 | ../../common/cleanup-neutron.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_tls/02-errors.yaml: -------------------------------------------------------------------------------- 1 | ../../common/errors_cleanup_neutron.yaml -------------------------------------------------------------------------------- /test/kuttl/tests/neutron_tls/deploy/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ./neutron_v1beta1_neutronapi_tls.yaml 5 | patches: 6 | - patch: |- 7 | - op: replace 8 | path: /spec/secret 9 | value: osp-secret 10 | - op: remove 11 | path: /metadata/namespace 12 | target: 13 | kind: NeutronAPI 14 | -------------------------------------------------------------------------------- /zuul.d/jobs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - job: 3 | name: neutron-operator-tempest-multinode 4 | parent: podified-multinode-edpm-deployment-crc 5 | dependencies: ["openstack-k8s-operators-content-provider"] 6 | irrelevant-files: 7 | - .*/*.md 8 | - ^.github/.*$ 9 | - .ci-operator.yaml 10 | - .dockerignore 11 | - .gitignore 12 | - .golangci.yaml 13 | - .pre-commit-config.yaml 14 | - .prow_ci.env 15 | - ^LICENSE.*$ 16 | - ^OWNERS$ 17 | - ^OWNERS_ALIASES$ 18 | - ^PROJECT$ 19 | - .*go.(mod|sum|work).* 20 | - ^kuttl-test.yaml$ 21 | - ^renovate.json$ 22 | - ^config/samples/.*$ 23 | - ^docs?/.* 24 | - ^hack/.*$ 25 | - ^tests?/functional/.*$ 26 | - ^tests?/kuttl/.*$ 27 | - ^zuul.d/(?!(project)).*\.yaml 28 | vars: 29 | cifmw_tempest_container: openstack-tempest-all 30 | cifmw_run_test_role: tempest 31 | cifmw_tempest_tempestconf_profile: 32 | overrides: 33 | compute-feature-enabled.vnc_console: true 34 | validation.run_validation: true 35 | # NOTE(gibi): This is a WA to force the publicURL as otherwise 36 | # tempest gets configured with adminURL and that causes test 37 | # instability. 38 | identity.v3_endpoint_type: public 39 | identity.v2_admin_endpoint_type: public 40 | cifmw_tempest_tests_allowed: 41 | - neutron_tempest_plugin.api 42 | - neutron_tempest_plugin.scenario 43 | # To check metadata with and without config drive 44 | - tempest.scenario.test_server_basic_ops.TestServerBasicOps.test_server_basic_ops 45 | cifmw_tempest_tests_skipped: 46 | # https://review.opendev.org/892839 47 | - neutron_tempest_plugin.scenario.test_mtu.NetworkWritableMtuTest 48 | # missing https://review.opendev.org/882818 in antelope 49 | - test_qos_dscp_create_and_update 50 | # Limit job runtime 51 | - NetworkSecGroupTest 52 | -------------------------------------------------------------------------------- /zuul.d/project.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - project: 3 | name: openstack-k8s-operators/neutron-operator 4 | github-check: 5 | jobs: 6 | - openstack-k8s-operators-content-provider 7 | - neutron-operator-tempest-multinode 8 | --------------------------------------------------------------------------------