├── .dockerignore ├── .fossa.yml ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ └── feature_request.yaml ├── actions │ └── run-integ-test │ │ └── action.yml ├── pull_request_template.md └── workflows │ ├── add_to_project.yaml │ ├── check_pr_linked_issue.yaml │ ├── kindIntegTest.yml │ ├── operatorBuildAndDeploy.yml │ ├── release.yml │ └── workflow-integration-tests.yaml ├── .gitignore ├── CHANGELOG.md ├── Dockerfile ├── LICENSE.txt ├── Makefile ├── PROJECT ├── README.md ├── apis ├── cassandra │ └── v1beta1 │ │ ├── cassandradatacenter_types.go │ │ ├── cassandradatacenter_types_test.go │ │ ├── cdc_types.go │ │ ├── groupversion_info.go │ │ └── zz_generated.deepcopy.go ├── config │ └── v1beta1 │ │ ├── groupversion_info.go │ │ ├── imageconfig_types.go │ │ ├── operatorconfig_types.go │ │ └── zz_generated.deepcopy.go └── control │ └── v1alpha1 │ ├── cassandratask_types.go │ ├── groupversion_info.go │ ├── scheduledtask_types.go │ └── zz_generated.deepcopy.go ├── cmd └── main.go ├── config ├── certmanager │ ├── certificate.yaml │ ├── kustomization.yaml │ └── kustomizeconfig.yaml ├── components │ ├── clusterscope │ │ └── kustomization.yaml │ ├── namespace │ │ ├── kustomization.yaml │ │ └── ns.yaml │ └── webhook │ │ ├── controller_manager_config.yaml │ │ ├── kustomization.yaml │ │ ├── kustomizeconfig.yaml │ │ └── patches │ │ └── manager_webhook_patch.yaml ├── crd │ ├── bases │ │ ├── cassandra.datastax.com_cassandradatacenters.yaml │ │ ├── control.k8ssandra.io_cassandratasks.yaml │ │ └── control.k8ssandra.io_scheduledtasks.yaml │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ └── patches │ │ ├── config_removal.yaml │ │ └── remove_xkeys.yaml ├── default │ ├── kustomization.yaml │ ├── manager_config_patch.yaml │ ├── manager_metrics_patch.yaml │ └── metrics_service.yaml ├── deployments │ ├── cluster │ │ └── kustomization.yaml │ └── default │ │ └── kustomization.yaml ├── logger │ └── vector_config.toml ├── manager │ ├── controller_manager_config.yaml │ ├── image_config.yaml │ ├── kustomization.yaml │ └── manager.yaml ├── manifests │ ├── bases │ │ └── cass-operator.clusterserviceversion.yaml │ ├── images │ │ └── ds.png │ ├── kustomization.yaml │ └── patches │ │ ├── description-replacement.yaml │ │ ├── spec-descriptors.yaml │ │ └── status-descriptors.yaml ├── network-policy │ ├── allow-metrics-traffic.yaml │ ├── allow-webhook-traffic.yaml │ └── kustomization.yaml ├── prometheus │ ├── kustomization.yaml │ └── monitor.yaml ├── rbac │ ├── cassandradatacenter_editor_role.yaml │ ├── cassandradatacenter_viewer_role.yaml │ ├── kustomization.yaml │ ├── leader_election_role.yaml │ ├── leader_election_role_binding.yaml │ ├── metrics_auth_role.yaml │ ├── metrics_auth_role_binding.yaml │ ├── metrics_reader_role.yaml │ ├── role.yaml │ ├── role_binding.yaml │ └── service_account.yaml ├── samples │ ├── cassandratask-cleanup.yaml │ ├── cassandratask-replacenode.yaml │ ├── cassandratask-sstables.yaml │ ├── example-cassdc-three-nodes-single-rack.yaml │ ├── kustomization.yaml │ └── scheduledtask.yaml ├── scorecard │ ├── bases │ │ └── config.yaml │ ├── kustomization.yaml │ └── patches │ │ ├── basic.config.yaml │ │ └── olm.config.yaml └── webhook │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ ├── manifests.yaml │ └── service.yaml ├── docs ├── developer │ ├── config.md │ ├── csv-description.md │ ├── diagrams │ │ ├── scale-up-diagram.mmd │ │ ├── scale-up-diagram.svg │ │ ├── update-diagram.mmd │ │ └── update-diagram.svg │ ├── kind.md │ ├── mocks.md │ ├── release-process.md │ ├── seeds.md │ ├── validating_webhook.md │ └── workflow_details.md ├── ingress │ ├── README.md │ ├── sample-cluster-sample-dc.yaml │ ├── sample-java-application │ │ ├── .gitignore │ │ ├── README.md │ │ ├── lib │ │ │ └── jSSLKeyLog.jar │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── datastax │ │ │ │ │ └── kubernetes │ │ │ │ │ ├── KubernetesIngressAddressTranslator.java │ │ │ │ │ ├── KubernetesOption.java │ │ │ │ │ └── SampleApp.java │ │ │ └── resources │ │ │ │ ├── direct.conf │ │ │ │ ├── ingress.conf │ │ │ │ ├── logback.xml │ │ │ │ ├── mtls-sni-ingress.conf │ │ │ │ └── sni-ingress.conf │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── datastax │ │ │ └── examples │ │ │ └── AppTest.java │ └── ssl │ │ ├── README.md │ │ ├── ca.csr.json │ │ ├── client.csr.json │ │ ├── client.keystore │ │ ├── client.truststore │ │ └── ingress.csr.json └── user │ ├── README.md │ └── jvm_server_configuration.md ├── go.mod ├── go.sum ├── hack ├── boilerplate.go.txt ├── cluster.sh ├── gatekeeper.sh ├── gatekeeper │ └── kustomization.yaml └── license-prepend │ ├── license-header.txt │ └── license-prepend.sh ├── internal ├── controllers │ ├── cassandra │ │ ├── cassandradatacenter_controller.go │ │ ├── cassandradatacenter_controller_test.go │ │ └── suite_test.go │ └── control │ │ ├── cassandratask_controller.go │ │ ├── cassandratask_controller_test.go │ │ ├── jobs.go │ │ ├── scheduledtask_controller.go │ │ ├── scheduledtask_controller_test.go │ │ └── suite_test.go ├── envtest │ ├── fake_mgmtapi.go │ └── statefulset_controller.go ├── result │ ├── result_helper.go │ └── result_helper_test.go └── webhooks │ └── cassandra │ └── v1beta1 │ ├── cassandradatacenter_webhook.go │ ├── cassandradatacenter_webhook_test.go │ └── webhook_suite_test.go ├── logger.Dockerfile ├── operator ├── docker │ └── ubi │ │ └── LICENSE ├── example-cassdc-yaml │ ├── cassandra-3.11.x │ │ ├── example-cassdc-full.yaml │ │ ├── example-cassdc-minimal.yaml │ │ └── example-cassdc-three-rack-three-node.yaml │ └── dse-6.8.x │ │ ├── example-cassdc-full.yaml │ │ ├── example-cassdc-minimal.yaml │ │ └── example-cassdc-three-rack-three-node.yaml └── k8s-flavors │ ├── aks │ └── storage.yaml │ ├── eks │ └── storage.yaml │ ├── gke │ └── storage.yaml │ ├── kind │ ├── kind-example-config.yaml │ └── rancher-local-path-storage.yaml │ └── minikube │ └── storage.yaml ├── pkg ├── cdc │ ├── generate_config.go │ ├── generate_config_test.go │ ├── serde.go │ ├── serde_test.go │ └── testobjects.go ├── dynamicwatch │ └── watch.go ├── events │ └── events.go ├── httphelper │ ├── client.go │ ├── client_test.go │ ├── httpclient.go │ ├── security.go │ ├── security_test.go │ ├── server_test_utils.go │ └── testdata │ │ ├── ca.crt │ │ ├── ca.key │ │ ├── client.crt │ │ ├── client.key │ │ ├── evil_ca.crt │ │ ├── evil_ca.key │ │ ├── gencerts.sh │ │ ├── server.crt │ │ ├── server.encrypted.key │ │ ├── server.key │ │ └── server.rsa.key ├── images │ ├── images.go │ └── images_test.go ├── mockhelper │ └── http.go ├── mocks │ ├── Client.go │ ├── HttpClient.go │ ├── SubResourceClient.go │ └── helper.go ├── monitoring │ ├── metrics.go │ └── metrics_test.go ├── oplabels │ ├── labels.go │ └── labels_test.go ├── reconciliation │ ├── construct_podtemplatespec.go │ ├── construct_podtemplatespec_test.go │ ├── construct_service.go │ ├── construct_service_test.go │ ├── construct_statefulset.go │ ├── construct_statefulset_test.go │ ├── constructor.go │ ├── constructor_test.go │ ├── context.go │ ├── decommission_node.go │ ├── decommission_node_test.go │ ├── defaults.go │ ├── handler.go │ ├── handler_reconcile_test.go │ ├── handler_test.go │ ├── rackinformation.go │ ├── reconcile_configsecret.go │ ├── reconcile_datacenter.go │ ├── reconcile_datacenter_test.go │ ├── reconcile_endpoints.go │ ├── reconcile_fql.go │ ├── reconcile_fql_test.go │ ├── reconcile_racks.go │ ├── reconcile_racks_helpers.go │ ├── reconcile_racks_helpers_test.go │ ├── reconcile_racks_test.go │ ├── reconcile_services.go │ ├── reconcile_services_test.go │ ├── secrets.go │ ├── secrets_test.go │ ├── testing.go │ └── utils.go ├── serverconfig │ ├── configgen.go │ ├── configgen_test.go │ ├── parsing.go │ └── parsing_test.go └── utils │ ├── crypto.go │ ├── crypto_test.go │ ├── hash_annotation.go │ ├── hash_annotation_test.go │ ├── k8s_utils.go │ ├── utilities.go │ └── utilities_test.go ├── scripts ├── lib.sh ├── post-release-process.sh ├── postprocess-bundle.sh ├── pre-release-process.sh ├── release-certified-bundles.sh ├── release-community-bundles.sh ├── release-helm-chart.sh ├── update-kubernetes.sh └── update-makefile-version.sh └── tests ├── README.md ├── add_racks └── add_racks_suite_test.go ├── additional_seeds └── additional_seeds_suite_test.go ├── additional_serviceoptions └── additional_service_opts_suite_test.go ├── additional_volumes └── additional_volumes_suite_test.go ├── bring_up_graph └── bring_up_graph_suite_test.go ├── bring_up_solr └── bring_up_solr_suite_test.go ├── bring_up_spark └── bring_up_spark_suite_test.go ├── canary_upgrade └── canary_upgrade_test.go ├── cdc_successful └── cdc_successful_test.go ├── cluster_wide_install ├── cluster_wide_install_suite_test.go └── kustomization.yaml ├── config_change └── config_change_suite_test.go ├── config_change_condition └── config_change_condition_suite_test.go ├── config_fql └── config_fql_4x_test.go ├── config_secret └── config_secret_suite_test.go ├── decommission_dc └── decommission_dc_suite_test.go ├── delete_node_lost_readiness └── delete_node_lost_readiness_suite_test.go ├── delete_node_terminated_container └── delete_node_terminate_container_suite_test.go ├── host_network └── host_network_suite_test.go ├── internode-encryption-generated └── internode_secret_generated_test.go ├── kustomize ├── deploy.go └── kustomization.yaml ├── multi_cluster_management └── multi_cluster_management_suite_test.go ├── no_infinite_reconcile └── no_infinite_reconcile_suite_test.go ├── node_move └── node_move_suite_test.go ├── node_replace └── node_replace_suite_test.go ├── nodeport_service └── nodeport_service_suite_test.go ├── podspec_simple └── podspec_simple_suite_test.go ├── pvc_expansion └── pvc_expansion_test.go ├── rolling_restart └── rolling_restart_suite_test.go ├── rolling_restart_with_override └── rolling_restart_suite_with_override_test.go ├── scale_down └── scale_down_suite_test.go ├── scale_down_not_enough_space └── scale_down_not_enough_space_suite_test.go ├── scale_down_unbalanced_racks └── scale_down_unbalanced_racks_suite_test.go ├── scale_up └── scale_up_suite_test.go ├── scale_up_stop_resume └── scale_up_park_unpark_suite_test.go ├── seed_selection └── seed_selection_suite_test.go ├── smoke_test_read_only_fs └── smoke_test_read_only_fs_test.go ├── stop_resume └── park_unpark_suite_test.go ├── stop_resume_scale_up └── park_unpark_scale_up_suite_test.go ├── superuser-secret-generated └── superuser_secret_generated_test.go ├── superuser-secret-provided └── superuser_secret_provided_test.go ├── terminate └── terminate_suite_test.go ├── test_all_the_things └── test_all_the_things_suite_test.go ├── test_bad_config_and_fix └── test_bad_config_and_fix_suite_test.go ├── test_mtls_mgmt_api └── test_mtls_mgmt_api_suite_test.go ├── testdata ├── additional-seeds-two-rack-four-node-dc.yaml ├── additional-service-annotations-and-labels.yaml ├── bob-secret-changed.yaml ├── bob-secret.yaml ├── cass-operator-1.1.0-chart │ ├── Chart.yaml │ ├── templates │ │ ├── clusterrole.yaml │ │ ├── clusterrolebinding.yaml │ │ ├── customresourcedefinition.yaml │ │ ├── deployment.yaml │ │ ├── role.yaml │ │ ├── rolebinding.yaml │ │ ├── secret.yaml │ │ ├── service.yaml │ │ ├── serviceaccount.yaml │ │ └── validatingwebhookconfiguration.yaml │ └── values.yaml ├── cass-operator-1.7.1-manifests.yaml ├── cluster-wide-install-dc1.yaml ├── cluster-wide-install-dc2.yaml ├── cluster-with-config-secret.yaml ├── config_fql_4x_test.yaml ├── configs │ ├── my-metrics-config.yaml │ └── vector-config.yaml ├── default-single-rack-2-node-dc-with-auth-enabled.yaml ├── default-single-rack-2-node-dc-with-superuser-secret.yaml ├── default-single-rack-2-node-dc.yaml ├── default-single-rack-2-node-dc1.yaml ├── default-single-rack-single-node-additional-volumesources.yaml ├── default-single-rack-single-node-addtional-volumes-dc.yaml ├── default-single-rack-single-node-dc-lvm.yaml ├── default-single-rack-single-node-dc-with-readonly-fs.yaml ├── default-single-rack-single-node-dc.yaml ├── default-single-rack-single-node-extra-container-dc.yaml ├── default-single-rack-single-node-hcd-dc.yaml ├── default-single-rack-single-node-prestop-dc.yaml ├── default-three-rack-four-node-dc.yaml ├── default-three-rack-four-node-limited-storage-dc.yaml ├── default-three-rack-three-node-dc-4x.yaml ├── default-three-rack-three-node-dc-zones.yaml ├── default-three-rack-three-node-dc.yaml ├── default-two-rack-four-node-dc.yaml ├── default-two-rack-two-node-dc.yaml ├── default-two-rack-two-node-dc2.yaml ├── encrypted-single-rack-2-node-dc.yaml ├── graph-dc.yaml ├── host-network-dc.yaml ├── image_config_parsing.yaml ├── image_config_parsing_more_options.yaml ├── kind │ ├── kind_config_1_worker.yaml │ ├── kind_config_3_workers.yaml │ └── kind_config_6_workers.yaml ├── mtls-certs-client.yaml ├── mtls-certs-server.yaml ├── nodeport-service-dc.yaml ├── operator-1.7.1-oss-dc.yaml ├── oss-one-node-dc-with-mtls.yaml ├── oss-one-node-dc-without-mtls.yaml ├── oss-three-rack-three-node-dc.yaml ├── oss-two-rack-six-node-dc.yaml ├── oss-upgrade-dc.yaml ├── single-token-three-rack-three-node-dc.yaml ├── smoke-test-dse.yaml ├── smoke-test-oss.yaml ├── solr-dc.yaml ├── spark-dc.yaml ├── tasks │ ├── flush_task.yaml │ ├── move_node_task.yaml │ ├── rebuild_task.yaml │ ├── replace_node_task.yaml │ ├── rolling_restart.yaml │ └── rolling_restart_override.yaml ├── test-cdc │ ├── cassandra-datacenter.yaml │ ├── dev-values.yaml │ └── testutils-deployment.yaml ├── test-config-secret.yaml └── updated-test-config-secret.yaml ├── timeout_prestop_termination └── timeout_prestop_termination_suite_test.go ├── upgrade_operator ├── kustomization.yaml └── upgrade_operator_suite_test.go ├── util ├── ginkgo │ └── lib.go ├── kubectl │ └── kubectl.go ├── lib.go └── sh │ └── lib.go └── webhook_validation └── webhook_validation_suite_test.go /.dockerignore: -------------------------------------------------------------------------------- 1 | /operator/.gogradle/ 2 | /operator/vendor/ 3 | /operator/build/ 4 | /.gradle/ 5 | /build/ 6 | -------------------------------------------------------------------------------- /.fossa.yml: -------------------------------------------------------------------------------- 1 | # Generated by FOSSA CLI (https://github.com/fossas/fossa-cli) 2 | # Visit https://fossa.com to learn more 3 | 4 | version: 2 5 | cli: 6 | server: https://app.fossa.com 7 | fetcher: custom 8 | project: cass-operator 9 | analyze: 10 | modules: 11 | - name: github.com/k8ssandra/cass-operator/operator/cmd/manager 12 | type: go 13 | target: github.com/k8ssandra/cass-operator/operator/cmd/manager 14 | path: operator/cmd/manager 15 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # the repo. Unless a later match takes precedence, 3 | # @k8ssandra/maintainers will be requested for 4 | # review when someone opens a pull request. 5 | * @k8ssandra/maintainers 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: 🐞 Bug report 2 | description: Report a bug to help us improve 3 | labels: [bug] 4 | body: 5 | - type: textarea 6 | id: problem 7 | attributes: 8 | label: What happened? 9 | description: | 10 | Please provide as much info as possible. If you have questions, you can also visit our Discord server: https://discord.gg/Fgep3hwm 11 | validations: 12 | required: true 13 | - type: textarea 14 | id: expected 15 | attributes: 16 | label: What did you expect to happen? 17 | validations: 18 | required: false 19 | - type: textarea 20 | id: repro 21 | attributes: 22 | label: How can we reproduce it (as minimally and precisely as possible)? 23 | validations: 24 | required: true 25 | - type: input 26 | id: cass-operator-version 27 | attributes: 28 | label: cass-operator version 29 | description: The release version or the used container image 30 | validations: 31 | required: true 32 | - type: input 33 | id: kube-version 34 | attributes: 35 | label: Kubernetes version 36 | description: kubectl version output 37 | validations: 38 | required: true 39 | - type: input 40 | id: install-type 41 | attributes: 42 | label: Method of installation 43 | description: How was cass-operator deployed? Kustomize, Helm, Argo etc 44 | placeholder: Kustomize 45 | validations: 46 | required: false 47 | - type: textarea 48 | id: additional 49 | attributes: 50 | label: Anything else we need to know? 51 | description: | 52 | If there are relevant cass-operator logs, add them here. 53 | If this is installation issue, let us also know the version of used tool (such as Helm / Kustomize). 54 | If there's a reference to this issue (Discord link, K8ssandra forums, etc) add it here. 55 | validations: 56 | required: false 57 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea for this project 3 | labels: [enhancement] 4 | body: 5 | - type: textarea 6 | id: feature 7 | attributes: 8 | label: What is missing? 9 | description: | 10 | Please describe the improvement you would like to see in the project. This could be an enhancement to an existing feature as well as new a feature. If you have any references, 11 | please add them also for context. 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: rationale 16 | attributes: 17 | label: Why is this needed? 18 | validations: 19 | required: true 20 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | **What this PR does**: 8 | 9 | **Which issue(s) this PR fixes**: 10 | Fixes # 11 | 12 | **Checklist** 13 | - [ ] Changes manually tested 14 | - [ ] Automated Tests added/updated 15 | - [ ] Documentation added/updated 16 | - [ ] CHANGELOG.md updated (not required for documentation PRs) 17 | - [ ] CLA Signed: [DataStax CLA](https://cla.datastax.com/) 18 | -------------------------------------------------------------------------------- /.github/workflows/add_to_project.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 DataStax, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | name: Add issues to GH project 15 | 16 | on: 17 | issues: 18 | types: 19 | - opened 20 | 21 | jobs: 22 | add-to-project: 23 | name: Add issue to GH project 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/add-to-project@v0.3.0 27 | with: 28 | project-url: https://github.com/orgs/k8ssandra/projects/8 29 | github-token: ${{ secrets.GH_PROJECTS_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/check_pr_linked_issue.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 DataStax, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | on: 15 | pull_request_target: 16 | types: [opened, edited, reopened, synchronize] 17 | 18 | jobs: 19 | check_pull_requests: 20 | runs-on: ubuntu-latest 21 | name: Check linked issues 22 | steps: 23 | - uses: nearform/github-action-check-linked-issues@v1 24 | id: check-linked-issues 25 | with: 26 | exclude-branches: "dependabot/**" 27 | comment: true -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Build the manager binary 2 | FROM golang:1.23 AS builder 3 | ARG TARGETOS 4 | ARG TARGETARCH 5 | 6 | WORKDIR /workspace 7 | # Copy the Go Modules manifests 8 | COPY go.mod go.mod 9 | COPY go.sum go.sum 10 | # cache deps before building and copying source so that we don't need to re-download as much 11 | # and so that source changes don't invalidate our downloaded layer 12 | RUN go mod download 13 | 14 | # Copy the go source 15 | COPY cmd/ cmd/ 16 | COPY apis/ apis/ 17 | COPY pkg/ pkg/ 18 | COPY internal/ internal/ 19 | 20 | # Build 21 | RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go 22 | 23 | # Build the UBI image 24 | FROM redhat/ubi9-micro:latest 25 | 26 | ARG VERSION 27 | 28 | LABEL maintainer="DataStax, Inc " 29 | LABEL name="cass-operator" 30 | LABEL vendor="DataStax, Inc" 31 | LABEL release="${VERSION}" 32 | LABEL version="${VERSION}" 33 | LABEL summary="DataStax Kubernetes Operator for Apache Cassandra " 34 | LABEL description="The DataStax Kubernetes Operator for Apache Cassandra®. This operator handles the provisioning and day to day management of Apache Cassandra based clusters. Features include configuration deployment, node remediation, and automatic upgrades." 35 | 36 | WORKDIR / 37 | COPY --from=builder /workspace/manager /manager 38 | COPY ./LICENSE.txt /licenses/ 39 | 40 | USER 65532:65532 41 | 42 | ENTRYPOINT ["/manager"] 43 | -------------------------------------------------------------------------------- /PROJECT: -------------------------------------------------------------------------------- 1 | # Code generated by tool. DO NOT EDIT. 2 | # This file is used to track the info used to scaffold your project 3 | # and allow the plugins properly work. 4 | # More info: https://book.kubebuilder.io/reference/project-config.html 5 | domain: cassandra.datastax.com 6 | layout: 7 | - go.kubebuilder.io/v4 8 | multigroup: true 9 | plugins: 10 | manifests.sdk.operatorframework.io/v2: {} 11 | scorecard.sdk.operatorframework.io/v2: {} 12 | projectName: cass-operator 13 | repo: github.com/k8ssandra/cass-operator 14 | resources: 15 | - api: 16 | crdVersion: v1 17 | namespaced: true 18 | controller: true 19 | group: cassandra.datastax.com 20 | kind: CassandraDatacenter 21 | path: github.com/k8ssandra/cass-operator/apis/cassandra/v1beta1 22 | version: v1beta1 23 | webhooks: 24 | defaulting: true 25 | validation: true 26 | webhookVersion: v1 27 | - api: 28 | crdVersion: v1 29 | namespaced: true 30 | controller: true 31 | domain: k8ssandra.io 32 | group: control 33 | kind: CassandraTask 34 | path: github.com/k8ssandra/cass-operator/apis/control/v1alpha1 35 | version: v1alpha1 36 | - api: 37 | crdVersion: v1 38 | namespaced: true 39 | controller: true 40 | domain: cassandra.datastax.com 41 | group: control 42 | kind: ScheduledTask 43 | path: github.com/k8ssandra/cass-operator/apis/control/v1alpha1 44 | version: v1alpha1 45 | version: "3" 46 | -------------------------------------------------------------------------------- /apis/cassandra/v1beta1/cdc_types.go: -------------------------------------------------------------------------------- 1 | package v1beta1 2 | 3 | // CDCConfiguration holds CDC config for the CassandraDatacenter. Note that it cannot contain arrays, channels, maps etc. because of the way the 4 | // reflection logic works which marshalls it into a string for the purposes of passing on the command line. 5 | type CDCConfiguration struct { 6 | // +kubebuilder:validation:MinLength=1 7 | PulsarServiceUrl *string `json:"pulsarServiceUrl"` 8 | // +optional 9 | TopicPrefix *string `json:"topicPrefix,omitempty"` 10 | // +optional 11 | CDCWorkingDir *string `json:"cdcWorkingDir,omitempty"` 12 | // +optional 13 | CDCPollIntervalMs *int `json:"cdcPollIntervalM,omitempty"` 14 | // +optional 15 | ErrorCommitLogReprocessEnabled *bool `json:"errorCommitLogReprocessEnabled,omitempty"` 16 | // +optional 17 | CDCConcurrentProcessors *int `json:"cdcConcurrentProcessors,omitempty"` 18 | // +optional 19 | PulsarBatchDelayInMs *int `json:"pulsarBatchDelayInMs,omitempty"` 20 | // +optional 21 | PulsarKeyBasedBatcher *bool `json:"pulsarKeyBasedBatcher,omitempty"` 22 | // +optional 23 | PulsarMaxPendingMessages *int `json:"pulsarMaxPendingMessages,omitempty"` 24 | // +optional 25 | PulsarMaxPendingMessagesAcrossPartitions *int `json:"pulsarMaxPendingMessagesAcrossPartitions,omitempty"` 26 | // +optional 27 | PulsarAuthPluginClassName *string `json:"pulsarAuthPluginClassName,omitempty"` 28 | // +optional 29 | PulsarAuthParams *string `json:"pulsarAuthParams,omitempty"` 30 | // +optional 31 | SSLProvider *string `json:"sslProvider,omitempty"` 32 | // +optional 33 | SSLTruststorePath *string `json:"sslTruststorePath,omitempty"` 34 | // +optional 35 | SSLTruststorePassword *string `json:"sslTruststorePassword,omitempty"` 36 | // +optional 37 | SSLTruststoreType *string `json:"sslTruststoreType,omitempty"` 38 | // +optional 39 | SSLKeystorePath *string `json:"sslKeystorePath,omitempty"` 40 | // +optional 41 | SSLKeystorePassword *string `json:"sslKeystorePassword,omitempty"` 42 | // +optional 43 | SSLCipherSuites *string `json:"sslCipherSuites,omitempty"` 44 | // +optional 45 | SSLEnabledProtocols *string `json:"sslEnabledProtocols,omitempty"` 46 | // +optional 47 | SSLAllowInsecureConnection *string `json:"sslAllowInsecureConnection,omitempty"` 48 | // +optional 49 | SSLHostnameVerificationEnable *string `json:"sslHostnameVerificationEnable,omitempty"` 50 | } 51 | -------------------------------------------------------------------------------- /apis/cassandra/v1beta1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021. 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 cassandra.datastax.com v1beta1 API group 18 | // +kubebuilder:object:generate=true 19 | // +groupName=cassandra.datastax.com 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: "cassandra.datastax.com", 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 | -------------------------------------------------------------------------------- /apis/config/v1beta1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021. 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 v1 contains API Schema definitions for the config v1 API group 18 | // +kubebuilder:object:generate=true 19 | // +groupName=config.k8ssandra.io 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: "config.k8ssandra.io", 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 | -------------------------------------------------------------------------------- /apis/config/v1beta1/operatorconfig_types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021. 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 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! 24 | // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. 25 | 26 | //+kubebuilder:object:root=true 27 | 28 | // OperatorConfig is the Schema for the operatorconfigs API 29 | type OperatorConfig struct { 30 | metav1.TypeMeta `json:",inline"` 31 | 32 | // SkipValidatingWebhook replaces the old SKIP_VALIDATING_WEBHOOK env variable. If set to true, the webhooks are not initialized 33 | DisableWebhooks bool `json:"disableWebhooks,omitempty"` 34 | 35 | // ImageConfigFile indicates the path where to load the imageConfig from 36 | ImageConfigFile string `json:"imageConfigFile,omitempty"` 37 | } 38 | 39 | func init() { 40 | SchemeBuilder.Register(&OperatorConfig{}) 41 | } 42 | -------------------------------------------------------------------------------- /apis/control/v1alpha1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021. 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 v1alpha1 contains API Schema definitions for the control.k8ssandra.io v1alpha1 API group 18 | // +kubebuilder:object:generate=true 19 | // +groupName=control.k8ssandra.io 20 | package v1alpha1 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: "control.k8ssandra.io", Version: "v1alpha1"} 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 | -------------------------------------------------------------------------------- /apis/control/v1alpha1/scheduledtask_types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | // ScheduledTaskSpec defines the desired state of ScheduledTask 24 | type ScheduledTaskSpec struct { 25 | Schedule string `json:"schedule,omitempty"` 26 | TaskDetails TaskDetails `json:"taskDetails,omitempty"` 27 | } 28 | 29 | type TaskDetails struct { 30 | // Name of the task. Always populated. 31 | Name string `json:"name,omitempty"` 32 | // +inline 33 | CassandraTaskSpec `json:",inline"` 34 | } 35 | 36 | // MedusaTaskStatus defines the observed state of MedusaTask 37 | type ScheduledTaskStatus struct { 38 | // NextSchedule indicates when the next backup is going to be done 39 | NextSchedule metav1.Time `json:"nextSchedule,omitempty"` 40 | 41 | // LastExecution tells when the backup was last time taken. If empty, the backup has never been taken 42 | LastExecution metav1.Time `json:"lastExecution,omitempty"` 43 | } 44 | 45 | type TaskResult struct { 46 | // Name of the pod that ran the task. Always populated. 47 | PodName string `json:"podName,omitempty"` 48 | } 49 | 50 | //+kubebuilder:object:root=true 51 | //+kubebuilder:subresource:status 52 | 53 | // ScheduledTask is the Schema for the scheduledtasks API 54 | type ScheduledTask struct { 55 | metav1.TypeMeta `json:",inline"` 56 | metav1.ObjectMeta `json:"metadata,omitempty"` 57 | 58 | Spec ScheduledTaskSpec `json:"spec,omitempty"` 59 | Status ScheduledTaskStatus `json:"status,omitempty"` 60 | } 61 | 62 | //+kubebuilder:object:root=true 63 | 64 | // ScheduledTaskList contains a list of ScheduledTask 65 | type ScheduledTaskList struct { 66 | metav1.TypeMeta `json:",inline"` 67 | metav1.ListMeta `json:"metadata,omitempty"` 68 | Items []ScheduledTask `json:"items"` 69 | } 70 | 71 | func init() { 72 | SchemeBuilder.Register(&ScheduledTask{}, &ScheduledTaskList{}) 73 | } 74 | -------------------------------------------------------------------------------- /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: cass-operator 9 | app.kubernetes.io/managed-by: kustomize 10 | name: selfsigned-issuer 11 | namespace: system 12 | spec: 13 | selfSigned: {} 14 | --- 15 | apiVersion: cert-manager.io/v1 16 | kind: Certificate 17 | metadata: 18 | labels: 19 | app.kubernetes.io/name: certificate 20 | app.kubernetes.io/instance: serving-cert 21 | app.kubernetes.io/component: certificate 22 | app.kubernetes.io/created-by: cass-operator 23 | app.kubernetes.io/part-of: cass-operator 24 | app.kubernetes.io/managed-by: kustomize 25 | name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml 26 | namespace: system 27 | spec: 28 | # SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize 29 | dnsNames: 30 | - SERVICE_NAME.SERVICE_NAMESPACE.svc 31 | - SERVICE_NAME.SERVICE_NAMESPACE.svc.cluster.local 32 | issuerRef: 33 | kind: Issuer 34 | name: selfsigned-issuer 35 | secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize 36 | -------------------------------------------------------------------------------- /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 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 | -------------------------------------------------------------------------------- /config/components/clusterscope/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Set WATCH_NAMESPACE to "" in the deployment to provide cluster-wide install 2 | apiVersion: kustomize.config.k8s.io/v1alpha1 3 | kind: Component 4 | patches: 5 | - patch: |- 6 | - op: remove 7 | path: /spec/template/spec/containers/0/env/0/valueFrom 8 | - op: add 9 | path: /spec/template/spec/containers/0/env/0/value 10 | value: "" 11 | target: 12 | group: apps 13 | kind: Deployment 14 | name: controller-manager 15 | version: v1 16 | - patch: |- 17 | - op: replace 18 | path: /metadata/name 19 | value: cass-operator-manager-crrole 20 | - op: replace 21 | path: /kind 22 | value: ClusterRole 23 | target: 24 | group: rbac.authorization.k8s.io 25 | kind: Role 26 | name: manager-role 27 | version: v1 28 | - patch: |- 29 | - op: replace 30 | path: /roleRef/kind 31 | value: ClusterRole 32 | - op: replace 33 | path: /roleRef/name 34 | value: cass-operator-manager-crrole 35 | - op: replace 36 | path: /subjects/0/name 37 | value: cass-operator-controller-manager 38 | - op: add 39 | path: /subjects/0/namespace 40 | value: cass-operator 41 | - op: replace 42 | path: /kind 43 | value: ClusterRoleBinding 44 | target: 45 | group: rbac.authorization.k8s.io 46 | kind: RoleBinding 47 | name: manager-rolebinding 48 | version: v1 49 | -------------------------------------------------------------------------------- /config/components/namespace/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | resources: 5 | - ns.yaml 6 | -------------------------------------------------------------------------------- /config/components/namespace/ns.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: cass-operator 6 | app.kubernetes.io/managed-by: kustomize 7 | control-plane: controller-manager 8 | name: system 9 | -------------------------------------------------------------------------------- /config/components/webhook/controller_manager_config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: config.k8ssandra.io/v1beta1 2 | kind: OperatorConfig 3 | metadata: 4 | name: operator-config 5 | disableWebhooks: false 6 | imageConfigFile: /configs/image_config.yaml 7 | -------------------------------------------------------------------------------- /config/components/webhook/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1alpha1 2 | kind: Component 3 | 4 | configMapGenerator: 5 | - behavior: merge 6 | files: 7 | - controller_manager_config.yaml 8 | name: manager-config 9 | 10 | resources: 11 | - ../../webhook 12 | - ../../certmanager 13 | 14 | configurations: 15 | - kustomizeconfig.yaml 16 | patches: 17 | - path: patches/manager_webhook_patch.yaml 18 | -------------------------------------------------------------------------------- /config/components/webhook/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 | -------------------------------------------------------------------------------- /config/components/webhook/patches/manager_webhook_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | labels: 7 | app.kubernetes.io/name: cass-operator 8 | app.kubernetes.io/managed-by: kustomize 9 | spec: 10 | template: 11 | spec: 12 | containers: 13 | - name: manager 14 | ports: 15 | - containerPort: 9443 16 | name: webhook-server 17 | protocol: TCP 18 | volumeMounts: 19 | - mountPath: /tmp/k8s-webhook-server/serving-certs 20 | name: cert 21 | readOnly: true 22 | volumes: 23 | - name: cert 24 | secret: 25 | defaultMode: 420 26 | secretName: webhook-server-cert 27 | -------------------------------------------------------------------------------- /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/cassandra.datastax.com_cassandradatacenters.yaml 6 | - bases/control.k8ssandra.io_cassandratasks.yaml 7 | - bases/control.k8ssandra.io_scheduledtasks.yaml 8 | #+kubebuilder:scaffold:crdkustomizeresource 9 | 10 | # name: controller-manager 11 | # namespace: system 12 | # patch: |- 13 | # # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs. 14 | # # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment. 15 | # - op: remove 16 | # path: /spec/template/spec/containers/1/volumeMounts/0 17 | 18 | 19 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. 20 | # patches here are for enabling the conversion webhook for each CRD 21 | #- patches/webhook_in_cassandradatacenters.yaml 22 | #- patches/webhook_in_cassandrajobs.yaml 23 | #+kubebuilder:scaffold:crdkustomizewebhookpatch 24 | 25 | # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. 26 | # patches here are for enabling the CA injection for each CRD 27 | # - patches/cainjection_in_cassandradatacenters.yaml 28 | #- patches/cainjection_in_cassandrajobs.yaml 29 | #+kubebuilder:scaffold:crdkustomizecainjectionpatch 30 | 31 | # the following config is for teaching kustomize how to do kustomization for CRDs. 32 | configurations: 33 | - kustomizeconfig.yaml 34 | apiVersion: kustomize.config.k8s.io/v1beta1 35 | kind: Kustomization 36 | patches: 37 | - path: patches/config_removal.yaml 38 | target: 39 | group: apiextensions.k8s.io 40 | kind: CustomResourceDefinition 41 | name: cassandradatacenters.cassandra.datastax.com 42 | version: v1 43 | - path: patches/remove_xkeys.yaml 44 | target: 45 | group: apiextensions.k8s.io 46 | kind: CustomResourceDefinition 47 | name: cassandradatacenters.cassandra.datastax.com 48 | version: v1 49 | -------------------------------------------------------------------------------- /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/config_removal.yaml: -------------------------------------------------------------------------------- 1 | # Remove the "config" section from the CRD, and enable 2 | # x-kubernetes-preserve-unknown-fields. 3 | # 4 | # This is necessary because the config field has a dynamic 5 | # schema which depends on the DSE version selected, and 6 | # dynamic schema aren't possible to fully specify and 7 | # validate via openAPI V3. 8 | # 9 | # Instead, we remove the config field from the schema 10 | # entirely and instruct openAPI/k8s to preserve fields even 11 | # if they aren't specified in the CRD. The field itself is defined 12 | # as a json.RawMessage, see dsedatacenter_types.go in the 13 | # api's subdirectory for details. 14 | - op: remove 15 | path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/config 16 | -------------------------------------------------------------------------------- /config/crd/patches/remove_xkeys.yaml: -------------------------------------------------------------------------------- 1 | - op: remove 2 | path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/podTemplateSpec/properties/spec/properties/containers/items/properties/ports/x-kubernetes-list-map-keys 3 | - op: remove 4 | path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/podTemplateSpec/properties/spec/properties/containers/items/properties/ports/x-kubernetes-list-type 5 | - op: remove 6 | path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/podTemplateSpec/properties/spec/properties/initContainers/items/properties/ports/x-kubernetes-list-map-keys 7 | - op: remove 8 | path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/podTemplateSpec/properties/spec/properties/initContainers/items/properties/ports/x-kubernetes-list-type 9 | - op: remove 10 | path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/podTemplateSpec/properties/spec/properties/topologySpreadConstraints/x-kubernetes-list-map-keys 11 | - op: remove 12 | path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/podTemplateSpec/properties/spec/properties/topologySpreadConstraints/x-kubernetes-list-type 13 | -------------------------------------------------------------------------------- /config/default/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Labels to add to all resources and selectors. 2 | labels: 3 | - includeSelectors: false 4 | pairs: 5 | app.kubernetes.io/name: cass-operator 6 | app.kubernetes.io/managed-by: kustomize 7 | 8 | resources: 9 | - ../crd 10 | - ../rbac 11 | - ../manager 12 | - metrics_service.yaml 13 | 14 | # Uncomment the patches line if you enable Metrics, and/or are using webhooks and cert-manager 15 | patches: 16 | # [METRICS] The following patch will enable the metrics endpoint using HTTPS and the port :8443. 17 | # More info: https://book.kubebuilder.io/reference/metrics 18 | - path: manager_metrics_patch.yaml 19 | target: 20 | kind: Deployment 21 | - path: manager_config_patch.yaml 22 | target: 23 | kind: Deployment 24 | -------------------------------------------------------------------------------- /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=/configs/controller_manager_config.yaml" 13 | volumeMounts: 14 | - name: manager-config 15 | mountPath: /configs 16 | volumes: 17 | - name: manager-config 18 | configMap: 19 | name: manager-config 20 | -------------------------------------------------------------------------------- /config/default/manager_metrics_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch adds the args to allow exposing the metrics endpoint using HTTPS 2 | - op: add 3 | path: /spec/template/spec/containers/0/args/0 4 | value: --metrics-bind-address=:8443 5 | -------------------------------------------------------------------------------- /config/default/metrics_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | app.kubernetes.io/name: cass-operator 7 | app.kubernetes.io/managed-by: kustomize 8 | name: controller-manager-metrics-service 9 | namespace: system 10 | spec: 11 | ports: 12 | - name: https 13 | port: 8443 14 | protocol: TCP 15 | targetPort: 8443 16 | selector: 17 | control-plane: controller-manager 18 | -------------------------------------------------------------------------------- /config/deployments/cluster/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - ../default 6 | 7 | components: 8 | - ../../components/clusterscope 9 | -------------------------------------------------------------------------------- /config/logger/vector_config.toml: -------------------------------------------------------------------------------- 1 | [sources.systemlog] 2 | type = "file" 3 | include = [ "/var/log/cassandra/system.log" ] 4 | read_from = "end" 5 | 6 | [sinks.console] 7 | type = "console" 8 | inputs = ["systemlog"] 9 | target = "stdout" 10 | 11 | [sinks.console.encoding] 12 | codec = "text" 13 | -------------------------------------------------------------------------------- /config/manager/controller_manager_config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: config.k8ssandra.io/v1beta1 2 | kind: OperatorConfig 3 | metadata: 4 | name: operator-config 5 | disableWebhooks: true 6 | imageConfigFile: /configs/image_config.yaml 7 | -------------------------------------------------------------------------------- /config/manager/image_config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: config.k8ssandra.io/v1beta1 2 | kind: ImageConfig 3 | metadata: 4 | name: image-config 5 | images: 6 | system-logger: "k8ssandra/system-logger:latest" 7 | config-builder: "datastax/cass-config-builder:1.0-ubi8" 8 | k8ssandra-client: "k8ssandra/k8ssandra-client:v0.7.0" 9 | # cassandra: 10 | # "4.0.0": "k8ssandra/cassandra-ubi:latest" 11 | # dse: 12 | # "6.8.999": "datastax/dse-server-prototype:latest" 13 | # imageRegistry: "localhost:5000" 14 | # imageNamespace: "internal" 15 | # imagePullPolicy: Always 16 | # imagePullSecret: 17 | # name: my-secret-pull-registry 18 | defaults: 19 | # Note, postfix is ignored if repository is not set 20 | cassandra: 21 | repository: "ghcr.io/k8ssandra/cass-management-api" 22 | suffix: "-ubi" 23 | dse: 24 | repository: "datastax/dse-mgmtapi-6_8" 25 | suffix: "-ubi8" 26 | hcd: 27 | repository: "datastax/hcd" 28 | suffix: "-ubi" 29 | -------------------------------------------------------------------------------- /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 | - image_config.yaml 11 | name: manager-config 12 | apiVersion: kustomize.config.k8s.io/v1beta1 13 | kind: Kustomization 14 | images: 15 | - name: controller 16 | newName: k8ssandra/cass-operator 17 | newTag: latest 18 | -------------------------------------------------------------------------------- /config/manager/manager.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: controller-manager 6 | namespace: system 7 | labels: 8 | control-plane: controller-manager 9 | app.kubernetes.io/name: cass-operator 10 | app.kubernetes.io/managed-by: kustomize 11 | spec: 12 | selector: 13 | matchLabels: 14 | name: cass-operator 15 | control-plane: controller-manager 16 | replicas: 1 17 | template: 18 | metadata: 19 | annotations: 20 | kubectl.kubernetes.io/default-container: manager 21 | labels: 22 | name: cass-operator 23 | control-plane: controller-manager 24 | spec: 25 | securityContext: 26 | runAsNonRoot: true 27 | seccompProfile: 28 | type: RuntimeDefault 29 | containers: 30 | - command: 31 | - /manager 32 | args: 33 | - --leader-elect 34 | - --health-probe-bind-address=:8081 35 | image: controller:latest 36 | name: manager 37 | imagePullPolicy: IfNotPresent 38 | securityContext: 39 | runAsNonRoot: true 40 | runAsGroup: 65534 41 | runAsUser: 65534 42 | readOnlyRootFilesystem: true 43 | allowPrivilegeEscalation: false 44 | capabilities: 45 | drop: 46 | - "ALL" 47 | livenessProbe: 48 | httpGet: 49 | path: /healthz 50 | port: 8081 51 | initialDelaySeconds: 15 52 | periodSeconds: 20 53 | readinessProbe: 54 | httpGet: 55 | path: /readyz 56 | port: 8081 57 | initialDelaySeconds: 5 58 | periodSeconds: 10 59 | resources: 60 | limits: 61 | cpu: 500m 62 | memory: 128Mi 63 | requests: 64 | cpu: 100m 65 | memory: 64Mi 66 | env: 67 | - name: WATCH_NAMESPACE 68 | valueFrom: 69 | fieldRef: 70 | fieldPath: metadata.namespace 71 | serviceAccountName: controller-manager 72 | terminationGracePeriodSeconds: 10 73 | -------------------------------------------------------------------------------- /config/manifests/images/ds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k8ssandra/cass-operator/a8d22a71b49d815ec91fd593ad35f704cf339108/config/manifests/images/ds.png -------------------------------------------------------------------------------- /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/cass-operator.clusterserviceversion.yaml 5 | - ../deployments/default 6 | - ../samples 7 | - ../scorecard 8 | 9 | generatorOptions: 10 | disableNameSuffixHash: true 11 | 12 | configMapGenerator: 13 | - files: 14 | - ../../docs/developer/csv-description.md 15 | name: field-config 16 | 17 | # [WEBHOOK] To enable webhooks, uncomment all the sections with [WEBHOOK] prefix. 18 | # Do NOT uncomment sections with prefix [CERTMANAGER], as OLM does not support cert-manager. 19 | # These patches remove the unnecessary "cert" volume and its manager container volumeMount. 20 | patchesJson6902: 21 | - target: 22 | group: operators.coreos.com 23 | version: v1alpha1 24 | kind: ClusterServiceVersion 25 | name: cass-operator.v0.0.0 26 | path: patches/spec-descriptors.yaml 27 | - target: 28 | group: operators.coreos.com 29 | version: v1alpha1 30 | kind: ClusterServiceVersion 31 | name: cass-operator.v0.0.0 32 | path: patches/status-descriptors.yaml 33 | - target: 34 | group: apps 35 | version: v1 36 | kind: Deployment 37 | name: controller-manager 38 | namespace: system 39 | patch: |- 40 | # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs. 41 | # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment. 42 | - op: remove 43 | path: /spec/template/spec/containers/0/volumeMounts/0 44 | # Remove the "cert" volume, since OLM will create and mount a set of certs. 45 | # Update the indices in this path if adding or removing volumes in the manager's Deployment. 46 | - op: remove 47 | path: /spec/template/spec/volumes/0 48 | 49 | replacements: 50 | - path: patches/description-replacement.yaml 51 | -------------------------------------------------------------------------------- /config/manifests/patches/description-replacement.yaml: -------------------------------------------------------------------------------- 1 | source: 2 | kind: ConfigMap 3 | name: field-config 4 | fieldPath: data.csv-description\.md 5 | targets: 6 | - select: 7 | kind: ClusterServiceVersion 8 | name: cass-operator.v0.0.0 9 | fieldPaths: 10 | - spec.description 11 | -------------------------------------------------------------------------------- /config/manifests/patches/status-descriptors.yaml: -------------------------------------------------------------------------------- 1 | - op: add 2 | path: /spec/customresourcedefinitions/owned/0/statusDescriptors 3 | value: 4 | - path: cassandraOperatorProgress 5 | description: Cassandra Operator Progress 6 | displayName: Cassandra Operator Progress 7 | x-descriptors: 8 | - urn:alm:descriptor:text 9 | - path: lastRollingRestart 10 | description: Last Rolling Restart 11 | displayName: Last Rolling Restart 12 | x-descriptors: 13 | - urn:alm:descriptor:text 14 | - path: lastServerNodeStarted 15 | description: Last Server Node Started 16 | displayName: Last Server Node Started 17 | x-descriptors: 18 | - urn:alm:descriptor:text 19 | - path: superUserUpserted 20 | description: Super User Upserted 21 | displayName: Super User Upserted 22 | x-descriptors: 23 | - urn:alm:descriptor:text 24 | - path: nodeReplacements 25 | description: | 26 | List of all nodes that have been replaced. 27 | displayName: Node Replacements 28 | - path: nodeStatuses 29 | description: | 30 | Data structure containing information around the health 31 | of all pods in the cluster. 32 | displayName: Node Statuses 33 | - path: observedGeneration 34 | description: | 35 | Holds information related to previous generations to detect when certain changes occur. 36 | displayName: Observed Generation 37 | - path: quietPeriod 38 | description: | 39 | Signals when reconcilliation should not occur due to waiting on other actions to complete. 40 | displayName: Quiet Period 41 | - path: conditions 42 | description: conditions 43 | displayName: Conditions 44 | -------------------------------------------------------------------------------- /config/network-policy/allow-metrics-traffic.yaml: -------------------------------------------------------------------------------- 1 | # This NetworkPolicy allows ingress traffic 2 | # with Pods running on namespaces labeled with 'metrics: enabled'. Only Pods on those 3 | # namespaces are able to gathering data from the metrics endpoint. 4 | apiVersion: networking.k8s.io/v1 5 | kind: NetworkPolicy 6 | metadata: 7 | labels: 8 | app.kubernetes.io/name: cass-operator 9 | app.kubernetes.io/managed-by: kustomize 10 | name: allow-metrics-traffic 11 | namespace: system 12 | spec: 13 | podSelector: 14 | matchLabels: 15 | control-plane: controller-manager 16 | policyTypes: 17 | - Ingress 18 | ingress: 19 | # This allows ingress traffic from any namespace with the label metrics: enabled 20 | - from: 21 | - namespaceSelector: 22 | matchLabels: 23 | metrics: enabled # Only from namespaces with this label 24 | ports: 25 | - port: 8443 26 | protocol: TCP 27 | -------------------------------------------------------------------------------- /config/network-policy/allow-webhook-traffic.yaml: -------------------------------------------------------------------------------- 1 | # This NetworkPolicy allows ingress traffic to your webhook server running 2 | # as part of the controller-manager from specific namespaces and pods. CR(s) which uses webhooks 3 | # will only work when applied in namespaces labeled with 'webhook: enabled' 4 | apiVersion: networking.k8s.io/v1 5 | kind: NetworkPolicy 6 | metadata: 7 | labels: 8 | app.kubernetes.io/name: cass-operator 9 | app.kubernetes.io/managed-by: kustomize 10 | name: allow-webhook-traffic 11 | namespace: system 12 | spec: 13 | podSelector: 14 | matchLabels: 15 | control-plane: controller-manager 16 | policyTypes: 17 | - Ingress 18 | ingress: 19 | # This allows ingress traffic from any namespace with the label webhook: enabled 20 | - from: 21 | - namespaceSelector: 22 | matchLabels: 23 | webhook: enabled # Only from namespaces with this label 24 | ports: 25 | - port: 443 26 | protocol: TCP 27 | -------------------------------------------------------------------------------- /config/network-policy/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - allow-webhook-traffic.yaml 3 | - allow-metrics-traffic.yaml 4 | -------------------------------------------------------------------------------- /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 | app.kubernetes.io/name: cass-operator 8 | app.kubernetes.io/managed-by: kustomize 9 | control-plane: controller-manager 10 | name: controller-manager-metrics-monitor 11 | namespace: system 12 | spec: 13 | endpoints: 14 | - path: /metrics 15 | port: https # Ensure this is the name of the port that exposes HTTPS metrics 16 | scheme: https 17 | bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 18 | tlsConfig: 19 | # Please use the following options for secure configurations: 20 | # caFile: /etc/metrics-certs/ca.crt 21 | # certFile: /etc/metrics-certs/tls.crt 22 | # keyFile: /etc/metrics-certs/tls.key 23 | insecureSkipVerify: true 24 | selector: 25 | matchLabels: 26 | control-plane: controller-manager 27 | -------------------------------------------------------------------------------- /config/rbac/cassandradatacenter_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit cassandradatacenters. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: cassandradatacenter-editor-role 6 | rules: 7 | - apiGroups: 8 | - cassandra.datastax.com 9 | resources: 10 | - cassandradatacenters 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - cassandra.datastax.com 21 | resources: 22 | - cassandradatacenters/status 23 | verbs: 24 | - get 25 | -------------------------------------------------------------------------------- /config/rbac/cassandradatacenter_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view cassandradatacenters. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: cassandradatacenter-viewer-role 6 | rules: 7 | - apiGroups: 8 | - cassandra.datastax.com 9 | resources: 10 | - cassandradatacenters 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - apiGroups: 16 | - cassandra.datastax.com 17 | resources: 18 | - cassandradatacenters/status 19 | verbs: 20 | - get 21 | -------------------------------------------------------------------------------- /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 | 13 | -------------------------------------------------------------------------------- /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 | - coordination.k8s.io 10 | resources: 11 | - configmaps 12 | - leases 13 | verbs: 14 | - get 15 | - list 16 | - watch 17 | - create 18 | - update 19 | - patch 20 | - delete 21 | - apiGroups: 22 | - "" 23 | resources: 24 | - events 25 | verbs: 26 | - create 27 | - patch 28 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /config/rbac/metrics_auth_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics-auth-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/metrics_auth_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: metrics-auth-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: metrics-auth-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/rbac/metrics_reader_role.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/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: manager-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: manager-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | --- 13 | apiVersion: rbac.authorization.k8s.io/v1 14 | kind: ClusterRoleBinding 15 | metadata: 16 | name: manager-res-rolebinding 17 | roleRef: 18 | apiGroup: rbac.authorization.k8s.io 19 | kind: ClusterRole 20 | name: cass-operator-manager-role 21 | subjects: 22 | - kind: ServiceAccount 23 | name: controller-manager 24 | -------------------------------------------------------------------------------- /config/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: cass-operator 6 | app.kubernetes.io/managed-by: kustomize 7 | name: controller-manager 8 | -------------------------------------------------------------------------------- /config/samples/cassandratask-cleanup.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: control.k8ssandra.io/v1alpha1 2 | kind: CassandraTask 3 | metadata: 4 | name: example-cleanup 5 | spec: 6 | datacenter: 7 | name: dc2 8 | namespace: cass-operator 9 | jobs: 10 | - name: cleanup-run 11 | command: cleanup 12 | -------------------------------------------------------------------------------- /config/samples/cassandratask-replacenode.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: control.k8ssandra.io/v1alpha1 2 | kind: CassandraTask 3 | metadata: 4 | name: example-replace 5 | spec: 6 | datacenter: 7 | name: dc1 8 | namespace: cass-operator 9 | jobs: 10 | - name: replace-run 11 | command: replacenode 12 | args: 13 | pod_name: cluster1-dc1-r2-sts-0 14 | -------------------------------------------------------------------------------- /config/samples/cassandratask-sstables.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: control.k8ssandra.io/v1alpha1 2 | kind: CassandraTask 3 | metadata: 4 | name: example-upgradesstables 5 | spec: 6 | datacenter: 7 | name: dc1 8 | namespace: cass-operator 9 | jobs: 10 | - name: upgrade-run 11 | command: upgradesstables 12 | -------------------------------------------------------------------------------- /config/samples/example-cassdc-three-nodes-single-rack.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: development 7 | serverType: cassandra 8 | serverVersion: "4.1.2" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 3 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: server-storage 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 10Gi 20 | podTemplateSpec: 21 | spec: 22 | containers: 23 | - name: "cassandra" 24 | securityContext: {} 25 | resources: 26 | requests: 27 | memory: 2Gi 28 | cpu: 1000m 29 | racks: 30 | - name: rack1 31 | - name: rack2 32 | - name: rack3 33 | config: 34 | jvm-server-options: 35 | initial_heap_size: "1G" 36 | max_heap_size: "1G" 37 | cassandra-yaml: 38 | num_tokens: 16 39 | authenticator: PasswordAuthenticator 40 | authorizer: CassandraAuthorizer 41 | role_manager: CassandraRoleManager 42 | -------------------------------------------------------------------------------- /config/samples/kustomization.yaml: -------------------------------------------------------------------------------- 1 | ## Append samples you want in your CSV to this file as resources ## 2 | resources: 3 | - example-cassdc-three-nodes-single-rack.yaml 4 | - cassandratask-cleanup.yaml 5 | - scheduledtask.yaml 6 | #+kubebuilder:scaffold:manifestskustomizesamples 7 | -------------------------------------------------------------------------------- /config/samples/scheduledtask.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: control.k8ssandra.io/v1alpha1 2 | kind: ScheduledTask 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: cass-operator 6 | app.kubernetes.io/managed-by: kustomize 7 | name: scheduledtask-sample 8 | spec: 9 | schedule: "*/1 * * * *" 10 | taskDetails: 11 | name: "my-task" 12 | datacenter: 13 | name: dc1 14 | namespace: cass-operator 15 | jobs: 16 | - name: replace-run 17 | command: replacenode 18 | args: 19 | pod_name: cluster1-dc1-r2-sts-0 20 | -------------------------------------------------------------------------------- /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.34.0 8 | labels: 9 | suite: basic 10 | test: basic-check-spec-test 11 | -------------------------------------------------------------------------------- /config/scorecard/patches/olm.config.yaml: -------------------------------------------------------------------------------- 1 | - op: add 2 | path: /stages/0/tests/- 3 | value: 4 | entrypoint: 5 | - scorecard-test 6 | - olm-bundle-validation 7 | image: quay.io/operator-framework/scorecard-test:v1.34.0 8 | labels: 9 | suite: olm 10 | test: olm-bundle-validation-test 11 | - op: add 12 | path: /stages/0/tests/- 13 | value: 14 | entrypoint: 15 | - scorecard-test 16 | - olm-crds-have-validation 17 | image: quay.io/operator-framework/scorecard-test:v1.34.0 18 | labels: 19 | suite: olm 20 | test: olm-crds-have-validation-test 21 | - op: add 22 | path: /stages/0/tests/- 23 | value: 24 | entrypoint: 25 | - scorecard-test 26 | - olm-crds-have-resources 27 | image: quay.io/operator-framework/scorecard-test:v1.34.0 28 | labels: 29 | suite: olm 30 | test: olm-crds-have-resources-test 31 | - op: add 32 | path: /stages/0/tests/- 33 | value: 34 | entrypoint: 35 | - scorecard-test 36 | - olm-spec-descriptors 37 | image: quay.io/operator-framework/scorecard-test:v1.34.0 38 | labels: 39 | suite: olm 40 | test: olm-spec-descriptors-test 41 | - op: add 42 | path: /stages/0/tests/- 43 | value: 44 | entrypoint: 45 | - scorecard-test 46 | - olm-status-descriptors 47 | image: quay.io/operator-framework/scorecard-test:v1.34.0 48 | labels: 49 | suite: olm 50 | test: olm-status-descriptors-test 51 | -------------------------------------------------------------------------------- /config/webhook/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manifests.yaml 3 | - service.yaml 4 | 5 | configurations: 6 | - kustomizeconfig.yaml 7 | -------------------------------------------------------------------------------- /config/webhook/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # the following config is for teaching kustomize where to look at when substituting vars. 2 | # It requires kustomize v2.1.0 or newer to work properly. 3 | nameReference: 4 | - kind: Service 5 | version: v1 6 | fieldSpecs: 7 | - kind: MutatingWebhookConfiguration 8 | group: admissionregistration.k8s.io 9 | path: webhooks/clientConfig/service/name 10 | - kind: ValidatingWebhookConfiguration 11 | group: admissionregistration.k8s.io 12 | path: webhooks/clientConfig/service/name 13 | 14 | namespace: 15 | - kind: MutatingWebhookConfiguration 16 | group: admissionregistration.k8s.io 17 | path: webhooks/clientConfig/service/namespace 18 | create: true 19 | - kind: ValidatingWebhookConfiguration 20 | group: admissionregistration.k8s.io 21 | path: webhooks/clientConfig/service/namespace 22 | create: true 23 | -------------------------------------------------------------------------------- /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-cassandra-datastax-com-v1beta1-cassandradatacenter 14 | failurePolicy: Fail 15 | name: mcassandradatacenter.kb.io 16 | rules: 17 | - apiGroups: 18 | - cassandra.datastax.com 19 | apiVersions: 20 | - v1beta1 21 | operations: 22 | - CREATE 23 | - UPDATE 24 | resources: 25 | - cassandradatacenters 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-cassandra-datastax-com-v1beta1-cassandradatacenter 40 | failurePolicy: Fail 41 | name: vcassandradatacenter.kb.io 42 | rules: 43 | - apiGroups: 44 | - cassandra.datastax.com 45 | apiVersions: 46 | - v1beta1 47 | operations: 48 | - CREATE 49 | - UPDATE 50 | resources: 51 | - cassandradatacenters 52 | sideEffects: None 53 | -------------------------------------------------------------------------------- /config/webhook/service.yaml: -------------------------------------------------------------------------------- 1 | 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: webhook-service 6 | namespace: system 7 | labels: 8 | app.kubernetes.io/name: cass-operator 9 | app.kubernetes.io/managed-by: kustomize 10 | spec: 11 | ports: 12 | - port: 443 13 | targetPort: 9443 14 | selector: 15 | control-plane: controller-manager 16 | -------------------------------------------------------------------------------- /docs/developer/diagrams/scale-up-diagram.mmd: -------------------------------------------------------------------------------- 1 | sequenceDiagram 2 | participant user as User 3 | participant operator as Cass Operator 4 | participant dc as dc1
CassandraDatacenter 5 | participant sts as cluster1-dc1-r1-sts
StatefulSet 6 | participant sts_ctrl as StatefulSet
Controller 7 | participant pod1 as cluster1-dc1-r1-sts-1
Pod 8 | participant pod2 as cluster1-dc1-r1-sts-2
Pod 9 | user->>dc: update size by 2 10 | dc->>operator: update event 11 | operator->>dc: set ScalingUp condition to True 12 | operator->>sts: increment replicas by 2 13 | sts->>sts_ctrl: update event 14 | par create pods in parallel 15 | sts_ctrl->>pod1: create 16 | and 17 | sts_ctrl->>pod2: create 18 | end 19 | loop requeue reconcile event until Node Management API running 20 | operator->>pod1: check Node Management API running 21 | operator->>pod2: check Node Management API running 22 | end 23 | Note over operator,pod1: Assuming Node Management API starts running on cluster1-dc1-r1-sts-1 first 24 | operator->>pod1: start cassandra 25 | Note over sts_ctrl,pod1: pod ready when cassandra
finished starting 26 | pod1->>sts_ctrl: update event (pod ready) 27 | sts_ctrl->>sts: increment ready replicas 28 | sts->>operator: update event 29 | loop requeue reconcile event until Node Management API running 30 | operator->>pod2: check Node Management API running 31 | end 32 | operator->>pod2: start cassandra 33 | Note over sts_ctrl,pod2: pod ready when cassandra finished starting 34 | pod2->>sts_ctrl: update event (pod ready) 35 | sts_ctrl->>sts: increment ready replicas 36 | sts->>operator: update event 37 | operator->>dc: set ScalingUp condition to False -------------------------------------------------------------------------------- /docs/developer/kind.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Kind cluster 2 | 3 | For development purposes, the [Kind](https://kind.sigs.k8s.io/) cluster is the closest to a real Kubernetes cluster in terms of compatibility. For that reason, we use it as a default for our integration testing. We've built some tools and helpers to simplify the workflow for development purposes. 4 | 5 | ## Install kind 6 | 7 | Some Linux distributions provide kind from their package registry, but in case you have Go already installed, this command is enough to install newest kind version: 8 | 9 | ```console 10 | go get sigs.k8s.io/kind@v0.16.0 11 | ``` 12 | 13 | Or to download a binary directly: 14 | 15 | ```console 16 | curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.16.0/kind-linux-amd64 17 | chmod +x ./kind 18 | ``` 19 | 20 | ## Setting up a kind cluster 21 | 22 | To start a new cluster, it is enough to run: 23 | 24 | ```console 25 | kind cluster create 26 | ``` 27 | 28 | But some of tests require more than one Cassandra node (and more than one Kind worker node), so to start a six worker node cluster would be: 29 | 30 | ```console 31 | kind cluster create --config=tests/testdata/kind/kind_config_6_workers.yaml 32 | ``` 33 | 34 | ## Deploy cass-operator to kind cluster 35 | 36 | To compile your version of cass-operator and load it to your kind cluster, run the following command: 37 | 38 | ```console 39 | make docker-build docker-kind 40 | ``` 41 | 42 | That builds the operator and then loads the resulting image to your kind cluster. To deploy it: 43 | 44 | ```console 45 | make deploy 46 | ``` 47 | 48 | And likewise, ``make undeploy`` will remove it from the kind cluster. 49 | 50 | ## Deleting the cluster 51 | 52 | Running the following command deletes a kind cluster: 53 | 54 | ```console 55 | kind delete cluster 56 | ``` -------------------------------------------------------------------------------- /docs/developer/mocks.md: -------------------------------------------------------------------------------- 1 | To regenerate the mockClient, the following steps are necessary when using mockery 2.x. This is a bit complicated, due to some historical contexts (feel free to fix and make mocking easier). 2 | 3 | Install mockery: https://vektra.github.io/mockery/latest/installation/ 4 | 5 | ## Create 6 | 7 | Create `pkg/mockhelper`. Add following file there: 8 | 9 | ```go 10 | package mockhelper 11 | 12 | import ( 13 | "net/http" 14 | 15 | client "sigs.k8s.io/controller-runtime/pkg/client" 16 | ) 17 | 18 | type Client interface { 19 | client.Client 20 | } 21 | 22 | type HttpClient interface { 23 | http.Client 24 | } 25 | ``` 26 | 27 | Create `.mockery.yaml`: 28 | 29 | ``` 30 | quiet: False 31 | disable-version-string: True 32 | with-expecter: True 33 | mockname: "{{.InterfaceName}}" 34 | filename: "{{.MockName}}.go" 35 | outpkg: mocks 36 | packages: 37 | github.com/k8ssandra/cass-operator/pkg/mockhelper: 38 | interfaces: 39 | Client: 40 | config: 41 | HttpClient: 42 | config: 43 | # TypesPackage: 44 | ``` 45 | 46 | Copy generated files to `pkg/mocks` and modify. Remove from controller-runtime client (`Client.go`): 47 | 48 | ``` 49 | // Client is an autogenerated mock type for the Client type 50 | type Client struct { 51 | mock.Mock 52 | } 53 | ```` 54 | 55 | Comment out methods: `NewClient()`, `SubResource(subResource string)` and `Status()`. All of these are already separately created in `mocks/helper.go`, since we want to modify the behavior of certain Status checks in our test code. -------------------------------------------------------------------------------- /docs/developer/seeds.md: -------------------------------------------------------------------------------- 1 | We've adjusted our procedures and rules for getting seed nodes at least a couple times, so I wanted to document the procedure in a way I'll remember it, and my approach for testing. 2 | 3 | - Procedure 4 | 5 | Pods should be labelled as a seed *after* they are ready to service traffic. Labelling them as a seed before has gotten us in trouble. 6 | 7 | The *only* exception to the above is the state where there are no nodes that can serve traffic, like starting a fresh cluster OR unparking. 8 | 9 | For me, it really helped to think about getting seeds into a good state as the task to do right before we start a DSE node. 10 | 11 | Because it is best to follow the Kubernetes principle of resources being declarative, I coded the operator to label the lowest ordinal pod(s) in each statefulset as the seed nodes. This can create a situation where a seed pod dies, and the the operator labels a neighboring pod as a seed, brings the "original" seed back online, and then swaps the seed label to the pod it just started. I think this is all fine. 12 | 13 | - Testing ideas 14 | 15 | The basic (but comprehensive) scenario of... 16 | * Bring up a three node / three rack cluster -> add three more nodes -> park the cluster -> unpark the cluster 17 | 18 | In addition, I thought a good test was to... 19 | 20 | * Bring up a nine node / three rack cluster -> `kubectl delete` the three seed nodes -> watch the operator label three other nodes as seeds -> watch the operator bring the three missing nodes back online 21 | 22 | There's good output to understand what's going on when you start a long process and then watch output from... 23 | ```bash 24 | kubectl -n dse-ns get pod -L com.datastax.dse.node.state,com.datastax.dse.seednode -w 25 | ``` -------------------------------------------------------------------------------- /docs/developer/validating_webhook.md: -------------------------------------------------------------------------------- 1 | ## The validating webhook. 2 | 3 | The operator offers, and installs when possible, a validating webhook for 4 | related CRDs. The webhook is intended to provide checks of the validity of an 5 | update or create request, where there might be CRD-specific guardrails that are 6 | not readily checked by implicit CRD validity. Such checks include preventing 7 | renaming certain elements of the deployment, such as the the cassandra cluster 8 | or the racks, which are core to the identity of a cassandra cluster. 9 | 10 | Validating webhooks have specific requirements in kubernetes: 11 | * They must be served over TLS 12 | * The TLS service name where they are reached must match the subject of the certificate 13 | * The CA signing the certificate must be either installed in the kube apiserver filesystem, or 14 | explicitly configured in the kubernetes validatingwebhookconfiguration object. 15 | 16 | To support the above scenarios, the operator uses cert-manager to take care of generating and 17 | injecting the certificates. The validating webhook can be disabled in the OperatorConfig, which is 18 | mounted as a ConfigMap to the container. -------------------------------------------------------------------------------- /docs/developer/workflow_details.md: -------------------------------------------------------------------------------- 1 | ## How the operator scales up a datacenter 2 | 3 | Given `CassandraDatacenter` like the following: 4 | 5 | ```yaml 6 | apiVersion: cassandra.datastax.com/v1beta1 7 | kind: CassandraDatacenter 8 | metadata: 9 | name: dc1 10 | spec: 11 | clusterName: cluster1 12 | serverType: cassandra 13 | serverVersion: "3.11.11" 14 | managementApiAuth: 15 | insecure: {} 16 | size: 1 17 | storageConfig: 18 | cassandraDataVolumeClaimSpec: 19 | storageClassName: server-storage 20 | accessModes: 21 | - ReadWriteOnce 22 | resources: 23 | requests: 24 | storage: 1Gi 25 | racks: 26 | - name: r1 27 | ``` 28 | 29 | When a user scales up the datacenter, for example, by doing the following: 30 | 31 | ``` 32 | kubectl patch cassandradatacenter/dc1 --patch '{"spec":{"size":3}}' --type merge 33 | ``` 34 | 35 | This is what the Cass Operator will do: 36 | 37 | ![scale-up sequence diagram](./diagrams/scale-up-diagram.svg) 38 | -------------------------------------------------------------------------------- /docs/ingress/sample-cluster-sample-dc.yaml: -------------------------------------------------------------------------------- 1 | # Sized to work on 3 k8s workers nodes with 1 core / 4 GB RAM 2 | # See neighboring example-cassdc-full.yaml for docs for each parameter 3 | apiVersion: cassandra.datastax.com/v1beta1 4 | kind: CassandraDatacenter 5 | metadata: 6 | name: sample-dc 7 | spec: 8 | clusterName: sample-cluster 9 | serverType: cassandra 10 | serverVersion: "4.1.5" 11 | managementApiAuth: 12 | insecure: {} 13 | racks: 14 | - name: sample-rack 15 | size: 3 16 | allowMultipleNodesPerWorker: true 17 | storageConfig: 18 | cassandraDataVolumeClaimSpec: 19 | storageClassName: local-path 20 | accessModes: 21 | - ReadWriteOnce 22 | resources: 23 | requests: 24 | storage: 1Gi 25 | config: 26 | cassandra-yaml: {} 27 | # authenticator: org.apache.cassandra.auth.PasswordAuthenticator 28 | # authorizer: org.apache.cassandra.auth.CassandraAuthorizer 29 | # role_manager: org.apache.cassandra.auth.CassandraRoleManager 30 | jvm-server-options: 31 | initial_heap_size: "800M" 32 | max_heap_size: "800M" 33 | -------------------------------------------------------------------------------- /docs/ingress/sample-java-application/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | client.keystore 3 | client.truststore 4 | *.iml 5 | .idea 6 | keylog.log 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .vscode 12 | -------------------------------------------------------------------------------- /docs/ingress/sample-java-application/README.md: -------------------------------------------------------------------------------- 1 | # Sample Application with Kubernetes Ingress 2 | 3 | This project is to illustrates how to configure and validate connectivity to Cassandra clusters running within Kubernetes. There are three reference client implementations available: 4 | 5 | * mTLS and SNI based balancing 6 | * Load balancing with mTLS 7 | * Simple load balancing 8 | 9 | At this time there is some _slight_ tweaking required to the configuration files to specify the keystore, truststore, and approach to use. 10 | 11 | Any connections requiring TLS support should place their keystore an truststore in the `src/main/resources/` directory. If you followed the [SSL](../ssl) guide then you should already have these files available. 12 | 13 | ## Building and Running 14 | 15 | ``` 16 | mvn exec:exec@ingress 17 | Discovered Nodes 18 | sample-dc:sample-rack:fd280adc-e55e-4f3d-97d1-138a1e1abef4 19 | sample-dc:sample-rack:fd280adc-e55e-4f3d-97d1-138a1e1abef4 20 | sample-dc:sample-rack:fd280adc-e55e-4f3d-97d1-138a1e1abef4 21 | 22 | Coordinator: sample-dc:sample-rack:fd280adc-e55e-4f3d-97d1-138a1e1abef4 23 | [data_center:'sample-dc', rack:'sample-rack', host_id:a7a45d6e-70e3-4e6d-b29c-5dba9a61a282, release_version:'3.11.6'] 24 | 25 | Coordinator: sample-dc:sample-rack:fd280adc-e55e-4f3d-97d1-138a1e1abef4 26 | [data_center:'sample-dc', rack:'sample-rack', host_id:7e2921a6-e170-4a4f-bf0f-011ab83b3739, release_version:'3.11.6'] 27 | [data_center:'sample-dc', rack:'sample-rack', host_id:fd280adc-e55e-4f3d-97d1-138a1e1abef4, release_version:'3.11.6'] 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/ingress/sample-java-application/lib/jSSLKeyLog.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k8ssandra/cass-operator/a8d22a71b49d815ec91fd593ad35f704cf339108/docs/ingress/sample-java-application/lib/jSSLKeyLog.jar -------------------------------------------------------------------------------- /docs/ingress/sample-java-application/src/main/java/com/datastax/kubernetes/KubernetesIngressAddressTranslator.java: -------------------------------------------------------------------------------- 1 | package com.datastax.kubernetes; 2 | 3 | import com.datastax.oss.driver.api.core.addresstranslation.AddressTranslator; 4 | import com.datastax.oss.driver.api.core.context.DriverContext; 5 | import edu.umd.cs.findbugs.annotations.NonNull; 6 | 7 | import java.net.InetSocketAddress; 8 | 9 | public class KubernetesIngressAddressTranslator implements AddressTranslator { 10 | private DriverContext driverContext; 11 | 12 | public KubernetesIngressAddressTranslator(DriverContext driverContext) { 13 | this.driverContext = driverContext; 14 | } 15 | 16 | @NonNull 17 | @Override 18 | public InetSocketAddress translate(@NonNull InetSocketAddress address) { 19 | String ingressAddress = driverContext.getConfig().getDefaultProfile().getString(KubernetesOption.INGRESS_ADDRESS); 20 | int ingressPort = driverContext.getConfig().getDefaultProfile().getInt(KubernetesOption.INGRESS_PORT); 21 | 22 | return new InetSocketAddress(ingressAddress, ingressPort); 23 | } 24 | 25 | @Override 26 | public void close() { 27 | // NOOP 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/ingress/sample-java-application/src/main/java/com/datastax/kubernetes/KubernetesOption.java: -------------------------------------------------------------------------------- 1 | package com.datastax.kubernetes; 2 | 3 | import com.datastax.oss.driver.api.core.config.DriverOption; 4 | import edu.umd.cs.findbugs.annotations.NonNull; 5 | 6 | public enum KubernetesOption implements DriverOption { 7 | ENDPOINTS("advanced.k8s.endpoints"), 8 | INGRESS_ADDRESS("advanced.k8s.ingress.address"), 9 | INGRESS_PORT("advanced.k8s.ingress.port"); 10 | 11 | private final String path; 12 | 13 | KubernetesOption(String path) { 14 | this.path = path; 15 | } 16 | 17 | @Override 18 | @NonNull 19 | public String getPath() { 20 | return path; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /docs/ingress/sample-java-application/src/main/resources/direct.conf: -------------------------------------------------------------------------------- 1 | datastax-java-driver { 2 | basic { 3 | session-name = "Direct" 4 | contact-points = ["sample-cluster-sample-dc-service:9042"] 5 | keyspace = "system" 6 | 7 | application { 8 | name = "Direct" 9 | version = "1.0.0-SNAPSHOT" 10 | } 11 | 12 | load-balancing-policy { 13 | local-datacenter = "sample-dc" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /docs/ingress/sample-java-application/src/main/resources/ingress.conf: -------------------------------------------------------------------------------- 1 | datastax-java-driver { 2 | basic { 3 | session-name = "Ingress" 4 | # Use the address of your ingress here 5 | contact-points = ["k3s.local:9042"] 6 | keyspace = "system" 7 | 8 | application { 9 | name = "Ingress" 10 | version = "1.0.0-SNAPSHOT" 11 | } 12 | 13 | load-balancing-policy { 14 | local-datacenter = "sample-dc" 15 | } 16 | } 17 | 18 | advanced { 19 | address-translator.class = com.datastax.kubernetes.KubernetesIngressAddressTranslator 20 | 21 | # Use the address of your ingress here 22 | k8s.ingress { 23 | address = "k3s.local" 24 | port = 9042 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/ingress/sample-java-application/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/ingress/sample-java-application/src/main/resources/mtls-sni-ingress.conf: -------------------------------------------------------------------------------- 1 | datastax-java-driver { 2 | basic { 3 | session-name = "mTLS SNI Ingress" 4 | session-keyspace = "system" 5 | 6 | application { 7 | name = "mTLS SNI Ingress" 8 | version = "1.0.0-SNAPSHOT" 9 | } 10 | 11 | load-balancing-policy { 12 | local-datacenter = "sample-dc" 13 | } 14 | } 15 | 16 | advanced { 17 | protocol { 18 | version = V4 19 | } 20 | 21 | ssl-engine-factory { 22 | class = com.datastax.oss.driver.internal.core.ssl.SniSslEngineFactory 23 | 24 | hostname-validation = false 25 | 26 | truststore-path = "../ssl/client.truststore" 27 | truststore-password = "changeit" 28 | 29 | keystore-path = "../ssl/client.keystore" 30 | keystore-password = "changeit" 31 | } 32 | 33 | # Use the address of your ingress here 34 | k8s { 35 | endpoints = [ 36 | "bbbf5a34-2240-4efb-ac06-c7974a2ec3dd", 37 | "73a03b32-bdb6-4b2a-a5db-dfd078ec8131", 38 | "deab7ace-711c-407f-96a0-bcba5099855b" 39 | ] 40 | 41 | ingress { 42 | address = "k3s.local" 43 | port = 9042 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /docs/ingress/sample-java-application/src/main/resources/sni-ingress.conf: -------------------------------------------------------------------------------- 1 | datastax-java-driver { 2 | basic { 3 | session-name = "SNI Ingress" 4 | session-keyspace = "system" 5 | 6 | application { 7 | name = "SNI Ingress" 8 | version = "1.0.0-SNAPSHOT" 9 | } 10 | 11 | load-balancing-policy { 12 | local-datacenter = "sample-dc" 13 | } 14 | } 15 | 16 | advanced { 17 | protocol { 18 | version = V4 19 | } 20 | 21 | ssl-engine-factory { 22 | class = com.datastax.oss.driver.internal.core.ssl.SniSslEngineFactory 23 | 24 | hostname-validation = false 25 | 26 | truststore-path = "../ssl/client.truststore" 27 | truststore-password = "changeit" 28 | } 29 | 30 | # Use the address of your ingress here 31 | k8s { 32 | endpoints = [ 33 | "c293a595-a08e-4a9c-b6bc-af5d279ffe76" 34 | "73a03b32-bdb6-4b2a-a5db-dfd078ec8131", 35 | "deab7ace-711c-407f-96a0-bcba5099855b" 36 | ] 37 | 38 | ingress { 39 | address = "k3s.local" 40 | port = 9042 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /docs/ingress/sample-java-application/src/test/java/com/datastax/examples/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.datastax.examples; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /docs/ingress/ssl/README.md: -------------------------------------------------------------------------------- 1 | # Sample SSL Certificates and Keys 2 | 3 | ## Requirements 4 | 5 | * [CFSSL](https://cfssl.org/) 6 | 7 | ## Generate Certificate Authority 8 | 9 | ```bash 10 | # Create CA from a JSON template 11 | cfssl gencert -initca ca.csr.json | cfssljson -bare ca 12 | 13 | # Create the secret resource 14 | kubectl create secret generic ca-cert --from-file=tls.cert=ca.pem --from-file=tls.ca=ca.pem 15 | 16 | # Create a truststore for the application 17 | keytool -import -v -trustcacerts -alias CARoot -file ca.pem -keystore client.truststore 18 | ``` 19 | 20 | ## Generate Ingress Certificate 21 | 22 | ```bash 23 | # If you are using SNI, retrieve the host IDs to include in the Ingress CSR 24 | # Make sure all nodes are up, then extract the values from the nodeStatuses field. 25 | kubectl get cassdc sample-dc -o yaml 26 | 27 | # Create and sign the Ingress certificate 28 | cfssl gencert -ca ca.pem -ca-key ca-key.pem ingress.csr.json | cfssljson -bare ingress 29 | 30 | # Create the secret resource 31 | kubectl create secret generic sample-cluster-sample-dc-cert --from-file=tls.crt=ingress.pem --from-file=tls.key=ingress-key.pem --from-file=tls.ca=ca.pem 32 | ``` 33 | 34 | ## Generate Client Certificate 35 | 36 | ```bash 37 | # Create and sign Client certificate 38 | cfssl gencert -ca ca.pem -ca-key ca-key.pem client.csr.json | cfssljson -bare client 39 | 40 | # Create the keystore for the client 41 | openssl pkcs12 -export -in client.pem -inkey client-key.pem -out client.p12 42 | keytool -importkeystore -destkeystore client.keystore -srckeystore client.p12 -srcstoretype PKCS12 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/ingress/ssl/ca.csr.json: -------------------------------------------------------------------------------- 1 | { 2 | "CN": "Sample Self-Signed CA", 3 | "key": { 4 | "algo": "rsa", 5 | "size": 2048 6 | }, 7 | "names": [ 8 | { 9 | "C": "US", 10 | "ST": "California", 11 | "L": "Santa Clara", 12 | "O": "Engineering", 13 | "OU": "Cassandra Operator" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /docs/ingress/ssl/client.csr.json: -------------------------------------------------------------------------------- 1 | { 2 | "CN": "sample-application", 3 | "key": { 4 | "algo": "rsa", 5 | "size": 2048 6 | }, 7 | "hosts": [], 8 | "names": [ 9 | { 10 | "C": "US", 11 | "ST": "California", 12 | "L": "Santa Clara", 13 | "O": "Engineering", 14 | "OU": "Cassandra Operator" 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /docs/ingress/ssl/client.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k8ssandra/cass-operator/a8d22a71b49d815ec91fd593ad35f704cf339108/docs/ingress/ssl/client.keystore -------------------------------------------------------------------------------- /docs/ingress/ssl/client.truststore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k8ssandra/cass-operator/a8d22a71b49d815ec91fd593ad35f704cf339108/docs/ingress/ssl/client.truststore -------------------------------------------------------------------------------- /docs/ingress/ssl/ingress.csr.json: -------------------------------------------------------------------------------- 1 | { 2 | "CN": "sample-dc.sample-cluster", 3 | "key": { 4 | "algo": "rsa", 5 | "size": 2048 6 | }, 7 | "hosts": [ 8 | "k3s.local", 9 | "c293a595-a08e-4a9c-b6bc-af5d279ffe76", 10 | "deab7ace-711c-407f-96a0-bcba5099855b", 11 | "73a03b32-bdb6-4b2a-a5db-dfd078ec8131" 12 | ], 13 | "names": [ 14 | { 15 | "C": "US", 16 | "ST": "California", 17 | "L": "Santa Clara", 18 | "O": "Engineering", 19 | "OU": "Cassandra Operator" 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025. 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 | */ -------------------------------------------------------------------------------- /hack/gatekeeper/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - github.com/open-policy-agent/gatekeeper-library/library 5 | -------------------------------------------------------------------------------- /hack/license-prepend/license-header.txt: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | -------------------------------------------------------------------------------- /hack/license-prepend/license-prepend.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euf -o pipefail 4 | set -x 5 | 6 | filelist="$(mktemp)" 7 | 8 | git ls-files | fgrep '.go' > "$filelist" 9 | 10 | for i in $(cat "$filelist") 11 | do 12 | if ! grep -q 'Please see the included license file for details' "$i" 13 | then 14 | cat hack/license-prepend/license-header.txt "$i" > "$i.TEMP" && mv "$i.TEMP" "$i" 15 | fi 16 | done 17 | -------------------------------------------------------------------------------- /internal/result/result_helper.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package result 5 | 6 | import ( 7 | "time" 8 | 9 | ctrl "sigs.k8s.io/controller-runtime" 10 | ) 11 | 12 | var DurationFunc func(int) time.Duration = func(secs int) time.Duration { return time.Duration(secs) * time.Second } 13 | 14 | type ReconcileResult interface { 15 | Completed() bool 16 | Output() (ctrl.Result, error) 17 | } 18 | 19 | type continueReconcile struct{} 20 | 21 | func (c continueReconcile) Completed() bool { 22 | return false 23 | } 24 | func (c continueReconcile) Output() (ctrl.Result, error) { 25 | panic("there was no Result to return") 26 | } 27 | 28 | type done struct{} 29 | 30 | func (d done) Completed() bool { 31 | return true 32 | } 33 | func (d done) Output() (ctrl.Result, error) { 34 | return ctrl.Result{}, nil 35 | } 36 | 37 | type callBackSoon struct { 38 | secs int 39 | } 40 | 41 | func (c callBackSoon) Completed() bool { 42 | return true 43 | } 44 | func (c callBackSoon) Output() (ctrl.Result, error) { 45 | t := DurationFunc(c.secs) 46 | return ctrl.Result{Requeue: true, RequeueAfter: t}, nil 47 | } 48 | 49 | type errorOut struct { 50 | err error 51 | } 52 | 53 | func (e errorOut) Completed() bool { 54 | return true 55 | } 56 | func (e errorOut) Output() (ctrl.Result, error) { 57 | return ctrl.Result{}, e.err 58 | } 59 | 60 | func Continue() ReconcileResult { 61 | return continueReconcile{} 62 | } 63 | 64 | func Done() ReconcileResult { 65 | return done{} 66 | } 67 | 68 | func RequeueSoon(secs int) ReconcileResult { 69 | return callBackSoon{secs: secs} 70 | } 71 | 72 | func Error(e error) ReconcileResult { 73 | return errorOut{err: e} 74 | } 75 | -------------------------------------------------------------------------------- /internal/result/result_helper_test.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package result 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | "time" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 13 | ) 14 | 15 | func TestContinue(t *testing.T) { 16 | t.Run("test Continue() fitting the interface", func(t *testing.T) { 17 | c := Continue() 18 | assert.False(t, c.Completed(), "Continue() output should say reconciling is not complete") 19 | 20 | assert.Panics( 21 | t, 22 | func() { 23 | res, err := c.Output() 24 | fmt.Println(res) 25 | fmt.Println(err) 26 | }, "Output() should panic for Continue()") 27 | }) 28 | } 29 | 30 | func TestDone(t *testing.T) { 31 | t.Run("test Done() fitting the interface", func(t *testing.T) { 32 | d := Done() 33 | assert.True(t, d.Completed(), "Done() output should say reconciling is complete") 34 | 35 | res, err := d.Output() 36 | assert.Equal(t, reconcile.Result{}, res, "Done() should return the zero value reconcile.Result{}") 37 | 38 | assert.NoError(t, err, "Done() should not have an error") 39 | }) 40 | } 41 | 42 | func TestError(t *testing.T) { 43 | t.Run("test Continue() fitting the interface", func(t *testing.T) { 44 | e := Error(fmt.Errorf("problem message")) 45 | 46 | assert.True(t, e.Completed(), "Error() output should say reconciling is complete") 47 | 48 | _, err := e.Output() 49 | 50 | assert.Error(t, err, "Error() should have an error") 51 | }) 52 | } 53 | 54 | func TestRequeueSoon(t *testing.T) { 55 | t.Run("test RequeueSoon() fitting the interface", func(t *testing.T) { 56 | r := RequeueSoon(10) 57 | 58 | assert.True(t, r.Completed(), "RequeueSoon() output should say reconciling is complete") 59 | 60 | res, err := r.Output() 61 | 62 | assert.NoError(t, err, "RequeueSoon() should not have an error") 63 | 64 | tenSecs := time.Second * 10 65 | assert.Equal(t, reconcile.Result{Requeue: true, RequeueAfter: tenSecs}, res, 66 | "RequeueSoon() should return a reconcile.Result{} with Requeue=true and 10 seconds") 67 | }) 68 | } 69 | -------------------------------------------------------------------------------- /logger.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM redhat/ubi9:latest AS builder 2 | ARG VERSION 3 | ARG TARGETPLATFORM 4 | 5 | # Install Vector 6 | ENV VECTOR_VERSION=0.46.1 7 | RUN case ${TARGETPLATFORM} in \ 8 | "linux/amd64") VECTOR_ARCH=x86_64 ;; \ 9 | "linux/arm64") VECTOR_ARCH=aarch64 ;; \ 10 | esac \ 11 | && rpm -i https://packages.timber.io/vector/${VECTOR_VERSION}/vector-${VECTOR_VERSION}-1.${VECTOR_ARCH}.rpm 12 | 13 | FROM redhat/ubi9-micro:latest 14 | 15 | ARG VERSION 16 | ARG TARGETPLATFORM 17 | 18 | LABEL maintainer="DataStax, Inc " 19 | LABEL name="system-logger" 20 | LABEL vendor="DataStax, Inc" 21 | LABEL release="${VERSION}" 22 | LABEL version="${VERSION}" 23 | LABEL summary="Sidecar for DataStax Kubernetes Operator for Apache Cassandra " 24 | LABEL description="Sidecar to output Cassandra system logs to stdout" 25 | 26 | # Copy our configuration 27 | COPY ./config/logger/vector_config.toml /etc/vector/vector.toml 28 | COPY --from=builder /usr/lib64/libstdc++.so.6 /usr/lib64/libstdc++.so.6 29 | COPY --from=builder /usr/bin/vector /usr/bin/vector 30 | 31 | ADD https://raw.githubusercontent.com/vectordotdev/vector/master/LICENSE /licences/LICENSE 32 | COPY ./LICENSE.txt /licenses/ 33 | 34 | # Non-root user, cassandra as default 35 | USER cassandra 36 | ENTRYPOINT ["/usr/bin/vector", "--config", "/etc/vector/vector.toml"] 37 | -------------------------------------------------------------------------------- /operator/example-cassdc-yaml/cassandra-3.11.x/example-cassdc-minimal.yaml: -------------------------------------------------------------------------------- 1 | # Sized to work on 3 k8s workers nodes with 1 core / 4 GB RAM 2 | # See neighboring example-cassdc-full.yaml for docs for each parameter 3 | apiVersion: cassandra.datastax.com/v1beta1 4 | kind: CassandraDatacenter 5 | metadata: 6 | name: dc1 7 | spec: 8 | clusterName: cluster1 9 | serverType: cassandra 10 | serverVersion: "3.11.11" 11 | managementApiAuth: 12 | insecure: {} 13 | size: 3 14 | storageConfig: 15 | cassandraDataVolumeClaimSpec: 16 | storageClassName: server-storage 17 | accessModes: 18 | - ReadWriteOnce 19 | resources: 20 | requests: 21 | storage: 5Gi 22 | config: 23 | cassandra-yaml: 24 | authenticator: org.apache.cassandra.auth.PasswordAuthenticator 25 | authorizer: org.apache.cassandra.auth.CassandraAuthorizer 26 | role_manager: org.apache.cassandra.auth.CassandraRoleManager 27 | jvm-options: 28 | initial_heap_size: "800M" 29 | max_heap_size: "800M" 30 | max_direct_memory: "800M" 31 | additional-jvm-opts: 32 | # As the database comes up for the first time, set system keyspaces to RF=3 33 | - "-Ddse.system_distributed_replication_dc_names=dc1" 34 | - "-Ddse.system_distributed_replication_per_dc=3" 35 | -------------------------------------------------------------------------------- /operator/example-cassdc-yaml/cassandra-3.11.x/example-cassdc-three-rack-three-node.yaml: -------------------------------------------------------------------------------- 1 | # Sized to work on 3 k8s workers nodes with 2 cores / 8 GB RAM 2 | # See neighboring example-cassdc-full.yaml for docs for each parameter 3 | apiVersion: cassandra.datastax.com/v1beta1 4 | kind: CassandraDatacenter 5 | metadata: 6 | name: dc1 7 | spec: 8 | clusterName: cluster1 9 | serverType: cassandra 10 | serverVersion: "3.11.11" 11 | managementApiAuth: 12 | insecure: {} 13 | size: 3 14 | racks: 15 | - name: rack1 16 | - name: rack2 17 | - name: rack3 18 | resources: 19 | requests: 20 | memory: 4Gi 21 | cpu: 1000m 22 | storageConfig: 23 | cassandraDataVolumeClaimSpec: 24 | storageClassName: server-storage 25 | accessModes: 26 | - ReadWriteOnce 27 | resources: 28 | requests: 29 | storage: 10Gi 30 | config: 31 | cassandra-yaml: 32 | num_tokens: 8 33 | authenticator: org.apache.cassandra.auth.PasswordAuthenticator 34 | authorizer: org.apache.cassandra.auth.CassandraAuthorizer 35 | role_manager: org.apache.cassandra.auth.CassandraRoleManager 36 | jvm-options: 37 | initial_heap_size: "2G" 38 | max_heap_size: "2G" 39 | max_direct_memory: "1G" 40 | additional-jvm-opts: 41 | - "-Dcassandra.system_distributed_replication_dc_names=dc1" 42 | - "-Dcassandra.system_distributed_replication_per_dc=3" 43 | -------------------------------------------------------------------------------- /operator/example-cassdc-yaml/dse-6.8.x/example-cassdc-minimal.yaml: -------------------------------------------------------------------------------- 1 | # Sized to work on 3 k8s workers nodes with 1 core / 4 GB RAM 2 | # See neighboring example-cassdc-full.yaml for docs for each parameter 3 | apiVersion: cassandra.datastax.com/v1beta1 4 | kind: CassandraDatacenter 5 | metadata: 6 | name: dc1 7 | spec: 8 | clusterName: cluster2 9 | serverType: dse 10 | serverVersion: "6.8.4" 11 | managementApiAuth: 12 | insecure: {} 13 | size: 3 14 | storageConfig: 15 | cassandraDataVolumeClaimSpec: 16 | storageClassName: server-storage 17 | accessModes: 18 | - ReadWriteOnce 19 | resources: 20 | requests: 21 | storage: 5Gi 22 | config: 23 | jvm-server-options: 24 | initial_heap_size: "800M" 25 | max_heap_size: "800M" 26 | max_direct_memory: "800M" 27 | additional-jvm-opts: 28 | # As the database comes up for the first time, set system keyspaces to RF=3 29 | - "-Ddse.system_distributed_replication_dc_names=dc1" 30 | - "-Ddse.system_distributed_replication_per_dc=3" 31 | -------------------------------------------------------------------------------- /operator/example-cassdc-yaml/dse-6.8.x/example-cassdc-three-rack-three-node.yaml: -------------------------------------------------------------------------------- 1 | # Sized to work on 3 k8s workers nodes with 2 cores / 8 GB RAM 2 | # See neighboring example-cassdc-full.yaml for docs for each parameter 3 | apiVersion: cassandra.datastax.com/v1beta1 4 | kind: CassandraDatacenter 5 | metadata: 6 | name: dc1 7 | spec: 8 | clusterName: cluster2 9 | serverType: dse 10 | serverVersion: "6.8.4" 11 | managementApiAuth: 12 | insecure: {} 13 | size: 3 14 | racks: 15 | - name: rack1 16 | - name: rack2 17 | - name: rack3 18 | resources: 19 | requests: 20 | memory: 4Gi 21 | cpu: 1000m 22 | storageConfig: 23 | cassandraDataVolumeClaimSpec: 24 | storageClassName: server-storage 25 | accessModes: 26 | - ReadWriteOnce 27 | resources: 28 | requests: 29 | storage: 10Gi 30 | config: 31 | cassandra-yaml: 32 | num_tokens: 8 33 | authenticator: com.datastax.bdp.cassandra.auth.DseAuthenticator 34 | authorizer: com.datastax.bdp.cassandra.auth.DseAuthorizer 35 | role_manager: com.datastax.bdp.cassandra.auth.DseRoleManager 36 | dse-yaml: 37 | authorization_options: 38 | enabled: true 39 | authentication_options: 40 | enabled: true 41 | default_scheme: internal 42 | jvm-server-options: 43 | initial_heap_size: "2G" 44 | max_heap_size: "2G" 45 | max_direct_memory: "1G" 46 | additional-jvm-opts: 47 | - "-Ddse.system_distributed_replication_dc_names=dc1" 48 | - "-Ddse.system_distributed_replication_per_dc=3" 49 | -------------------------------------------------------------------------------- /operator/k8s-flavors/aks/storage.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | name: server-storage 5 | provisioner: kubernetes.io/azure-disk 6 | parameters: 7 | storageaccounttype: Premium_LRS 8 | kind: Managed 9 | volumeBindingMode: WaitForFirstConsumer 10 | reclaimPolicy: Delete -------------------------------------------------------------------------------- /operator/k8s-flavors/eks/storage.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | name: server-storage 5 | provisioner: kubernetes.io/aws-ebs 6 | parameters: 7 | type: gp2 8 | volumeBindingMode: WaitForFirstConsumer 9 | reclaimPolicy: Delete 10 | -------------------------------------------------------------------------------- /operator/k8s-flavors/gke/storage.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | name: server-storage 5 | provisioner: kubernetes.io/gce-pd 6 | parameters: 7 | type: pd-ssd 8 | replication-type: none 9 | volumeBindingMode: WaitForFirstConsumer 10 | reclaimPolicy: Delete 11 | -------------------------------------------------------------------------------- /operator/k8s-flavors/kind/kind-example-config.yaml: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.sigs.k8s.io/v1alpha3 3 | networking: 4 | apiServerPort: 45451 5 | nodes: 6 | - role: control-plane 7 | - role: worker 8 | - role: worker 9 | - role: worker 10 | -------------------------------------------------------------------------------- /operator/k8s-flavors/minikube/storage.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | name: server-storage 5 | provisioner: k8s.io/minikube-hostpath 6 | reclaimPolicy: Delete 7 | volumeBindingMode: Immediate 8 | -------------------------------------------------------------------------------- /pkg/cdc/serde_test.go: -------------------------------------------------------------------------------- 1 | package cdc 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | var serdeTestConfig = ` 11 | { 12 | "cassandra-env-sh":{ 13 | "initial_heap_size": "800M", 14 | "additional-jvm-opts":[ 15 | "-Ddse.system_distributed_replication_dc_names=dc1" 16 | ] 17 | }, 18 | "cassandra-yaml": { 19 | "authenticator": "PasswordAuthenticator" 20 | }, 21 | "unknownfields": { 22 | "unknown1": true 23 | } 24 | } 25 | ` 26 | 27 | // Tests that Unmarhsalling works as expected. 28 | func Test_UnmarshallConfig(t *testing.T) { 29 | c := configData{} 30 | err := json.Unmarshal([]byte(serdeTestConfig), &c) 31 | assert.NoError(t, err, err) 32 | assert.NotNil(t, c.CassandraYaml) 33 | assert.Contains(t, c.CassandraYaml, "authenticator") 34 | assert.NotNil(t, c.CassEnvSh) 35 | assert.NotNil(t, c.CassEnvSh.AddtnlJVMOptions) 36 | assert.Contains(t, *c.CassEnvSh.AddtnlJVMOptions, "-Ddse.system_distributed_replication_dc_names=dc1") 37 | assert.Contains(t, c.UnknownFields["unknownfields"], "unknown1") 38 | } 39 | 40 | // Tests that Marshalling works as expected. 41 | func Test_MarshallConfig(t *testing.T) { 42 | c := configData{ 43 | CassEnvSh: &cassEnvSh{ 44 | AddtnlJVMOptions: &[]string{"-Ddse.system_distributed_replication_dc_names=dc1"}, 45 | UnknownFields: map[string]interface{}{ 46 | "initial_heap_size": "800M", 47 | }, 48 | }, 49 | CassandraYaml: map[string]interface{}{ 50 | "authenticator": "PasswordAuthenticator", 51 | }, 52 | UnknownFields: map[string]interface{}{ 53 | "unknownfields": map[string]interface{}{ 54 | "unknown1": true, 55 | }, 56 | }, 57 | } 58 | jsonConfig, err := json.Marshal(&c) 59 | assert.NoError(t, err, err) 60 | // Have to marshall everything back to a map[string]interface{} to avoid issues with line breaks etc. 61 | actual := make(map[string]interface{}) 62 | err = json.Unmarshal(jsonConfig, &actual) 63 | assert.NoError(t, err, err) 64 | 65 | expected := make(map[string]interface{}) 66 | err = json.Unmarshal([]byte(serdeTestConfig), &expected) 67 | assert.NoError(t, err, err) 68 | assert.Equal(t, expected, actual) 69 | } 70 | -------------------------------------------------------------------------------- /pkg/cdc/testobjects.go: -------------------------------------------------------------------------------- 1 | package cdc 2 | 3 | import ( 4 | cassdcapi "github.com/k8ssandra/cass-operator/apis/cassandra/v1beta1" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | ) 7 | 8 | // GetCassandraDatacenter gets a minimal CassandraDatacenter object. 9 | func GetCassandraDatacenter(name string, namespace string) cassdcapi.CassandraDatacenter { 10 | return cassdcapi.CassandraDatacenter{ 11 | ObjectMeta: metav1.ObjectMeta{ 12 | Name: name, 13 | Namespace: namespace, 14 | }, 15 | Spec: cassdcapi.CassandraDatacenterSpec{ 16 | Size: 1, 17 | ServerVersion: "4.0.1", 18 | ServerType: "cassandra", 19 | }, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /pkg/httphelper/httpclient.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package httphelper 5 | 6 | import "net/http" 7 | 8 | type HttpClient interface { 9 | Do(req *http.Request) (*http.Response, error) 10 | } 11 | -------------------------------------------------------------------------------- /pkg/httphelper/testdata/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC+zCCAeOgAwIBAgIJAN9TR7rIQmtIMA0GCSqGSIb3DQEBDQUAMBMxETAPBgNV 3 | BAMMCE15Um9vdENBMCAXDTE5MTEwNzE4NTMxM1oYDzIxMTkxMDE0MTg1MzEzWjAT 4 | MREwDwYDVQQDDAhNeVJvb3RDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC 5 | ggEBALsOhG98SGM/8RKi4twAt5BKau7NNUm3QmtBI1kN29hJKG4dMCxr9fxOcn7z 6 | E2C7cDADRkjILQ9Uka7/C3CMBQwlkNAIqDa4oQq/wW12pwCpzhOb18o67p81Iodp 7 | nGf5bIwBMT75O3HYWwdWPMWaMKqi8SRP4+GWs5M2/j+MMB7tdaC/xSn9zt+j56HK 8 | p67lDj2xZ2e0jn3jGPKZJLyuzwXim2qJ/w4/6BF5R45VeYzb2xTc6mwJ2udrYpAu 9 | VCJqozcsyKrclskSqbfgKlosS+OYTFY9ZTh8b7pSEg4Chg9Pwm/cIPS3qhujkHM+ 10 | a/9cn3HS41w0EIdIHeTKk45PaxkCAwEAAaNQME4wHQYDVR0OBBYEFFcvwrY8Z6hZ 11 | Su6CJlX0vBRpxCsXMB8GA1UdIwQYMBaAFFcvwrY8Z6hZSu6CJlX0vBRpxCsXMAwG 12 | A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQENBQADggEBAEUrKhh/93QH3JS8GBvydhF0 13 | GeIKeQgRtEnf2+sR0G7XBBcXlr/dbAA5ns16QPPF3ntROVumlDOsJnX+HiuZ83kI 14 | z0ZNIXxweIGjSFdkxGw7meCVKA9BOP25sQzUSSSFVG7J/0o5tHOh4LFKKtOuGxqG 15 | byYW5Oyw4XGMVkr/SDP0R3g39pzkqTVca0foqPq37KMX7u91ApZDOa8rsyBaFS2t 16 | /6sd/5Ab2nWntB/o48x7VNehaxjDOz7HwWyLYgXxxdKqifTdJV4v7TtFaS/8684r 17 | vhAPPwMpao9HpAEsu1nASK0JuyT9ZPI/Gc6Y/33aBKF39U5omdtWsUaLIWVkDM4= 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /pkg/httphelper/testdata/ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7DoRvfEhjP/ES 3 | ouLcALeQSmruzTVJt0JrQSNZDdvYSShuHTAsa/X8TnJ+8xNgu3AwA0ZIyC0PVJGu 4 | /wtwjAUMJZDQCKg2uKEKv8FtdqcAqc4Tm9fKOu6fNSKHaZxn+WyMATE++Ttx2FsH 5 | VjzFmjCqovEkT+PhlrOTNv4/jDAe7XWgv8Up/c7fo+ehyqeu5Q49sWdntI594xjy 6 | mSS8rs8F4ptqif8OP+gReUeOVXmM29sU3OpsCdrna2KQLlQiaqM3LMiq3JbJEqm3 7 | 4CpaLEvjmExWPWU4fG+6UhIOAoYPT8Jv3CD0t6obo5BzPmv/XJ9x0uNcNBCHSB3k 8 | ypOOT2sZAgMBAAECggEBAJeULQd2i+Y5Y235pqImxplbZIm8qojgwybMswswKs16 9 | gxOv/WCR39Sj8S4kZbiGS2Ps02CZLcJ1glRvgmKiZFiyfEXILh+hv4ZJW0IL20qz 10 | TzYenF/ZH5LN6PwYPdEXkrllIfXo2x3m9+TbIgXya6tqvMPzJTOh/kS2VJNEU55K 11 | 415GsR5jmnlhpJupzUNjOrovlYt7CLGZd6V2GIHaccKVfgO6ciGv42S3QBjoYP9u 12 | Ri08UBcKtw/HEnsmWNt/uD/OJ1OFpJuSXdSHOFL49W4eMZa8yaMDIy5Hj1TVfOJl 13 | kFSSCFDfmCb/pc9RhFE0APebRxhJmpkwANpRYpsyfDECgYEA9jTDsjaa5pvffZ43 14 | l23r8sbXkClzcUfftHKRRpOZnodTC5tabYhZphpYStvnNLEYpxK6ipU0xDM/Agq/ 15 | CrN0z8x5mc839O6/qZqFHxWQDiH/bHr4L3q3ynrebfIEkdgK6jbr/csLACh0H2dK 16 | 7i6T1wwrn1qJKPG+gfBTXCHjVzUCgYEAwn9n70Yt1a/OvVWGa3cvtn4zXOAlh9Yg 17 | 9wNwCIDtGrhhhgSVqV1IPOalBTMTqMhZZp2ovPuwxpNnOo8erdvXikYCbkNUzgp5 18 | 08lIJMqZLuFDujCXMwOM18xIWbQlUbWO01L9qMbTnO/JsTsx4mfHXCVd2MIdu7gP 19 | Cgw9MWoX7NUCgYAkTDclyQMhSI20eWT8wEnu6v3Q1Sud4djLQ7DDVPNq+cx2g5rb 20 | VyTQZkXqE22MySc3Sn2R/Nlgq6V4aZksvLRWBnFPCcvYInLDUHKb2JP6YWzE04RP 21 | i6oZAfBVCT8/OTiyuxIjwpGGnnAwSQw0/UzygWrU/YYHMUzC32mKxbw8mQKBgQCh 22 | C4+KvwhKrHS5ruxLZXfbWqm62FobHIFVJsKIOACbpFoT9w3ZG8UpsCypnn5DvgjQ 23 | f/Ds8laQRhMumLzlZmgVNRzkIdpBdMklRL/4vsyR1bIXpA4+Dk17jcnGhPR1sKif 24 | cFNaga9Mffv6RTJr7lRThxkq1qh5+9BwGGw+00MWNQKBgBv7UdZaEktIAxPJfznq 25 | VTTEE/+htEIVgMESEnZZvHBXI+OiesB2X8pEZBBrz3q19gpc2hhJwrpw1qUmiTzW 26 | Ks1pIImAwojyU0yFGwKqtblUMeKu8pxgieYYpGbK0VgV28ABWPv7o06RulA+Y4nR 27 | 1+P2ZIyHhkq4RSZqZKNYVAUN 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /pkg/httphelper/testdata/client.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICqTCCAZECAmDLMA0GCSqGSIb3DQEBDQUAMBMxETAPBgNVBAMMCE15Um9vdENB 3 | MCAXDTE5MTEwNzE4NTMxOVoYDzIxMTkxMDE0MTg1MzE5WjAfMR0wGwYDVQQDDBRT 4 | b21lRmFuY3lQYW50c0NsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC 5 | ggEBAKwDjadcAyfe5sEcI7LB/9pZy/Y8BCbSc6usdk/FEe0RPA1csOq/VjwMtAWY 6 | K6QcxKj+S937wjpOjNEPNCQFaX+nFW1i3Hu9Tfd12xmfcvUXZ44UI9mnBBy5U0R5 7 | cm/kBGOJXcXxR/N6Q0uyfWJLJU/IWEkHmGZKhkjLLN1ZuCCtMTh+8TCKSMaibJT5 8 | kL2o6NznHT8g9/Yzha12mmOHqAMfeLJYw54BoG7+7yTkz6HWantho9C0JsCGM/Kb 9 | pxoE5WhODZyijx2jBLMB8zeqD+2AKXfLICp061C4G0dJoGwUUt68NGEgOB4wxNnf 10 | t+9LNZ2GigvrACOricf2sSfoXCcCAwEAATANBgkqhkiG9w0BAQ0FAAOCAQEAgDGy 11 | o9Ov0LfQc28n5mptOfL8nIlgDKqfiVZrY5IoGCQcDv6BD6DVCaKDsYG3zJw8fF+r 12 | LVJXQSFi2CYbXvwSSukPnBuqQFB5YnFw/sOwdaUW5ZUtrRqYz7J9AX6bCK3Cl58a 13 | dAo6G1Vld6aGuuxl9LUzfsh70IrFlWQmgVfNXa2zcFli0Y2kHn/p4TJSpTouYEV8 14 | 2EBmHQHDSBJjO3EIMcR8Muv0YlK/rKFWqq8D5IRUmuGvsiHTvmuUzyRw3kXXP8uk 15 | jXp+yy5G8coGmc5TVTkZtqXqTQz+iu44KjhfcBQDmWUl/P6Wy7ll+33yqT92sMWQ 16 | 3o/v5stmeEgMo2o7bg== 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /pkg/httphelper/testdata/client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCsA42nXAMn3ubB 3 | HCOywf/aWcv2PAQm0nOrrHZPxRHtETwNXLDqv1Y8DLQFmCukHMSo/kvd+8I6TozR 4 | DzQkBWl/pxVtYtx7vU33ddsZn3L1F2eOFCPZpwQcuVNEeXJv5ARjiV3F8UfzekNL 5 | sn1iSyVPyFhJB5hmSoZIyyzdWbggrTE4fvEwikjGomyU+ZC9qOjc5x0/IPf2M4Wt 6 | dppjh6gDH3iyWMOeAaBu/u8k5M+h1mp7YaPQtCbAhjPym6caBOVoTg2coo8dowSz 7 | AfM3qg/tgCl3yyAqdOtQuBtHSaBsFFLevDRhIDgeMMTZ37fvSzWdhooL6wAjq4nH 8 | 9rEn6FwnAgMBAAECggEAPTyKmlD8Yp5M4eSFpObBkdcz8DYPeE6llTExcVaD+jSP 9 | f2ZHKVrydTBEilVQ+/yt2keldKJi0+UQ5oAWHNi8ZRBzZVyzh22uKvGPDYEhKLWr 10 | TP5IgPyfTyZ+yTq/DaxMD69gbc5mwfv9px4k2vBLmSqGm4ETtR7EzXdfQnHlReQs 11 | eckThLq2JRh6pztoms1mWkGWtuhp4FvGceIAFxIw9IY/ZiNXbt4qm8GRZ9LwAWt5 12 | 3XdjLi2HdnweUMdLFhFEEZerJS32ya0WR3Q7OUBqGh+Z0cfSlL5ZIqiNL1c+4plp 13 | LNNHCKyJ5wtxFUK3wAzAdmM6SuZEHaYb7zY+vZCKWQKBgQDhsZgCROWKocCT3kcP 14 | xIKYgtTEipWf7NJwWaIHLmfTezULLKPFSoLA5jfzyKq4RByHEuY2XJp3HI7FLRDs 15 | 1X7r2Uz+ePhpqyWutzlbZsy5G+2tuOxjTAYA9qCsjLuZZ74Hbrqy14gyRj+CuI/5 16 | JduiSOEVpb+EFbNxYJv+3IfOSwKBgQDDHKvG7YGe/sSNemytKxMZaorFMjYUKcCD 17 | dmORvIWwGCLqTDEej6bAykU1Qgru6A/8kZq5nlvVGb0/YeeZvbuj1PImfZKDBl4h 18 | aIE1laONzpoWhRTqh8MWRl3KQ0G7oywQW93H8A9ai4al2glB9Hm9zcOyzzb2MNC9 19 | z5/NTMdQFQKBgQDUwWmemfwY16qGuj8a6hCCXLLeJBYwkDtAlf5b7q8JeVfjlM09 20 | qqPf3CZatYvZ8LtDydki3eDu8AjWb0lJOWlQQ6SFLtxeIGyBa0+yjhHnXiCMZ4rP 21 | gFcYiWWlw3UFg/prX0K4XN2TJw2v2PQ/1iRZs4Ibugf0J9DkzEHB23paSQKBgArf 22 | WiMnsQVvJPzNSakMsW/FJB6BAcp12Sh6PGoumzSI48kynboaPyyXGOwy1fEiNWHZ 23 | q0mUrYFegdE6X3GNxRsIDsZeUP/EJxKthCW8RPTuAmAm4ld/YTuoiClxPgR6v0Xa 24 | GK2/jtt40vQDBmkKeo49HR6ltWZaqgcpvrnuAV1RAoGBALk9F3Y9faeVLF/mK/5E 25 | /hxmzqOEwDmNCFZRYwQqO+FtkmiRvmZefj5+NLR/US2faH/J2MHCZrJgu6YGBbzV 26 | v5HER1UFkHY24i7RNYW/sxH9iyBq4/uaF/FYJL4i/0z009ZxJ7BcpjT4nJowu8UM 27 | yYG7hNCPusvYwoBkpRcesQRe 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /pkg/httphelper/testdata/evil_ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC+zCCAeOgAwIBAgIJAJ+uwNjoCRYxMA0GCSqGSIb3DQEBDQUAMBMxETAPBgNV 3 | BAMMCE15RXZpbENBMCAXDTE5MTEwNzE4NTMxNVoYDzIxMTkxMDE0MTg1MzE1WjAT 4 | MREwDwYDVQQDDAhNeUV2aWxDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC 5 | ggEBAL3N2PNcfQ2JUREoio/pxYzTbMf+nx1UE1EPjFs5Z8orw9Ref1X+6dY2nBQ0 6 | qyRMsj7VynWAi17LGz5I68GlQFNAUioY6hkUIgFeYuPKPTPHZKnJJP931uTeXmcb 7 | A5pybFf/E03aRQ2aq8e+7VoKXLvlu+oUOuT1zFQ6U+NFoV8kO9vKT2Zc2i6lo3N/ 8 | W5MVJHWMN5Z9K2nk9hRoaKkIRkY1AUsCNkM1OEI3CGI428LCUVCTu1zg+5+T4wVL 9 | Iq8eK/7HwwL3hbrVYPThiAv8uyz2lcHiHWG8F+TgUC6CZM6BT7iqH8mBCEZzNjKS 10 | R3tKq/LJXCYrMsZssnwtrgK4Pp0CAwEAAaNQME4wHQYDVR0OBBYEFG4zyjcERUi/ 11 | yQ7Y2GkA6AiWYJGIMB8GA1UdIwQYMBaAFG4zyjcERUi/yQ7Y2GkA6AiWYJGIMAwG 12 | A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQENBQADggEBAGSfWVGKHhNm7FjPhA/9U+rT 13 | uP0Ecr9qTEY5EtMgfKkFHkazkC2ES3b/iK5aUjOLgPJqqHXvYqqG68UFynnYtVXz 14 | ppR+WVEV4E0Cf3BZCqrbyaplayAG6LO/ez/RXwzeFoOmi+Mat1M9oFzl+VSzyrd/ 15 | 74oWjRgb74Ljbz7SJ+21IQbiUbafoqdQd8GgEoyYE0dZ8La4Kl/HfxohUxMJlWts 16 | s2zeaGNzItLQHPpA8L+fDuTJYHgH36gYx1wJtdr2XLSGUDUqu1nQ8pkpFkYYRxLw 17 | Vl3wM46lYqyuG4jxBZYCa07pFzALMjZ3ycVgLH9/ZuVcmQYsQtSDHAR6IDzYhOU= 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /pkg/httphelper/testdata/evil_ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9zdjzXH0NiVER 3 | KIqP6cWM02zH/p8dVBNRD4xbOWfKK8PUXn9V/unWNpwUNKskTLI+1cp1gIteyxs+ 4 | SOvBpUBTQFIqGOoZFCIBXmLjyj0zx2SpyST/d9bk3l5nGwOacmxX/xNN2kUNmqvH 5 | vu1aCly75bvqFDrk9cxUOlPjRaFfJDvbyk9mXNoupaNzf1uTFSR1jDeWfStp5PYU 6 | aGipCEZGNQFLAjZDNThCNwhiONvCwlFQk7tc4Pufk+MFSyKvHiv+x8MC94W61WD0 7 | 4YgL/Lss9pXB4h1hvBfk4FAugmTOgU+4qh/JgQhGczYykkd7SqvyyVwmKzLGbLJ8 8 | La4CuD6dAgMBAAECggEAcfl8P5bYWRqOHZmUqxqb0BbdibLyZTApcVG+3MC5/IMP 9 | UyVznXY3gLTGQLPn2SJdHrJOowSPrFqWf25Wc7AB0nwbWsAfQvP9/4hoJZU57y/a 10 | 2MG6f9W8qy6EzbFBFquDN8wqEWPyd1rbsFSMPrdePE6V6tg/DWI0Upe77AvR/Ui/ 11 | zCizx9dO+iaJtYi6Uzlpr+FteH3Cijaglai9vRvY0qRM6fFMn024rsaKtZvmcBdx 12 | DT11RG2e0MnApQJTKr48srII0p45382+N2uikbL6K5We8fzGMjATbe1aeLEkd7SJ 13 | uW0mmfj1J+Am1+dodmUe/g7k68XjsdZxYVZWoZNKAQKBgQD7Wez2yFxCiQ000wWs 14 | eIKnLXhgTxhgrjQ24C35/QUxOulE10HKNT29Q3ysrxeHlqMUVkzmr9O91EgXiDnH 15 | 1RpGtxtmqhQLaQDq2wfxXOJSNJo3tJeTx8m422vr/wVbTxk3NAJkyCVjeSn0G+bZ 16 | vGDdAa0jfBuiKdLcSMdjARLt3QKBgQDBUIOW+/D2PzWBD8zOeLO8v94MX6mfKZee 17 | gfsnsJF6dGxa+pL2CTCU+RYshinMTst1aTyTU7FHHqXuwQa8zD3LVO0C2K4bbHbQ 18 | fNhJpHa+YL4H5sh2ESFxvtYo5esy/pLtxGYoylP8iWQRPDcXAjRO6iaLhXiZV+Fv 19 | vAvwHktnwQKBgQDX8LoUiq44u2YNK/6D3kThO79ffpSC+ycAvjjBvQ7o7KPb8NMk 20 | 1fjk0UYbVZHxewlAP6RxzD0tqWMGVJLPi9W3SzjPSu9NnjibjPGV+ya1WVvk39IZ 21 | tFsp5dkiN0Zy29HeC2DDFPCKNV5FynLaPW06cmY9RjK3bxcpCZ3DAPkyQQKBgALx 22 | nO9hqsu1LrVmbjH+uI35RgJeOpEH6x0o0ZBLKgv5VeUUx8QjY7ABEwteh6hq0sJY 23 | 9ekwbxSsLM6z9cxON+quwmU2s4ALaMvH+us0K/K+OmaYZxkVLbMzusMorSo7ojUo 24 | tn2MhzbjSLjSd+xLxkwlWKzrPWjoY7B15qCjdXaBAoGAW/lNZYFWLil6rEpQ2SWt 25 | BOAxB8/qGLrX5l2jFYZ7QO1UKRNjAqjCtxy/Tg0OabeUmKWz/5hD27ApUaX6zfmv 26 | O6gj0aWefcpGmg8OCmk8LWKTjDNLkwVE6z3GVyv2oxwoeVCBmPuiAA92TEvidrOq 27 | k0SRR/bmjG/tuYJrpjyiPis= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /pkg/httphelper/testdata/gencerts.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 6 | CERTS_DIR="$SCRIPT_DIR" 7 | 8 | function openssl() { 9 | # Ensure the certificates directory exists 10 | mkdir -p "$CERTS_DIR" 11 | 12 | # This just runs the openssl command but in a container with all the 13 | # extensions and whatnot we need. 14 | docker run -i -v "$CERTS_DIR:/export" -w /export frapsoft/openssl "$@" 15 | } 16 | 17 | function create_certificates() { 18 | openssl req -extensions v3_ca -new -x509 -days 36500 -nodes \ 19 | -subj "/CN=MyRootCA" -newkey rsa:2048 -sha512 -out ca.crt \ 20 | -keyout ca.key \ 21 | || return $? 22 | 23 | openssl req -extensions v3_ca -new -x509 -days 36500 -nodes \ 24 | -subj "/CN=MyEvilCA" -newkey rsa:2048 -sha512 -out evil_ca.crt \ 25 | -keyout evil_ca.key \ 26 | || return $? 27 | 28 | openssl req -new -keyout server.key -nodes -newkey rsa:2048 \ 29 | -subj "/CN=localhost" \ 30 | | openssl x509 -req -CAkey ca.key -CA ca.crt -days 36500 \ 31 | -set_serial $RANDOM -sha512 -out server.crt \ 32 | || return $? 33 | 34 | openssl req -new -keyout client.key -nodes -newkey rsa:2048 \ 35 | -subj "/CN=SomeFancyPantsClient" \ 36 | | openssl x509 -req -CAkey ca.key -CA ca.crt -days 36500 \ 37 | -set_serial $RANDOM -sha512 -out client.crt \ 38 | || return $? 39 | 40 | openssl rsa -in server.key -out server.rsa.key 41 | 42 | openssl pkcs8 -topk8 -in server.key -out server.encrypted.key \ 43 | -passout pass:bob 44 | } 45 | 46 | create_certificates 47 | -------------------------------------------------------------------------------- /pkg/httphelper/testdata/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICnjCCAYYCAhDSMA0GCSqGSIb3DQEBDQUAMBMxETAPBgNVBAMMCE15Um9vdENB 3 | MCAXDTE5MTEwNzE4NTMxN1oYDzIxMTkxMDE0MTg1MzE3WjAUMRIwEAYDVQQDDAls 4 | b2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsfAiB7bcx 5 | vItTNhJfMvE9ghf2f1iU9g4JR6Hs4BNBBONj0ZrcWCuBziijFxlAI6vMnmW/Q4i9 6 | vNQp0tzfX4njW6pmrTlyxa5hJFPhPuYLezWfAAXbs7duJfqviifEOskl78IjDJpP 7 | K5y8sfX7kFVi7D8m/vmQGrrgFOlXMVdw2JZYUdNIjTCaX9aFHX9nbbXt6uLnCHij 8 | agbcIfGSZfG/NFIdilaZSh92jg2uSHEyOsxpFrF+FKNSLwWeDEzkQ6wQ2arhJTqq 9 | sgcAcF/i4k2fRMukogVGZ96LP1F9UvqjlaM3IqDZD69KxS97Fuitk7qztg3nWE4A 10 | AHNK1Dafzet1AgMBAAEwDQYJKoZIhvcNAQENBQADggEBAGuBLc5YB5nOL2x9U673 11 | +UpI/qJ+dUXQI5d+eb8IzuyEEK0aqN29TdUds0t6pUeF8TSULAShpYc01vXXQSez 12 | ktSu7s9aHs9wbUx5/9V68n/C/ysFcTfWYcpmLj8WGU4sHols+KKqbmb6GPo6+sYT 13 | d2UFFwWYVudWyXTpyBrnaXQA2K7FxIDHhe41r+GqS4dcm1TCOR8SbK94sq7rurNr 14 | kErNv59us4jfqkuTFFftgkpOMIh/6I6ruzn0Bbx10zvJziL5YDg6zFvMlZPz0bd0 15 | LDFzoWk8enPUi+XWwILQ8wyK+EjifMJMHMt5SYHFN+uuAsXlKsipUIaZcVqhPIJL 16 | c80= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /pkg/httphelper/testdata/server.encrypted.key: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIE6TAbBgkqhkiG9w0BBQMwDgQIBEFLyMd+wjsCAggABIIEyJ5lMwuiRWneJ+D5 3 | v1rZ3bl3IgXAbt6PruZJSYaqTA3kJ8wGPk7SAqVbJjRyMEUHXNOjOOvvCZDB5LIk 4 | KE8MjC4gvLGcadow4RBbKYQf7FCud+Z/2KF6IldPNErciGZXqQCExlckVn8Lel0J 5 | zarI7lk9hjsVbYjRINZcQWXl0tRa+MeVcFQW+zIfBEImT/R66C2R03UtsHJjhgn9 6 | YVjrkDHdzCR78Sbdko1sLwSl4whN+EFwtf6FDoZvIXRmerh9E8Bus7OYEI6/8RAL 7 | SiRPx2NFe3Bd5WjYSbfhnUrG46SblUNlBd6gcCq7awPm5S1btc6Bl24LM+d8GkzE 8 | QcU0wvclOXjWNbpL9lHM8cdqIF/n6yvbIDnSbn/PIGCmcst9LEs/z9jo/0IcKtLA 9 | WvE5RWzJ8EjlKHsBW9Etcni7rRnz7KLrchkhCOE4PoqztZWfmGSBZK5PGYCYqPUv 10 | tdppQmoYxlje+jW+FN+5iOmfMdas1thYW5qa6aebG5b8MN0p+raKA8pP0PahXfk3 11 | LuNBDgcgnTUn0CJ+sQyaz0mZVYgE22bOcl1y7ZoitZoy8wWtxR8fntc63A7zuFKM 12 | ES9XCnlYd3C9kTZdN0W1uGi/S8arrkJ9ugP6LVe/Jpa5R0it7HYAIjRuFR1/ROrg 13 | YbsEy3iQGZXDyoC9SrFvWEIqaeRq1p394KA8a5Cuh9VTUzL7oPa8e9km2crfcrG1 14 | B9TLG9LQZ+kUKRFRcquSJJfhEmuX+Qbr3jV92BMe70xbXP+QbDMGgjx97AzKc0or 15 | KSV1jr/pccmjLMU0n/Oz/aUWPPQGu+aILSKnaZpzBqauVPds3/qr3FBRDJM14h2J 16 | ke+V8/h5d5PFyvQFp7R86LwbxOZbZndnike1mXa4i+Bkluv8mwL8c24dISiNmwI7 17 | YEN6hrDUxByLAmvXyRoVMCdxV5dfbHzSOVUYl8m94qJYahCK/mPeawUYH5BroNEx 18 | DLC7OEsVQaghdhxZvBLnsRfhpnwDRY8BbSlZpxVu3cvG0gsXMpWTdKsidfbSv5UW 19 | vslO2JEqb2c1wTZ8MHkAId7kp6X/jm4yABxuY1swG50KNAq1oL5b1lBfgaSh/s+h 20 | DVzrZ5BOvHfjndhPDFbfUZEdToouqp43zw5Tig/lbmLl13DAyOZyanzHyY0PoURR 21 | sLfHCXB+NpNGA/35uIXGDWS3g0XVAt4bz+QSe+6TJJZVrW3tapqRuGWdqVBsV7vX 22 | luIm1Rj+tZyYKQg6Tx1vjkBFAtohojO1DXrbh+MOZ8OmfEhho7xQkm6naeOA6nwL 23 | y9hc3X7tXr6J0r846ljLkRzWQNiyJgJSIjqbQ+P+CaHozMm/k5ED2BVBy67aUUt/ 24 | vUfACG0VuJ8LYQbZDGhZIBP+YRspKI1hSv2fNYczVtVvcDYqFmBKfFW2V9qPpDix 25 | Qmzl9Cd4NMLA4r0zvS78B7XsJ1v6oj2kSMGCtgWQ0v9F7Sy1B5qIm5CmMqHe3sI3 26 | WpjXu1ho8yUt/T91ik8qMCi8K7GNix1vj0Q03nkoIEA+suDu7XamfhzVvi9MoyVb 27 | csZHzDGFx15RkpY3c7R5cfUvZDU27tJ+shRsVSkUro464wrW/NZBfKzMFsjmH3WU 28 | I1p7lip8TUGRJpN4yQ== 29 | -----END ENCRYPTED PRIVATE KEY----- 30 | -------------------------------------------------------------------------------- /pkg/httphelper/testdata/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCsfAiB7bcxvItT 3 | NhJfMvE9ghf2f1iU9g4JR6Hs4BNBBONj0ZrcWCuBziijFxlAI6vMnmW/Q4i9vNQp 4 | 0tzfX4njW6pmrTlyxa5hJFPhPuYLezWfAAXbs7duJfqviifEOskl78IjDJpPK5y8 5 | sfX7kFVi7D8m/vmQGrrgFOlXMVdw2JZYUdNIjTCaX9aFHX9nbbXt6uLnCHijagbc 6 | IfGSZfG/NFIdilaZSh92jg2uSHEyOsxpFrF+FKNSLwWeDEzkQ6wQ2arhJTqqsgcA 7 | cF/i4k2fRMukogVGZ96LP1F9UvqjlaM3IqDZD69KxS97Fuitk7qztg3nWE4AAHNK 8 | 1Dafzet1AgMBAAECggEAc1whdITA2Yr4xBaOAw3XOwQfcsWJQVev25UFP6A+QGY8 9 | jy5JHMX7kz2HAE0ankM9TAVEl79bXUtFuxNElkEXv/A276U7nv+HuYDKeQPQaC1n 10 | l4g0YtS4Aft0xqLoJd4LWkwY08hCDGFm2u1LT40hDqBjPHmcAD1gby6NQbvGd7nK 11 | jadXdeZUFs/gPp5Ow6oBfTvK+SeqhQrRWlbYXJ+zaSUyVkiOJWx7E2DiiD8G2hfS 12 | D+wgJMGoeb3mg3Ds3usjNOL4waPlyQDVewOvAu3SEPlYjCSPyuZUtts8FXTKuhPU 13 | KEM58JFo212bVvEhk048nfKts/k40OOOGUIc1c0/AQKBgQDePQaok/25Z27AQC9a 14 | gBZewewe9VGLRW9pYAVhD0Aij0fMl6tinFoICUM5Yu65DVtGTszvR6P60aEQNBMH 15 | gcsNJb8WYmGX8ldYGfUEQdfXqQYwKV1Ktvn4vLgYQ1rFLiYoxRTRzW09Nh1oRbtR 16 | jAOd+L6rMkXk6ogGCqC5hkH2XQKBgQDGsA0iZ5KJq+7xdavzpSz6hdxsEw9aoG+T 17 | CQeR2NbAmrspLSAbY1dZKw+8XXhgHBjIc7po0yQv+0LHSih11pR0rgvgNSWecIw4 18 | JwwksJ5QB3c6T4FOfbteOwV0SAdAuc0HnwGB7c4fxaeBYF1E9vOuZBBogkoTzO3x 19 | c4CwB3/H+QKBgQDcyJvY1k125/7rF9jze9S9hsJhby33wp+QfEhbyJ7atqWJ6BPn 20 | /5Sh7zHNzS+EwHQxQQ/vl6idAa2VP2a4SoXDJgDU6CA0qBmF+SOlexRHuC/hoPaB 21 | x45HQpVR5XhD9DkMv96TIBaqfRxx/vS9avAc/IXP5j3x0d4Ywm4yYeMeMQKBgQC7 22 | az44gfKcou6WHiXBgsHW34Z4+9Gz7zrQO+hED4Mj09FQmhx7OU4f8pq5WIJARsCp 23 | 9WCVmPW9vQnU64MXBP6swbC6IegGeKwMG+k8gs4TN7ej7XNQExI3ZP1UHs2YpKte 24 | 0QKfCS8ykUPcqoXQlBJxIjrIGn6+BsU8yXNOmQRUIQKBgHBOVuSCmoEpYPm7vjL3 25 | STIOlvpxWJHNnVeKm1sFAFtdmb2TYF0bzF5CV12LqBIQ1dWGvLox+og2lOw9uJDB 26 | UPFfLB6E3UqgjA0lEhr+jTYZhHZ69AkUmDCZvj7xqjQO4hdJeHBWeGGMoZJjF5Sm 27 | 4Ccn7qA3+wIgzlnk5/2a6FCL 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /pkg/httphelper/testdata/server.rsa.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEArHwIge23MbyLUzYSXzLxPYIX9n9YlPYOCUeh7OATQQTjY9Ga 3 | 3Fgrgc4ooxcZQCOrzJ5lv0OIvbzUKdLc31+J41uqZq05csWuYSRT4T7mC3s1nwAF 4 | 27O3biX6r4onxDrJJe/CIwyaTyucvLH1+5BVYuw/Jv75kBq64BTpVzFXcNiWWFHT 5 | SI0wml/WhR1/Z2217eri5wh4o2oG3CHxkmXxvzRSHYpWmUofdo4NrkhxMjrMaRax 6 | fhSjUi8FngxM5EOsENmq4SU6qrIHAHBf4uJNn0TLpKIFRmfeiz9RfVL6o5WjNyKg 7 | 2Q+vSsUvexborZO6s7YN51hOAABzStQ2n83rdQIDAQABAoIBAHNcIXSEwNmK+MQW 8 | jgMN1zsEH3LFiUFXr9uVBT+gPkBmPI8uSRzF+5M9hwBNGp5DPUwFRJe/W11LRbsT 9 | RJZBF7/wNu+lO57/h7mAynkD0GgtZ5eINGLUuAH7dMai6CXeC1pMGNPIQgxhZtrt 10 | S0+NIQ6gYzx5nAA9YG8ujUG7xne5yo2nV3XmVBbP4D6eTsOqAX07yvknqoUK0VpW 11 | 2Fyfs2klMlZIjiVsexNg4og/BtoX0g/sICTBqHm95oNw7N7rIzTi+MGj5ckA1XsD 12 | rwLt0hD5WIwkj8rmVLbbPBV0yroT1ChDOfCRaNtdm1bxIZNOPJ3yrbP5ONDjjhlC 13 | HNXNPwECgYEA3j0GqJP9uWduwEAvWoAWXsHsHvVRi0VvaWAFYQ9AIo9HzJerYpxa 14 | CAlDOWLuuQ1bRk7M70ej+tGhEDQTB4HLDSW/FmJhl/JXWBn1BEHX16kGMCldSrb5 15 | +Ly4GENaxS4mKMUU0c1tPTYdaEW7UYwDnfi+qzJF5OqIBgqguYZB9l0CgYEAxrAN 16 | ImeSiavu8XWr86Us+oXcbBMPWqBvkwkHkdjWwJq7KS0gG2NXWSsPvF14YBwYyHO6 17 | aNMkL/tCx0ooddaUdK4L4DUlnnCMOCcMJLCeUAd3Ok+BTn27XjsFdEgHQLnNB58B 18 | ge3OH8WngWBdRPbzrmQQaIJKE8zt8XOAsAd/x/kCgYEA3Mib2NZNduf+6xfY83vU 19 | vYbCYW8t98KfkHxIW8ie2raliegT5/+Uoe8xzc0vhMB0MUEP75eonQGtlT9muEqF 20 | wyYA1OggNKgZhfkjpXsUR7gv4aD2gceOR0KVUeV4Q/Q5DL/ekyAWqn0ccf70vWrw 21 | HPyFz+Y98dHeGMJuMmHjHjECgYEAu2s+OIHynKLulh4lwYLB1t+GePvRs+860Dvo 22 | RA+DI9PRUJocezlOH/KauViCQEbAqfVglZj1vb0J1OuDFwT+rMGwuiHoBnisDBvp 23 | PILOEze3o+1zUBMSN2T9VB7NmKSrXtECnwkvMpFD3KqF0JQScSI6yBp+vgbFPMlz 24 | TpkEVCECgYBwTlbkgpqBKWD5u74y90kyDpb6cViRzZ1XiptbBQBbXZm9k2BdG8xe 25 | Qlddi6gSENXVhry6MfqINpTsPbiQwVDxXywehN1KoIwNJRIa/o02GYR2evQJFJgw 26 | mb4+8ao0DuIXSXhwVnhhjKGSYxeUpuAnJ+6gN/sCIM5Z5Of9muhQiw== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /pkg/mockhelper/http.go: -------------------------------------------------------------------------------- 1 | package mockhelper 2 | 3 | import ( 4 | "net/http" 5 | 6 | client "sigs.k8s.io/controller-runtime/pkg/client" 7 | ) 8 | 9 | type Client interface { 10 | client.Client 11 | } 12 | 13 | type HttpClient interface { 14 | http.Client 15 | } 16 | -------------------------------------------------------------------------------- /pkg/mocks/HttpClient.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.26.1. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | http "net/http" 7 | 8 | mock "github.com/stretchr/testify/mock" 9 | ) 10 | 11 | // HttpClient is an autogenerated mock type for the HttpClient type 12 | type HttpClient struct { 13 | mock.Mock 14 | } 15 | 16 | // Do provides a mock function with given fields: req 17 | func (_m *HttpClient) Do(req *http.Request) (*http.Response, error) { 18 | ret := _m.Called(req) 19 | 20 | var r0 *http.Response 21 | var r1 error 22 | if rf, ok := ret.Get(0).(func(*http.Request) (*http.Response, error)); ok { 23 | return rf(req) 24 | } 25 | if rf, ok := ret.Get(0).(func(*http.Request) *http.Response); ok { 26 | r0 = rf(req) 27 | } else { 28 | if ret.Get(0) != nil { 29 | r0 = ret.Get(0).(*http.Response) 30 | } 31 | } 32 | 33 | if rf, ok := ret.Get(1).(func(*http.Request) error); ok { 34 | r1 = rf(req) 35 | } else { 36 | r1 = ret.Error(1) 37 | } 38 | 39 | return r0, r1 40 | } 41 | 42 | type mockConstructorTestingTNewHttpClient interface { 43 | mock.TestingT 44 | Cleanup(func()) 45 | } 46 | 47 | // NewHttpClient creates a new instance of HttpClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 48 | func NewHttpClient(t mockConstructorTestingTNewHttpClient) *HttpClient { 49 | mock := &HttpClient{} 50 | mock.Mock.Test(t) 51 | 52 | t.Cleanup(func() { mock.AssertExpectations(t) }) 53 | 54 | return mock 55 | } 56 | -------------------------------------------------------------------------------- /pkg/mocks/helper.go: -------------------------------------------------------------------------------- 1 | package mocks 2 | 3 | import ( 4 | mock "github.com/stretchr/testify/mock" 5 | client "sigs.k8s.io/controller-runtime/pkg/client" 6 | ) 7 | 8 | // This file overwrites some mocked methods 9 | 10 | // Client is an autogenerated mock type for the Client type 11 | type Client struct { 12 | mock.Mock 13 | subResourceClient *SubResourceClient 14 | } 15 | 16 | // Status provides a mock function with given fields. Overrides normal mock functionality (can't be asserted) 17 | func (_m *Client) Status() client.SubResourceWriter { 18 | return _m.SubResource("status") 19 | } 20 | 21 | // SubResource provides a mock function with given fields: subResource. Overrides normal mock functionality (can't be asserted) 22 | func (_m *Client) SubResource(subResource string) client.SubResourceClient { 23 | return _m.subResourceClient 24 | } 25 | 26 | type mockConstructorTestingTNewClient interface { 27 | mock.TestingT 28 | Cleanup(func()) 29 | } 30 | 31 | // NewClient creates a new instance of Client. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 32 | func NewClient(t mockConstructorTestingTNewClient) *Client { 33 | subclient := NewSubResourceClient(t) 34 | mock := &Client{subResourceClient: subclient} 35 | mock.Mock.Test(t) 36 | 37 | t.Cleanup(func() { mock.AssertExpectations(t) }) 38 | 39 | return mock 40 | } 41 | -------------------------------------------------------------------------------- /pkg/oplabels/labels.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package oplabels 5 | 6 | import ( 7 | "fmt" 8 | 9 | api "github.com/k8ssandra/cass-operator/apis/cassandra/v1beta1" 10 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 | ) 12 | 13 | const ( 14 | ManagedByLabel = "app.kubernetes.io/managed-by" 15 | ManagedByLabelValue = "cass-operator" 16 | NameLabel = "app.kubernetes.io/name" 17 | NameLabelValue = "cassandra" 18 | InstanceLabel = "app.kubernetes.io/instance" 19 | VersionLabel = "app.kubernetes.io/version" 20 | CreatedByLabel = "app.kubernetes.io/created-by" 21 | CreatedByLabelValue = ManagedByLabelValue 22 | ) 23 | 24 | func AddOperatorMetadata(obj *metav1.ObjectMeta, dc *api.CassandraDatacenter) { 25 | if obj.Labels == nil { 26 | obj.Labels = make(map[string]string) 27 | } 28 | if obj.Annotations == nil { 29 | obj.Annotations = make(map[string]string) 30 | } 31 | 32 | AddOperatorLabels(obj.Labels, dc) 33 | AddOperatorAnnotations(obj.Annotations, dc) 34 | } 35 | 36 | func AddOperatorLabels(m map[string]string, dc *api.CassandraDatacenter) { 37 | if m == nil { 38 | m = make(map[string]string) 39 | } 40 | m[ManagedByLabel] = ManagedByLabelValue 41 | m[NameLabel] = NameLabelValue 42 | m[VersionLabel] = dc.Spec.ServerVersion 43 | m[InstanceLabel] = fmt.Sprintf("cassandra-%s", api.CleanLabelValue(dc.Spec.ClusterName)) 44 | m[CreatedByLabel] = CreatedByLabelValue 45 | 46 | if len(dc.Spec.AdditionalLabels) != 0 { 47 | for key, value := range dc.Spec.AdditionalLabels { 48 | m[key] = api.CleanLabelValue(value) 49 | } 50 | } 51 | 52 | } 53 | 54 | func AddOperatorAnnotations(m map[string]string, dc *api.CassandraDatacenter) { 55 | if m == nil { 56 | m = make(map[string]string) 57 | } 58 | if len(dc.Spec.AdditionalAnnotations) != 0 { 59 | for key, value := range dc.Spec.AdditionalAnnotations { 60 | m[key] = value 61 | } 62 | } 63 | } 64 | 65 | func HasManagedByCassandraOperatorLabel(m map[string]string) bool { 66 | v, ok := m[ManagedByLabel] 67 | return ok && v == ManagedByLabelValue 68 | } 69 | -------------------------------------------------------------------------------- /pkg/reconciliation/constructor_test.go: -------------------------------------------------------------------------------- 1 | package reconciliation 2 | 3 | import ( 4 | "testing" 5 | 6 | api "github.com/k8ssandra/cass-operator/apis/cassandra/v1beta1" 7 | "github.com/stretchr/testify/assert" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | func TestPodDisruptionBudget(t *testing.T) { 12 | assert := assert.New(t) 13 | 14 | dc := &api.CassandraDatacenter{ 15 | ObjectMeta: metav1.ObjectMeta{ 16 | Name: "dc1", 17 | Namespace: "test", 18 | }, 19 | Spec: api.CassandraDatacenterSpec{ 20 | DatacenterName: "dc1-override", 21 | Size: 3, 22 | }, 23 | } 24 | 25 | // create a PodDisruptionBudget object 26 | pdb := newPodDisruptionBudgetForDatacenter(dc) 27 | assert.Equal("dc1-pdb", pdb.Name) 28 | assert.Equal("test", pdb.Namespace) 29 | assert.Equal("dc1", pdb.Spec.Selector.MatchLabels["cassandra.datastax.com/datacenter"]) 30 | assert.Equal(pdb.Spec.MinAvailable.IntVal, int32(dc.Spec.Size-1)) 31 | } 32 | -------------------------------------------------------------------------------- /pkg/reconciliation/defaults.go: -------------------------------------------------------------------------------- 1 | package reconciliation 2 | 3 | var ( 4 | // Provides reasonable defaults for the logger container. 5 | DefaultsLoggerContainer = buildResourceRequirements(100, 64, 0, 128) 6 | 7 | // Provides reasonable defaults for the configuration container. 8 | DefaultsConfigInitContainer = buildResourceRequirements(1000, 256, 1000, 384) 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/reconciliation/rackinformation.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package reconciliation 5 | 6 | // RackInformation contains an identifying name and a node count for a logical rack 7 | type RackInformation struct { 8 | RackName string 9 | NodeCount int 10 | SeedCount int 11 | } 12 | -------------------------------------------------------------------------------- /pkg/reconciliation/reconcile_fql.go: -------------------------------------------------------------------------------- 1 | package reconciliation 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/k8ssandra/cass-operator/internal/result" 7 | "github.com/k8ssandra/cass-operator/pkg/httphelper" 8 | ) 9 | 10 | // CheckFullQueryLogging sets FQL enabled or disabled. It calls the NodeMgmtClient which calls the Cassandra management API and returns a result.ReconcileResult. 11 | func (rc *ReconciliationContext) CheckFullQueryLogging() result.ReconcileResult { 12 | rc.ReqLogger.Info("reconcile_racks::CheckFullQueryLogging") 13 | dc := rc.GetDatacenter() 14 | if !dc.DeploymentSupportsFQL() { 15 | return result.Continue() 16 | } 17 | 18 | enableFQL, err := dc.FullQueryEnabled() 19 | if err != nil { 20 | return result.Error(err) 21 | } 22 | 23 | podList, err := rc.listPods(rc.Datacenter.GetClusterLabels()) 24 | if err != nil { 25 | rc.ReqLogger.Error(err, "error listing all pods in the cluster to progress full query logging reconciliation") 26 | return result.RequeueSoon(2) 27 | } 28 | for _, podPtr := range podList { 29 | features, err := rc.NodeMgmtClient.FeatureSet(podPtr) 30 | if err != nil { 31 | rc.ReqLogger.Error(err, "failed to verify featureset for FQL support") 32 | return result.RequeueSoon(2) 33 | } 34 | if !features.Supports(httphelper.FullQuerySupport) { 35 | if enableFQL { 36 | err := errors.New("FQL should be enabled but we cannot verify if FQL is supported by mgmt api") 37 | return result.Error(err) 38 | } 39 | // FQL support not available in mgmt API but user is not requesting it - continue. 40 | return result.Continue() 41 | } 42 | fqlEnabledForPod, err := rc.NodeMgmtClient.CallIsFullQueryLogEnabledEndpoint(podPtr) 43 | if err != nil { 44 | rc.ReqLogger.Error(err, "can't get whether query logging enabled for pod ", "podName", podPtr.Name) 45 | return result.RequeueSoon(2) 46 | } 47 | if fqlEnabledForPod != enableFQL { 48 | rc.ReqLogger.Info("Modifying full query logging on ", "podIP", podPtr.Status.PodIP, "podName", podPtr.Name, "fqlDesiredState", enableFQL) 49 | err := rc.NodeMgmtClient.CallSetFullQueryLog(podPtr, enableFQL) 50 | if err != nil { 51 | rc.ReqLogger.Error(err, "couldn't enable full query logging on ", "podIP", podPtr.Status.PodIP, "podName", podPtr.Name) 52 | return result.RequeueSoon(2) 53 | } 54 | } 55 | } 56 | return result.Continue() 57 | } 58 | -------------------------------------------------------------------------------- /pkg/reconciliation/reconcile_racks_helpers_test.go: -------------------------------------------------------------------------------- 1 | package reconciliation 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | corev1 "k8s.io/api/core/v1" 9 | ) 10 | 11 | func TestMapContains(t *testing.T) { 12 | labels := make(map[string]string) 13 | labels["key1"] = "val1" 14 | labels["key2"] = "val2" 15 | labels["key3"] = "val3" 16 | 17 | selectors := make(map[string]string) 18 | selectors["key1"] = "val1" 19 | selectors["key3"] = "val3" 20 | 21 | isMatch := mapContains(labels, selectors) 22 | 23 | if !isMatch { 24 | t.Fatalf("mapContains should have found match.") 25 | } 26 | } 27 | 28 | func TestMapContainsDoesntContain(t *testing.T) { 29 | labels := make(map[string]string) 30 | labels["key1"] = "val1" 31 | labels["key2"] = "val2" 32 | labels["key3"] = "val3" 33 | 34 | selectors := make(map[string]string) 35 | selectors["key1"] = "val4" 36 | selectors["key3"] = "val3" 37 | 38 | isMatch := mapContains(labels, selectors) 39 | 40 | if isMatch { 41 | t.Fatalf("mapContains should not have found match.") 42 | } 43 | } 44 | 45 | func TestPodPrtsFromPodList(t *testing.T) { 46 | pod1 := corev1.Pod{} 47 | pod1.Name = "pod1" 48 | 49 | pod2 := corev1.Pod{} 50 | pod2.Name = "pod2" 51 | 52 | pod3 := corev1.Pod{} 53 | pod3.Name = "pod3" 54 | podList := corev1.PodList{ 55 | Items: []corev1.Pod{pod1, pod2, pod3}, 56 | } 57 | 58 | prts := PodPtrsFromPodList(&podList) 59 | 60 | expectedNames := []string{"pod1", "pod2", "pod3"} 61 | var actualNames []string 62 | for _, p := range prts { 63 | actualNames = append(actualNames, p.Name) 64 | } 65 | assert.ElementsMatch(t, expectedNames, actualNames) 66 | 67 | } 68 | -------------------------------------------------------------------------------- /pkg/reconciliation/utils.go: -------------------------------------------------------------------------------- 1 | package reconciliation 2 | 3 | import ( 4 | corev1 "k8s.io/api/core/v1" 5 | "k8s.io/apimachinery/pkg/api/resource" 6 | ) 7 | 8 | // Builds the resource requirements given the default values for cpu and memory. 9 | func buildResourceRequirements(cpuMillis, memoryMB, cpuLimits, memoryLimits int64) corev1.ResourceRequirements { 10 | req := corev1.ResourceRequirements{ 11 | Requests: corev1.ResourceList{ 12 | "cpu": *resource.NewMilliQuantity(cpuMillis, resource.DecimalSI), 13 | "memory": *resource.NewScaledQuantity(memoryMB, resource.Mega), 14 | }, 15 | Limits: corev1.ResourceList{ 16 | "memory": *resource.NewScaledQuantity(memoryLimits, resource.Mega), 17 | }, 18 | } 19 | 20 | if cpuLimits > int64(0) { 21 | req.Limits["cpu"] = *resource.NewMilliQuantity(cpuLimits, resource.DecimalSI) 22 | } 23 | 24 | return req 25 | } 26 | 27 | // Determines if the given resource requirements are specified or not. 28 | func isResourceRequirementsNotSpecified(res *corev1.ResourceRequirements) bool { 29 | if res.Limits == nil && res.Requests == nil { 30 | return false 31 | } 32 | 33 | return true 34 | } 35 | 36 | // Returns the default resources in case the given resources are not configured. 37 | func getResourcesOrDefault(res *corev1.ResourceRequirements, 38 | defaultRes *corev1.ResourceRequirements) *corev1.ResourceRequirements { 39 | if !isResourceRequirementsNotSpecified(res) { 40 | return defaultRes 41 | } 42 | 43 | return res 44 | } 45 | 46 | func emptyMapIfNil(m map[string]string) map[string]string { 47 | if m == nil { 48 | return map[string]string{} 49 | } 50 | return m 51 | } 52 | -------------------------------------------------------------------------------- /pkg/serverconfig/parsing.go: -------------------------------------------------------------------------------- 1 | package serverconfig 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/Jeffail/gabs/v2" 7 | api "github.com/k8ssandra/cass-operator/apis/cassandra/v1beta1" 8 | ) 9 | 10 | func LegacyInternodeEnabled(dc *api.CassandraDatacenter) bool { 11 | config, err := gabs.ParseJSON(dc.Spec.Config) 12 | if err != nil { 13 | return false 14 | } 15 | 16 | hasOldKeyStore := func(gobContainer map[string]*gabs.Container) bool { 17 | if gobContainer == nil { 18 | return false 19 | } 20 | 21 | if keystorePath, found := gobContainer["keystore"]; found { 22 | if strings.TrimSpace(keystorePath.Data().(string)) == "/etc/encryption/node-keystore.jks" { 23 | return true 24 | } 25 | } 26 | return false 27 | } 28 | 29 | if config.Exists("cassandra-yaml", "client_encryption_options") || config.Exists("cassandra-yaml", "server_encryption_options") { 30 | serverContainer := config.Path("cassandra-yaml.server_encryption_options").ChildrenMap() 31 | clientContainer := config.Path("cassandra-yaml.client_encryption_options").ChildrenMap() 32 | 33 | if hasOldKeyStore(clientContainer) || hasOldKeyStore(serverContainer) { 34 | return true 35 | } 36 | } 37 | 38 | return false 39 | } 40 | -------------------------------------------------------------------------------- /pkg/utils/hash_annotation.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package utils 5 | 6 | import ( 7 | "crypto/sha256" 8 | "encoding/base64" 9 | "hash" 10 | 11 | "github.com/davecgh/go-spew/spew" 12 | ) 13 | 14 | type Annotated interface { 15 | GetAnnotations() map[string]string 16 | SetAnnotations(annotations map[string]string) 17 | } 18 | 19 | const ResourceHashAnnotationKey = "cassandra.datastax.com/resource-hash" 20 | 21 | func ResourcesHaveSameHash(r1, r2 Annotated) bool { 22 | a1 := r1.GetAnnotations() 23 | a2 := r2.GetAnnotations() 24 | if a1 == nil || a2 == nil { 25 | return false 26 | } 27 | return a1[ResourceHashAnnotationKey] == a2[ResourceHashAnnotationKey] 28 | } 29 | 30 | func AddHashAnnotation(r Annotated) { 31 | hash := deepHashString(r) 32 | m := r.GetAnnotations() 33 | if m == nil { 34 | m = map[string]string{} 35 | } 36 | m[ResourceHashAnnotationKey] = hash 37 | r.SetAnnotations(m) 38 | } 39 | 40 | func deepHashString(obj interface{}) string { 41 | hasher := sha256.New() 42 | DeepHashObject(hasher, obj) 43 | hashBytes := hasher.Sum([]byte{}) 44 | b64Hash := base64.StdEncoding.EncodeToString(hashBytes) 45 | return b64Hash 46 | } 47 | 48 | // DeepHashObject writes specified object to hash using the spew library 49 | // which follows pointers and prints actual values of the nested objects 50 | // ensuring the hash does not change when a pointer changes. 51 | func DeepHashObject(hasher hash.Hash, objectToWrite interface{}) { 52 | hasher.Reset() 53 | printer := spew.ConfigState{ 54 | Indent: " ", 55 | SortKeys: true, 56 | DisableMethods: true, 57 | SpewKeys: true, 58 | } 59 | printer.Fprintf(hasher, "%#v", objectToWrite) 60 | } 61 | -------------------------------------------------------------------------------- /pkg/utils/hash_annotation_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | appsv1 "k8s.io/api/apps/v1" 5 | "testing" 6 | ) 7 | 8 | func Test_deepHashString(t *testing.T) { 9 | 10 | t.Run("test hash behavior", func(t *testing.T) { 11 | var ss1 appsv1.StatefulSet 12 | var ss2 appsv1.StatefulSet 13 | 14 | ss1.Labels = map[string]string{"abc": "123"} 15 | ss2.Labels = map[string]string{"def": "456"} 16 | 17 | hash1 := deepHashString(&ss1) 18 | hash2 := deepHashString(&ss2) 19 | 20 | if hash1 == hash2 { 21 | t.Errorf("deepHash did not produce different hashes %s %s", hash1, hash2) 22 | } 23 | 24 | var d1 appsv1.Deployment 25 | 26 | hash3 := deepHashString(&d1) 27 | 28 | if hash1 == hash3 { 29 | t.Errorf("deepHash did not produce different hashes %s %s", hash1, hash3) 30 | } 31 | 32 | ss1.Labels["def"] = "456" 33 | ss2.Labels["abc"] = "123" 34 | 35 | hash4 := deepHashString(&ss1) 36 | hash5 := deepHashString(&ss2) 37 | 38 | if hash4 != hash5 { 39 | t.Errorf("deepHash should have produced the same hash %s %s", hash4, hash5) 40 | } 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /scripts/lib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | NEXT_VERSION="" 4 | VERSION_PART="" 5 | 6 | next_minor_version() { 7 | VERSION_PART=2 8 | next_version 9 | } 10 | 11 | next_patch_version() { 12 | VERSION_PART=3 13 | next_version 14 | } 15 | 16 | next_version() { 17 | local RE='[^0-9]*\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)\([0-9A-Za-z-]*\)' 18 | 19 | local NEXT_VERSION_PARTS=(0 0 0) 20 | for i in {1..3} 21 | do 22 | local PART=$(echo $CURRENT_VERSION | sed -e "s#$RE#\\$i#") 23 | ARRAY_INDEX=$((i-1)) 24 | NEXT_VERSION_PARTS[$ARRAY_INDEX]=$PART 25 | 26 | if [ $i == $VERSION_PART ] 27 | then 28 | let PART+=1 29 | NEXT_VERSION_PARTS[$ARRAY_INDEX]=$PART 30 | break 31 | fi 32 | done 33 | 34 | NEXT_VERSION=${NEXT_VERSION_PARTS[0]}.${NEXT_VERSION_PARTS[1]}.${NEXT_VERSION_PARTS[2]} 35 | } 36 | -------------------------------------------------------------------------------- /scripts/post-release-process.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [[ ! $0 == scripts/* ]]; then 3 | echo "This script must be run from the root directory" 4 | exit 1 5 | fi 6 | 7 | IMG=k8ssandra/cass-operator:latest 8 | KUSTOMIZE=$(pwd)/bin/kustomize 9 | 10 | # Add new ## unreleased after the tagging (post-release-process.sh) 11 | gawk -i inplace '/##/ && ++c==1 { print "## unreleased\n"; print; next }1' CHANGELOG.md 12 | 13 | CURRENT_BRANCH=$(git branch --show-current) 14 | 15 | if [ $CURRENT_BRANCH != "master" ]; then 16 | # This is a release branch, we only bump the patch version 17 | export PATCH_RELEASE=true 18 | scripts/update-makefile-version.sh 19 | NEXT_VERSION=$(gawk 'match($0, /^VERSION \?= /) { print substr($0, RLENGTH+1)}' Makefile) 20 | git add Makefile 21 | git add CHANGELOG.md 22 | git commit -m "Prepare for next version $NEXT_VERSION" 23 | exit 0 24 | fi 25 | 26 | # Modify Makefile for the next VERSION in line 27 | scripts/update-makefile-version.sh 28 | 29 | # Return config/manager/kustomization.yaml to :latest 30 | cd config/manager && $KUSTOMIZE edit set image controller=$IMG && cd - 31 | 32 | # Return config/manager/image_config.yaml to :latest 33 | LOG_IMG=k8ssandra/system-logger:latest yq eval -i '.images.system-logger = env(LOG_IMG)' config/manager/image_config.yaml 34 | 35 | # Remove cr.k8ssandra.io prefixes 36 | yq eval -i '.images.k8ssandra-client |= sub("cr.k8ssandra.io/", "")' config/manager/image_config.yaml 37 | yq eval -i '.defaults.cassandra.repository |= sub("cr.k8ssandra.io/", "")' config/manager/image_config.yaml 38 | yq eval -i '.defaults.cassandra.repository |= "ghcr.io/" + .' config/manager/image_config.yaml 39 | 40 | # Remove cr.dstx.io prefixes 41 | yq eval -i '.images.config-builder |= sub("cr.dtsx.io/", "")' config/manager/image_config.yaml 42 | yq eval -i '.defaults.dse.repository |= sub("cr.dtsx.io/", "")' config/manager/image_config.yaml 43 | 44 | # Commit to git 45 | NEXT_VERSION=$(gawk 'match($0, /^VERSION \?= /) { print substr($0, RLENGTH+1)}' Makefile) 46 | 47 | git add Makefile 48 | git add CHANGELOG.md 49 | git add config/manager/kustomization.yaml 50 | git add config/manager/image_config.yaml 51 | 52 | git commit -m "Prepare for next version $NEXT_VERSION" 53 | -------------------------------------------------------------------------------- /scripts/release-community-bundles.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [[ ! $0 == scripts/* ]]; then 3 | echo "This script must be run from the root directory" 4 | exit 1 5 | fi 6 | 7 | if [ "$#" -ne 1 ]; then 8 | echo "Usage: scripts/release-community-bundles.sh version" 9 | echo "Script assumes you are in the correct branch / tag and that community-operators repository" 10 | echo "has been checked out to ../community-operators/" 11 | exit 12 | fi 13 | 14 | VERSION=$1 15 | TARGET_DIRS=(community-operators community-operators-prod) 16 | 17 | # Checkout tag 18 | git checkout v$VERSION 19 | 20 | # Create bundle 21 | make VERSION=$VERSION REGISTRY=cr.k8ssandra.io bundle 22 | 23 | # Modify package name to cass-operator-community 24 | yq eval -i '.annotations."operators.operatorframework.io.bundle.package.v1" = "cass-operator-community"' bundle/metadata/annotations.yaml 25 | 26 | for dir in "${TARGET_DIRS[@]}" 27 | do 28 | TARGET_DIR=../$dir/operators/cass-operator-community/$VERSION 29 | mkdir $TARGET_DIR 30 | cp -R bundle/* $TARGET_DIR 31 | 32 | cd $TARGET_DIR 33 | git checkout -b cass-operator-$VERSION main 34 | git add . 35 | git commit -s -am "operator cass-operator-community (${VERSION})" 36 | cd - 37 | done 38 | -------------------------------------------------------------------------------- /scripts/update-kubernetes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -euo pipefail 3 | 4 | VERSION=${1#"v"} 5 | if [ -z "$VERSION" ]; then 6 | echo "Must specify version!" 7 | exit 1 8 | fi 9 | MODS=($( 10 | curl -sS https://raw.githubusercontent.com/kubernetes/kubernetes/v${VERSION}/go.mod | 11 | sed -n 's|.*k8s.io/\(.*\) => ./staging/src/k8s.io/.*|k8s.io/\1|p' 12 | )) 13 | for MOD in "${MODS[@]}"; do 14 | V=$( 15 | go mod download -json "${MOD}@kubernetes-${VERSION}" | 16 | sed -n 's|.*"Version": "\(.*\)".*|\1|p' 17 | ) 18 | go mod edit "-replace=${MOD}=${MOD}@${V}" 19 | done 20 | go get "k8s.io/kubernetes@v${VERSION}" 21 | -------------------------------------------------------------------------------- /scripts/update-makefile-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [[ ! $0 == scripts/* ]]; then 3 | echo "This script must be run from the root directory" 4 | exit 1 5 | fi 6 | 7 | . scripts/lib.sh 8 | 9 | CURRENT_VERSION=$(gawk 'match($0, /^VERSION \?= /) { print substr($0, RLENGTH+1)}' Makefile) 10 | 11 | if [[ -n $PATCH_RELEASE ]]; then 12 | next_patch_version 13 | else 14 | next_minor_version 15 | fi 16 | 17 | sed -i '' -e "s/VERSION ?= $CURRENT_VERSION/VERSION ?= $NEXT_VERSION/" Makefile 18 | -------------------------------------------------------------------------------- /tests/bring_up_graph/bring_up_graph_suite_test.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package bring_up_graph 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | . "github.com/onsi/ginkgo/v2" 11 | . "github.com/onsi/gomega" 12 | 13 | "github.com/k8ssandra/cass-operator/tests/kustomize" 14 | ginkgo_util "github.com/k8ssandra/cass-operator/tests/util/ginkgo" 15 | "github.com/k8ssandra/cass-operator/tests/util/kubectl" 16 | ) 17 | 18 | var ( 19 | testName = "Bring Up Graph" 20 | namespace = "test-bring-up-graph" 21 | dcName = "dc1" 22 | dcYaml = "../testdata/graph-dc.yaml" 23 | ns = ginkgo_util.NewWrapper(testName, namespace) 24 | ) 25 | 26 | func TestLifecycle(t *testing.T) { 27 | AfterSuite(func() { 28 | logPath := fmt.Sprintf("%s/aftersuite", ns.LogDir) 29 | err := kubectl.DumpAllLogs(logPath).ExecV() 30 | if err != nil { 31 | t.Logf("Failed to dump all the logs: %v", err) 32 | } 33 | 34 | fmt.Printf("\n\tPost-run logs dumped at: %s\n\n", logPath) 35 | ns.Terminate() 36 | err = kustomize.Undeploy(namespace) 37 | if err != nil { 38 | t.Logf("Failed to undeploy cass-operator: %v", err) 39 | } 40 | }) 41 | 42 | RegisterFailHandler(Fail) 43 | RunSpecs(t, testName) 44 | } 45 | 46 | var _ = Describe(testName, func() { 47 | Context("when in a new cluster", func() { 48 | Specify("the operator bring up a graph node", func() { 49 | By("deploy cass-operator with kustomize") 50 | err := kustomize.Deploy(namespace) 51 | Expect(err).ToNot(HaveOccurred()) 52 | 53 | ns.WaitForOperatorReady() 54 | 55 | step := "creating a datacenter resource with graph" 56 | testFile, err := ginkgo_util.CreateTestFile(dcYaml) 57 | Expect(err).ToNot(HaveOccurred()) 58 | 59 | k := kubectl.ApplyFiles(testFile) 60 | ns.ExecAndLog(step, k) 61 | 62 | ns.WaitForDatacenterReady(dcName) 63 | 64 | // graph takes a LONG time to come up in my environment 65 | ns.WaitForDatacenterOperatorProgress(dcName, "Ready", 300) 66 | }) 67 | }) 68 | }) 69 | -------------------------------------------------------------------------------- /tests/bring_up_solr/bring_up_solr_suite_test.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package bring_up_solr 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | . "github.com/onsi/ginkgo/v2" 11 | . "github.com/onsi/gomega" 12 | 13 | "github.com/k8ssandra/cass-operator/tests/kustomize" 14 | ginkgo_util "github.com/k8ssandra/cass-operator/tests/util/ginkgo" 15 | "github.com/k8ssandra/cass-operator/tests/util/kubectl" 16 | ) 17 | 18 | var ( 19 | testName = "Bring Up Solr" 20 | namespace = "test-bring-up-solr" 21 | dcName = "dc1" 22 | dcYaml = "../testdata/solr-dc.yaml" 23 | ns = ginkgo_util.NewWrapper(testName, namespace) 24 | ) 25 | 26 | func TestLifecycle(t *testing.T) { 27 | AfterSuite(func() { 28 | logPath := fmt.Sprintf("%s/aftersuite", ns.LogDir) 29 | err := kubectl.DumpAllLogs(logPath).ExecV() 30 | if err != nil { 31 | t.Logf("Failed to dump all the logs: %v", err) 32 | } 33 | 34 | fmt.Printf("\n\tPost-run logs dumped at: %s\n\n", logPath) 35 | ns.Terminate() 36 | err = kustomize.Undeploy(namespace) 37 | if err != nil { 38 | t.Logf("Failed to undeploy cass-operator: %v", err) 39 | } 40 | }) 41 | 42 | RegisterFailHandler(Fail) 43 | RunSpecs(t, testName) 44 | } 45 | 46 | var _ = Describe(testName, func() { 47 | Context("when in a new cluster", func() { 48 | Specify("the operator bring up a solr node", func() { 49 | By("deploy cass-operator with kustomize") 50 | err := kustomize.Deploy(namespace) 51 | Expect(err).ToNot(HaveOccurred()) 52 | 53 | ns.WaitForOperatorReady() 54 | 55 | step := "creating a datacenter resource with solr" 56 | testFile, err := ginkgo_util.CreateTestFile(dcYaml) 57 | Expect(err).ToNot(HaveOccurred()) 58 | 59 | k := kubectl.ApplyFiles(testFile) 60 | ns.ExecAndLog(step, k) 61 | 62 | // solr takes 10 minutes to come up on my machine 63 | ns.WaitForDatacenterReadyWithTimeouts(dcName, 1000, 30) 64 | }) 65 | }) 66 | }) 67 | -------------------------------------------------------------------------------- /tests/bring_up_spark/bring_up_spark_suite_test.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package bring_up_spark 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | . "github.com/onsi/ginkgo/v2" 11 | . "github.com/onsi/gomega" 12 | 13 | "github.com/k8ssandra/cass-operator/tests/kustomize" 14 | ginkgo_util "github.com/k8ssandra/cass-operator/tests/util/ginkgo" 15 | "github.com/k8ssandra/cass-operator/tests/util/kubectl" 16 | ) 17 | 18 | var ( 19 | testName = "Bring Up Spark" 20 | namespace = "test-bring-up-spark" 21 | dcName = "dc1" 22 | dcYaml = "../testdata/spark-dc.yaml" 23 | ns = ginkgo_util.NewWrapper(testName, namespace) 24 | ) 25 | 26 | func TestLifecycle(t *testing.T) { 27 | AfterSuite(func() { 28 | logPath := fmt.Sprintf("%s/aftersuite", ns.LogDir) 29 | err := kubectl.DumpAllLogs(logPath).ExecV() 30 | if err != nil { 31 | t.Logf("Failed to dump all the logs: %v", err) 32 | } 33 | 34 | fmt.Printf("\n\tPost-run logs dumped at: %s\n\n", logPath) 35 | ns.Terminate() 36 | err = kustomize.Undeploy(namespace) 37 | if err != nil { 38 | t.Logf("Failed to undeploy cass-operator: %v", err) 39 | } 40 | }) 41 | 42 | RegisterFailHandler(Fail) 43 | RunSpecs(t, testName) 44 | } 45 | 46 | var _ = Describe(testName, func() { 47 | Context("when in a new cluster", func() { 48 | Specify("the operator bring up a spark node", func() { 49 | By("deploy cass-operator with kustomize") 50 | err := kustomize.Deploy(namespace) 51 | Expect(err).ToNot(HaveOccurred()) 52 | 53 | ns.WaitForOperatorReady() 54 | 55 | step := "creating a datacenter resource with spark" 56 | testFile, err := ginkgo_util.CreateTestFile(dcYaml) 57 | Expect(err).ToNot(HaveOccurred()) 58 | 59 | k := kubectl.ApplyFiles(testFile) 60 | ns.ExecAndLog(step, k) 61 | 62 | ns.WaitForDatacenterReady(dcName) 63 | 64 | // spark takes a LONG time to come up in my environment 65 | ns.WaitForDatacenterOperatorProgress(dcName, "Ready", 2000) 66 | }) 67 | }) 68 | }) 69 | -------------------------------------------------------------------------------- /tests/cluster_wide_install/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - ../../config/deployments/cluster 6 | 7 | -------------------------------------------------------------------------------- /tests/host_network/host_network_suite_test.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package host_network 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | . "github.com/onsi/ginkgo/v2" 11 | . "github.com/onsi/gomega" 12 | 13 | "github.com/k8ssandra/cass-operator/tests/kustomize" 14 | ginkgo_util "github.com/k8ssandra/cass-operator/tests/util/ginkgo" 15 | "github.com/k8ssandra/cass-operator/tests/util/kubectl" 16 | ) 17 | 18 | var ( 19 | testName = "Host Network" 20 | namespace = "test-host-network" 21 | dcName = "dc1" 22 | dcYaml = "../testdata/host-network-dc.yaml" 23 | ns = ginkgo_util.NewWrapper(testName, namespace) 24 | ) 25 | 26 | func TestLifecycle(t *testing.T) { 27 | AfterSuite(func() { 28 | logPath := fmt.Sprintf("%s/aftersuite", ns.LogDir) 29 | err := kubectl.DumpAllLogs(logPath).ExecV() 30 | if err != nil { 31 | t.Logf("Failed to dump all the logs: %v", err) 32 | } 33 | 34 | fmt.Printf("\n\tPost-run logs dumped at: %s\n\n", logPath) 35 | ns.Terminate() 36 | err = kustomize.Undeploy(namespace) 37 | if err != nil { 38 | t.Logf("Failed to undeploy cass-operator: %v", err) 39 | } 40 | }) 41 | 42 | RegisterFailHandler(Fail) 43 | RunSpecs(t, testName) 44 | } 45 | 46 | var _ = Describe(testName, func() { 47 | Context("when in a new cluster", func() { 48 | Specify("the operator can properly create an additional seed service", func() { 49 | var step string 50 | var k kubectl.KCmd 51 | 52 | By("deploy cass-operator with kustomize") 53 | err := kustomize.Deploy(namespace) 54 | Expect(err).ToNot(HaveOccurred()) 55 | 56 | ns.WaitForOperatorReady() 57 | 58 | step = "creating a datacenter resource with 3 racks/3 nodes" 59 | testFile, err := ginkgo_util.CreateTestFile(dcYaml) 60 | Expect(err).ToNot(HaveOccurred()) 61 | 62 | k = kubectl.ApplyFiles(testFile) 63 | ns.ExecAndLog(step, k) 64 | 65 | ns.WaitForDatacenterReady(dcName) 66 | 67 | step = "ensure pod has host networking enabled" 68 | json := `jsonpath={.spec.hostNetwork}` 69 | k = kubectl.Get("pod", fmt.Sprintf("cluster1-%s-r1-sts-0", dcName)).FormatOutput(json) 70 | ns.WaitForOutputAndLog(step, k, "true", 60) 71 | }) 72 | }) 73 | }) 74 | -------------------------------------------------------------------------------- /tests/internode-encryption-generated/internode_secret_generated_test.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package internode_secret_generated 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | . "github.com/onsi/ginkgo/v2" 11 | . "github.com/onsi/gomega" 12 | 13 | "github.com/k8ssandra/cass-operator/tests/kustomize" 14 | ginkgo_util "github.com/k8ssandra/cass-operator/tests/util/ginkgo" 15 | "github.com/k8ssandra/cass-operator/tests/util/kubectl" 16 | ) 17 | 18 | var ( 19 | testName = "Internode Secret Generated" 20 | namespace = "test-internode-secret-generated" 21 | defaultSecretName = "dc2-keystore" 22 | secretResource = fmt.Sprintf("secret/%s", defaultSecretName) 23 | dcName = "dc2" 24 | dcYaml = "../testdata/encrypted-single-rack-2-node-dc.yaml" 25 | ns = ginkgo_util.NewWrapper(testName, namespace) 26 | ) 27 | 28 | func TestLifecycle(t *testing.T) { 29 | AfterSuite(func() { 30 | logPath := fmt.Sprintf("%s/aftersuite", ns.LogDir) 31 | err := kubectl.DumpAllLogs(logPath).ExecV() 32 | if err != nil { 33 | t.Logf("Failed to dump all the logs: %v", err) 34 | } 35 | 36 | fmt.Printf("\n\tPost-run logs dumped at: %s\n\n", logPath) 37 | ns.Terminate() 38 | err = kustomize.Undeploy(namespace) 39 | if err != nil { 40 | t.Logf("Failed to undeploy cass-operator: %v", err) 41 | } 42 | }) 43 | 44 | RegisterFailHandler(Fail) 45 | RunSpecs(t, testName) 46 | } 47 | 48 | var _ = Describe(testName, func() { 49 | Context("when in a new cluster where internodeSecretName is unspecified", func() { 50 | Specify("the operator generates an appropriate internode secret", func() { 51 | var step string 52 | var k kubectl.KCmd 53 | 54 | By("deploy cass-operator with kustomize") 55 | err := kustomize.Deploy(namespace) 56 | Expect(err).ToNot(HaveOccurred()) 57 | 58 | ns.WaitForOperatorReady() 59 | 60 | step = "creating a datacenter resource with 1 racks/2 nodes" 61 | testFile, err := ginkgo_util.CreateTestFile(dcYaml) 62 | Expect(err).ToNot(HaveOccurred()) 63 | 64 | k = kubectl.ApplyFiles(testFile) 65 | ns.ExecAndLog(step, k) 66 | 67 | ns.WaitForDatacenterReady(dcName) 68 | 69 | // verify the secret was created 70 | step = "check that the internode secret was created" 71 | k = kubectl.Get(secretResource) 72 | ns.ExecAndLog(step, k) 73 | }) 74 | }) 75 | }) 76 | -------------------------------------------------------------------------------- /tests/kustomize/deploy.go: -------------------------------------------------------------------------------- 1 | package kustomize 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "os/exec" 8 | "path/filepath" 9 | ) 10 | 11 | func Deploy(namespace string) error { 12 | return DeployDir(namespace, "kustomize") 13 | } 14 | 15 | func Undeploy(namespace string) error { 16 | return UndeployDir(namespace, "kustomize") 17 | } 18 | 19 | func DeployDir(namespace, testDir string) error { 20 | return runMake(namespace, "deploy-test", testDir) 21 | } 22 | 23 | func UndeployDir(namespace, testDir string) error { 24 | return runMake(namespace, "undeploy-test", testDir) 25 | } 26 | 27 | func runMake(namespace, command, dir string) error { 28 | ns := fmt.Sprintf("NAMESPACE=%s", namespace) 29 | kustDir := fmt.Sprintf("TEST_DIR=%s", dir) 30 | deploy := exec.Command("make", ns, command, kustDir) 31 | var out bytes.Buffer 32 | deploy.Stdout = &out 33 | deploy.Stderr = &out 34 | 35 | path, err := os.Getwd() 36 | if err != nil { 37 | fmt.Printf("Getwd error output:\n%s\n", out.String()) 38 | return err 39 | } 40 | 41 | makeDir, err := os.Open(filepath.Join(path, "..", "..")) 42 | if err != nil { 43 | fmt.Printf("os.Open error output:\n%s\n", out.String()) 44 | return err 45 | } 46 | 47 | deploy.Dir = makeDir.Name() 48 | 49 | err = deploy.Run() 50 | if err != nil { 51 | fmt.Printf("Run error output:\n%s\n", out.String()) 52 | return err 53 | } 54 | 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /tests/no_infinite_reconcile/no_infinite_reconcile_suite_test.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package no_infinite_reconcile 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | . "github.com/onsi/ginkgo/v2" 11 | . "github.com/onsi/gomega" 12 | 13 | "github.com/k8ssandra/cass-operator/tests/kustomize" 14 | ginkgo_util "github.com/k8ssandra/cass-operator/tests/util/ginkgo" 15 | "github.com/k8ssandra/cass-operator/tests/util/kubectl" 16 | ) 17 | 18 | var ( 19 | testName = "No Infinite Reconcile" 20 | namespace = "test-no-infinite-reconcile" 21 | dcName = "dc1" 22 | dcYaml = "../testdata/default-three-rack-three-node-dc.yaml" 23 | ns = ginkgo_util.NewWrapper(testName, namespace) 24 | ) 25 | 26 | func TestLifecycle(t *testing.T) { 27 | AfterSuite(func() { 28 | logPath := fmt.Sprintf("%s/aftersuite", ns.LogDir) 29 | err := kubectl.DumpAllLogs(logPath).ExecV() 30 | if err != nil { 31 | t.Logf("Failed to dump all the logs: %v", err) 32 | } 33 | 34 | fmt.Printf("\n\tPost-run logs dumped at: %s\n\n", logPath) 35 | ns.Terminate() 36 | err = kustomize.Undeploy(namespace) 37 | if err != nil { 38 | t.Logf("Failed to undeploy cass-operator: %v", err) 39 | } 40 | }) 41 | 42 | RegisterFailHandler(Fail) 43 | RunSpecs(t, testName) 44 | } 45 | 46 | var _ = Describe(testName, func() { 47 | Context("when in a new cluster", func() { 48 | Specify("the operator eventually stops reconciling", func() { 49 | var step string 50 | var k kubectl.KCmd 51 | 52 | By("deploy cass-operator with kustomize") 53 | err := kustomize.Deploy(namespace) 54 | Expect(err).ToNot(HaveOccurred()) 55 | 56 | ns.WaitForOperatorReady() 57 | 58 | step = "creating a datacenter resource with 3 racks/3 nodes" 59 | testFile, err := ginkgo_util.CreateTestFile(dcYaml) 60 | Expect(err).ToNot(HaveOccurred()) 61 | 62 | k = kubectl.ApplyFiles(testFile) 63 | ns.ExecAndLog(step, k) 64 | 65 | ns.WaitForDatacenterReady(dcName) 66 | 67 | ns.ExpectDoneReconciling(dcName) 68 | }) 69 | }) 70 | }) 71 | -------------------------------------------------------------------------------- /tests/testdata/additional-seeds-two-rack-four-node-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 4 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | - name: r2 23 | config: 24 | jvm-options: 25 | initial_heap_size: "512m" 26 | max_heap_size: "512m" 27 | additional-jvm-opts: 28 | - "-Ddse.system_distributed_replication_dc_names=dc1" 29 | - "-Ddse.system_distributed_replication_per_dc=1" 30 | - "-Dcassandra.system_distributed_replication_dc_names=dc1" 31 | - "-Dcassandra.system_distributed_replication_per_dc=1" 32 | -------------------------------------------------------------------------------- /tests/testdata/additional-service-annotations-and-labels.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 1 12 | additionalServiceConfig: 13 | dcService: 14 | additionalLabels: 15 | test: additional-serviceoptions 16 | additionalAnnotations: 17 | external-dns.alpha.kubernetes.io/hostname: localhost 18 | storageConfig: 19 | cassandraDataVolumeClaimSpec: 20 | storageClassName: standard 21 | accessModes: 22 | - ReadWriteOnce 23 | resources: 24 | requests: 25 | storage: 250Mi 26 | racks: 27 | - name: r1 28 | config: 29 | jvm-options: 30 | initial_heap_size: "512m" 31 | max_heap_size: "512m" 32 | -------------------------------------------------------------------------------- /tests/testdata/bob-secret-changed.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: my-superuser-secret 5 | type: Opaque 6 | data: 7 | username: Ym9i 8 | password: c29tZWZhbmN5cGFudHNuZXdwYXNzd29yZA== 9 | -------------------------------------------------------------------------------- /tests/testdata/bob-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: my-superuser-secret 5 | type: Opaque 6 | data: 7 | username: Ym9i 8 | password: Ym9iYmVy 9 | -------------------------------------------------------------------------------- /tests/testdata/cass-operator-1.1.0-chart/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: cass-operator 3 | version: 1.0.0 4 | description: Helm chart for Cass Operator. 5 | -------------------------------------------------------------------------------- /tests/testdata/cass-operator-1.1.0-chart/templates/clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | creationTimestamp: null 5 | name: {{ .Values.clusterRoleName }} 6 | rules: 7 | - apiGroups: 8 | - admissionregistration.k8s.io 9 | resources: 10 | - validatingwebhookconfigurations 11 | verbs: 12 | - create 13 | - get 14 | - update 15 | resourceNames: 16 | - "cassandradatacenter-webhook-registration" 17 | -------------------------------------------------------------------------------- /tests/testdata/cass-operator-1.1.0-chart/templates/clusterrolebinding.yaml: -------------------------------------------------------------------------------- 1 | kind: ClusterRoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: {{ .Values.clusterRoleBindingName }} 5 | subjects: 6 | - kind: ServiceAccount 7 | name: {{ .Values.serviceAccountName }} 8 | namespace: {{ .Release.Namespace }} 9 | roleRef: 10 | kind: ClusterRole 11 | name: {{ .Values.clusterRoleName }} 12 | apiGroup: rbac.authorization.k8s.io 13 | -------------------------------------------------------------------------------- /tests/testdata/cass-operator-1.1.0-chart/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Values.deploymentName }} 5 | spec: 6 | replicas: {{ .Values.deploymentReplicas }} 7 | selector: 8 | matchLabels: 9 | name: cass-operator 10 | template: 11 | metadata: 12 | labels: 13 | name: cass-operator 14 | spec: 15 | serviceAccountName: {{ .Values.serviceAccountName }} 16 | volumes: 17 | - name: cass-operator-certs-volume 18 | secret: 19 | secretName: cass-operator-webhook-config 20 | containers: 21 | - name: cass-operator 22 | image: {{ .Values.image }} 23 | imagePullPolicy: {{ .Values.imagePullPolicy }} 24 | volumeMounts: 25 | - mountPath: /tmp/k8s-webhook-server/serving-certs 26 | name: cass-operator-certs-volume 27 | readOnly: false 28 | livenessProbe: 29 | exec: 30 | command: 31 | - pgrep 32 | - ".*operator" 33 | initialDelaySeconds: 5 34 | periodSeconds: 5 35 | timeoutSeconds: 5 36 | failureThreshold: 3 37 | readinessProbe: 38 | exec: 39 | command: 40 | - stat 41 | - "/tmp/operator-sdk-ready" 42 | initialDelaySeconds: 5 43 | periodSeconds: 5 44 | timeoutSeconds: 5 45 | failureThreshold: 1 46 | env: 47 | - name: WATCH_NAMESPACE 48 | valueFrom: 49 | fieldRef: 50 | fieldPath: metadata.namespace 51 | - name: POD_NAME 52 | valueFrom: 53 | fieldRef: 54 | fieldPath: metadata.name 55 | - name: OPERATOR_NAME 56 | value: "cass-operator" 57 | - name: SKIP_VALIDATING_WEBHOOK 58 | value: "FALSE" 59 | -------------------------------------------------------------------------------- /tests/testdata/cass-operator-1.1.0-chart/templates/role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: Role 3 | metadata: 4 | name: {{ .Values.roleName }} 5 | rules: 6 | - apiGroups: 7 | - "" 8 | resources: 9 | - pods 10 | - services 11 | - endpoints 12 | - persistentvolumeclaims 13 | - events 14 | - configmaps 15 | - secrets 16 | verbs: 17 | - '*' 18 | - apiGroups: 19 | - "" 20 | resources: 21 | - namespaces 22 | verbs: 23 | - get 24 | - apiGroups: 25 | - apps 26 | resources: 27 | - deployments 28 | - daemonsets 29 | - replicasets 30 | - statefulsets 31 | verbs: 32 | - '*' 33 | - apiGroups: 34 | - monitoring.coreos.com 35 | resources: 36 | - servicemonitors 37 | verbs: 38 | - get 39 | - create 40 | - apiGroups: 41 | - apps 42 | resourceNames: 43 | - cass-operator 44 | resources: 45 | - deployments/finalizers 46 | verbs: 47 | - update 48 | - apiGroups: 49 | - datastax.com 50 | resources: 51 | - '*' 52 | verbs: 53 | - '*' 54 | - apiGroups: 55 | - policy 56 | resources: 57 | - poddisruptionbudgets 58 | verbs: 59 | - '*' 60 | - apiGroups: 61 | - cassandra.datastax.com 62 | resources: 63 | - '*' 64 | verbs: 65 | - '*' 66 | -------------------------------------------------------------------------------- /tests/testdata/cass-operator-1.1.0-chart/templates/rolebinding.yaml: -------------------------------------------------------------------------------- 1 | kind: RoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: {{ .Values.roleBindingName }} 5 | subjects: 6 | - kind: ServiceAccount 7 | name: {{ .Values.serviceAccountName }} 8 | roleRef: 9 | kind: Role 10 | name: {{ .Values.roleName }} 11 | apiGroup: rbac.authorization.k8s.io 12 | -------------------------------------------------------------------------------- /tests/testdata/cass-operator-1.1.0-chart/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: cass-operator-webhook-config 5 | data: 6 | tls.crt: "" 7 | tls.key: "" 8 | -------------------------------------------------------------------------------- /tests/testdata/cass-operator-1.1.0-chart/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: cassandradatacenter-webhook-service 5 | labels: 6 | name: cass-operator-webhook 7 | spec: 8 | ports: 9 | - port: 443 10 | targetPort: 443 11 | selector: 12 | name: cass-operator 13 | -------------------------------------------------------------------------------- /tests/testdata/cass-operator-1.1.0-chart/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: {{ .Values.serviceAccountName }} 5 | -------------------------------------------------------------------------------- /tests/testdata/cass-operator-1.1.0-chart/templates/validatingwebhookconfiguration.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: admissionregistration.k8s.io/v1beta1 2 | kind: ValidatingWebhookConfiguration 3 | metadata: 4 | name: "cassandradatacenter-webhook-registration" 5 | webhooks: 6 | - name: "cassandradatacenter-webhook.cassandra.datastax.com" 7 | rules: 8 | - apiGroups: ["cassandra.datastax.com"] 9 | apiVersions: ["v1beta1"] 10 | operations: ["CREATE", "UPDATE", "DELETE"] 11 | resources: ["cassandradatacenters"] 12 | scope: "*" 13 | clientConfig: 14 | service: 15 | name: "cassandradatacenter-webhook-service" 16 | namespace: {{ .Release.Namespace }} 17 | path: /validate-cassandra-datastax-com-v1beta1-cassandradatacenter 18 | admissionReviewVersions: ["v1beta1"] 19 | failurePolicy: "Ignore" 20 | matchPolicy: "Equivalent" 21 | sideEffects: None 22 | timeoutSeconds: 10 23 | -------------------------------------------------------------------------------- /tests/testdata/cass-operator-1.1.0-chart/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values 2 | serviceAccountName: cass-operator 3 | clusterRoleName: cass-operator-cluster-role 4 | clusterRoleBindingName: cass-operator 5 | roleName: cass-operator 6 | roleBindingName: cass-operator 7 | deploymentName: cass-operator 8 | deploymentReplicas: 1 9 | image: "datastax/cass-operator:1.1.0" 10 | imagePullPolicy: IfNotPresent 11 | -------------------------------------------------------------------------------- /tests/testdata/cluster-wide-install-dc1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 1 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | config: 23 | jvm-options: 24 | initial_heap_size: "512m" 25 | max_heap_size: "512m" 26 | -------------------------------------------------------------------------------- /tests/testdata/cluster-wide-install-dc2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 1 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | config: 23 | jvm-options: 24 | initial_heap_size: "512m" 25 | max_heap_size: "512m" 26 | -------------------------------------------------------------------------------- /tests/testdata/cluster-with-config-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | annotations: 6 | cassandra.datastax.com/autoupdate-spec: always 7 | spec: 8 | clusterName: cluster1 9 | serverType: cassandra 10 | serverVersion: "3.11.10" 11 | managementApiAuth: 12 | insecure: {} 13 | size: 3 14 | storageConfig: 15 | cassandraDataVolumeClaimSpec: 16 | storageClassName: standard 17 | accessModes: 18 | - ReadWriteOnce 19 | resources: 20 | requests: 21 | storage: 1Gi 22 | racks: 23 | - name: r1 24 | - name: r2 25 | - name: r3 26 | configSecret: test-config 27 | -------------------------------------------------------------------------------- /tests/testdata/config_fql_4x_test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: 4.0.0 9 | managementApiAuth: 10 | insecure: {} 11 | size: 1 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | config: 21 | cassandra-yaml: 22 | full_query_logging_options: 23 | log_dir: /var/log/cassandra/fql 24 | -------------------------------------------------------------------------------- /tests/testdata/configs/my-metrics-config.yaml: -------------------------------------------------------------------------------- 1 | kind: ConfigMap 2 | apiVersion: v1 3 | metadata: 4 | name: my-metrics-config 5 | namespace: cass-operator 6 | data: 7 | metrics-collector.yaml: | 8 | relabels: 9 | - regex: ".+" 10 | replacement: "true" 11 | sourceLabels: ["table"] 12 | targetLabel: "should_drop" 13 | -------------------------------------------------------------------------------- /tests/testdata/configs/vector-config.yaml: -------------------------------------------------------------------------------- 1 | kind: ConfigMap 2 | apiVersion: v1 3 | metadata: 4 | name: vector-config 5 | namespace: cass-operator 6 | data: 7 | vector.toml: | 8 | [api] 9 | enabled = true 10 | 11 | [sources.systemlog] 12 | type = "file" 13 | include = [ "/var/log/cassandra/system.log" ] 14 | read_from = "beginning" 15 | fingerprint.strategy = "device_and_inode" 16 | 17 | [sources.systemlog.multiline] 18 | start_pattern = "^(INFO|WARN|ERROR|DEBUG|TRACE|FATAL)" 19 | condition_pattern = "^(INFO|WARN|ERROR|DEBUG|TRACE|FATAL)" 20 | mode = "halt_before" 21 | timeout_ms = 10000 22 | 23 | [transforms.parse_cassandra_log] 24 | type = "remap" 25 | inputs = [ "systemlog" ] 26 | source = ''' 27 | del(.source_type) 28 | . |= parse_groks!(.message, patterns: [ 29 | "%{LOGLEVEL:loglevel}\\s+\\[(?((.+)))\\]\\s+%{TIMESTAMP_ISO8601:timestamp}\\s+%{JAVACLASS:class}:%{NUMBER:line}\\s+-\\s+(?(.+\\n?)+)", 30 | ] 31 | ) 32 | pod_name, err = get_env_var("POD_NAME") 33 | if err == null { 34 | .pod_name = pod_name 35 | } 36 | 37 | node_name, err = get_env_var("NODE_NAME") 38 | if err == null { 39 | .node_name = node_name 40 | } 41 | 42 | cluster, err = get_env_var("CLUSTER_NAME") 43 | if err == null { 44 | .cluster = cluster 45 | } 46 | 47 | datacenter, err = get_env_var("DATACENTER_NAME") 48 | if err == null { 49 | .datacenter = datacenter 50 | } 51 | 52 | rack, err = get_env_var("RACK_NAME") 53 | if err == null { 54 | .rack = rack 55 | } 56 | 57 | namespace, err = get_env_var("NAMESPACE") 58 | if err == null { 59 | .namespace = namespace 60 | } 61 | ''' 62 | 63 | [sinks.console] 64 | type = "console" 65 | inputs = ["parse_cassandra_log"] 66 | target = "stdout" 67 | encoding.codec = "json" 68 | -------------------------------------------------------------------------------- /tests/testdata/default-single-rack-2-node-dc-with-auth-enabled.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: cassandra 8 | serverVersion: "4.1.2" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 2 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | config: 23 | jvm-server-options: 24 | initial_heap_size: "512m" 25 | max_heap_size: "512m" 26 | cassandra-yaml: 27 | allocate_tokens_for_local_replication_factor: 2 28 | rpc_address: "0.0.0.0" 29 | authenticator: PasswordAuthenticator 30 | authorizer: CassandraAuthorizer 31 | role_manager: CassandraRoleManager 32 | -------------------------------------------------------------------------------- /tests/testdata/default-single-rack-2-node-dc-with-superuser-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: cassandra 8 | serverVersion: "4.1.2" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 2 12 | superuserSecretName: my-superuser-secret 13 | storageConfig: 14 | cassandraDataVolumeClaimSpec: 15 | storageClassName: standard 16 | accessModes: 17 | - ReadWriteOnce 18 | resources: 19 | requests: 20 | storage: 1Gi 21 | users: 22 | - secretName: bobby-secret 23 | superuser: false 24 | racks: 25 | - name: r1 26 | config: 27 | jvm-server-options: 28 | initial_heap_size: "512m" 29 | max_heap_size: "512m" 30 | cassandra-yaml: 31 | allocate_tokens_for_local_replication_factor: 2 32 | rpc_address: "0.0.0.0" 33 | authenticator: PasswordAuthenticator 34 | authorizer: CassandraAuthorizer 35 | role_manager: CassandraRoleManager 36 | -------------------------------------------------------------------------------- /tests/testdata/default-single-rack-2-node-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: cassandra 8 | serverVersion: "4.0.4" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 2 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | config: 23 | cassandra-yaml: 24 | allocate_tokens_for_local_replication_factor: 2 25 | jvm-server-options: 26 | initial_heap_size: "512m" 27 | max_heap_size: "512m" 28 | -------------------------------------------------------------------------------- /tests/testdata/default-single-rack-2-node-dc1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster2 7 | serverType: cassandra 8 | serverVersion: "4.0.4" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 2 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | config: 23 | cassandra-yaml: 24 | allocate_tokens_for_local_replication_factor: 2 25 | jvm-server-options: 26 | initial_heap_size: "512m" 27 | max_heap_size: "512m" 28 | -------------------------------------------------------------------------------- /tests/testdata/default-single-rack-single-node-additional-volumesources.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: cassandra 8 | serverVersion: "4.0.7" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 1 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: &storageclass_server_storage 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | additionalVolumes: 21 | - name: metrics-config 22 | mountPath: /opt/management-api/configs 23 | volumeSource: 24 | configMap: 25 | name: "my-metrics-config" 26 | - name: vector-config 27 | mountPath: /etc/vector 28 | volumeSource: 29 | configMap: 30 | name: "vector-config" 31 | racks: 32 | - name: r1 33 | config: 34 | jvm-server-options: 35 | initial_heap_size: "512m" 36 | max_heap_size: "512m" 37 | -------------------------------------------------------------------------------- /tests/testdata/default-single-rack-single-node-addtional-volumes-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 1 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: &storageclass_server_storage 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | additionalVolumes: 21 | - name: "server-logs" 22 | mountPath: "/var/log/cassandra" 23 | pvcSpec: *storageclass_server_storage 24 | - name: cassandra-commitlogs 25 | mountPath: /var/lib/cassandra/commitlog 26 | pvcSpec: *storageclass_server_storage 27 | racks: 28 | - name: r1 29 | podTemplateSpec: 30 | spec: 31 | initContainers: 32 | - name: server-config-init 33 | resources: {} 34 | containers: 35 | - args: ["/bin/sh", "-c", "tail -n+1 -F /var/log/cassandra/system.log"] 36 | image: busybox 37 | imagePullPolicy: "Always" 38 | name: "another-tailing-logger" 39 | terminationMessagePath: "/dev/termination-log" 40 | terminationMessagePolicy: "File" 41 | securityContext: 42 | allowPrivilegeEscalation: false 43 | capabilities: 44 | drop: 45 | - "ALL" 46 | readOnlyRootFilesystem: true 47 | runAsGroup: 999 48 | runAsUser: 999 49 | runAsNonRoot: true 50 | volumeMounts: 51 | - mountPath: "/var/log/cassandra" 52 | name: "server-logs" 53 | config: 54 | jvm-options: 55 | initial_heap_size: "512m" 56 | max_heap_size: "512m" 57 | -------------------------------------------------------------------------------- /tests/testdata/default-single-rack-single-node-dc-lvm.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | annotations: 6 | cassandra.datastax.com/allow-storage-changes: "true" 7 | spec: 8 | clusterName: cluster1 9 | serverType: cassandra 10 | serverVersion: "4.1.4" 11 | managementApiAuth: 12 | insecure: {} 13 | size: 1 14 | storageConfig: 15 | cassandraDataVolumeClaimSpec: 16 | storageClassName: topolvm-provisioner-thin 17 | accessModes: 18 | - ReadWriteOnce 19 | resources: 20 | requests: 21 | storage: 1Gi 22 | racks: 23 | - name: r1 24 | config: 25 | jvm-server-options: 26 | initial_heap_size: "512m" 27 | max_heap_size: "512m" 28 | -------------------------------------------------------------------------------- /tests/testdata/default-single-rack-single-node-dc-with-readonly-fs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: 4.1.6 9 | managementApiAuth: 10 | insecure: {} 11 | readOnlyRootFilesystem: true 12 | size: 1 13 | storageConfig: 14 | cassandraDataVolumeClaimSpec: 15 | storageClassName: standard 16 | accessModes: 17 | - ReadWriteOnce 18 | resources: 19 | requests: 20 | storage: 1Gi 21 | racks: 22 | - name: r1 23 | config: 24 | jvm-server-options: 25 | initial_heap_size: "512m" 26 | max_heap_size: "512m" 27 | -------------------------------------------------------------------------------- /tests/testdata/default-single-rack-single-node-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: cassandra 8 | serverVersion: "4.1.1" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 1 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | config: 23 | jvm-server-options: 24 | initial_heap_size: "512m" 25 | max_heap_size: "512m" 26 | -------------------------------------------------------------------------------- /tests/testdata/default-single-rack-single-node-extra-container-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 1 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | podTemplateSpec: 23 | spec: 24 | containers: 25 | - args: ["/bin/sh", "-c", "tail -n+1 -F /var/log/cassandra/system.log"] 26 | image: busybox 27 | imagePullPolicy: "Always" 28 | name: "another-tailing-logger" 29 | terminationMessagePath: "/dev/termination-log" 30 | terminationMessagePolicy: "File" 31 | volumeMounts: 32 | - mountPath: "/var/log/cassandra" 33 | name: "server-logs" 34 | config: 35 | jvm-options: 36 | initial_heap_size: "512m" 37 | max_heap_size: "512m" 38 | -------------------------------------------------------------------------------- /tests/testdata/default-single-rack-single-node-hcd-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: hcd 8 | serverVersion: "1.0.0" 9 | serverImage: "datastax/hcd:1.0.0-early-preview-ubi" 10 | managementApiAuth: 11 | insecure: {} 12 | size: 1 13 | storageConfig: 14 | cassandraDataVolumeClaimSpec: 15 | storageClassName: standard 16 | accessModes: 17 | - ReadWriteOnce 18 | resources: 19 | requests: 20 | storage: 1Gi 21 | racks: 22 | - name: r1 23 | config: 24 | jvm-server-options: 25 | initial_heap_size: "512m" 26 | max_heap_size: "512m" 27 | -------------------------------------------------------------------------------- /tests/testdata/default-single-rack-single-node-prestop-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 1 12 | podTemplateSpec: 13 | spec: 14 | containers: 15 | - name: "cassandra" 16 | lifecycle: 17 | preStop: 18 | exec: 19 | command: ["/bin/sleep", "6000s"] 20 | storageConfig: 21 | cassandraDataVolumeClaimSpec: 22 | storageClassName: standard 23 | accessModes: 24 | - ReadWriteOnce 25 | resources: 26 | requests: 27 | storage: 1Gi 28 | racks: 29 | - name: r1 30 | config: 31 | jvm-options: 32 | initial_heap_size: "512m" 33 | max_heap_size: "512m" 34 | -------------------------------------------------------------------------------- /tests/testdata/default-three-rack-four-node-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 4 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | - name: r2 23 | - name: r3 24 | config: 25 | jvm-options: 26 | initial_heap_size: "512m" 27 | max_heap_size: "512m" 28 | -------------------------------------------------------------------------------- /tests/testdata/default-three-rack-four-node-limited-storage-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 4 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 300Ki 20 | racks: 21 | - name: r1 22 | - name: r2 23 | - name: r3 24 | config: 25 | jvm-options: 26 | initial_heap_size: "512m" 27 | max_heap_size: "512m" 28 | -------------------------------------------------------------------------------- /tests/testdata/default-three-rack-three-node-dc-4x.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | datacenterName: My_Super_Dc 9 | serverVersion: 4.1.6 10 | managementApiAuth: 11 | insecure: {} 12 | size: 3 13 | storageConfig: 14 | cassandraDataVolumeClaimSpec: 15 | storageClassName: standard 16 | accessModes: 17 | - ReadWriteOnce 18 | resources: 19 | requests: 20 | storage: 1Gi 21 | racks: 22 | - name: r1 23 | - name: r2 24 | - name: r3 25 | config: 26 | jvm-server-options: 27 | initial_heap_size: "512m" 28 | max_heap_size: "512m" 29 | -------------------------------------------------------------------------------- /tests/testdata/default-three-rack-three-node-dc-zones.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "5.0.2" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 3 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | affinity: 23 | nodeAffinity: 24 | requiredDuringSchedulingIgnoredDuringExecution: 25 | nodeSelectorTerms: 26 | - matchExpressions: 27 | - key: topology.kubernetes.io/zone 28 | operator: In 29 | values: 30 | - europe-north1-a 31 | - name: r2 32 | affinity: 33 | nodeAffinity: 34 | requiredDuringSchedulingIgnoredDuringExecution: 35 | nodeSelectorTerms: 36 | - matchExpressions: 37 | - key: topology.kubernetes.io/zone 38 | operator: In 39 | values: 40 | - europe-north1-b 41 | - name: r3 42 | affinity: 43 | nodeAffinity: 44 | requiredDuringSchedulingIgnoredDuringExecution: 45 | nodeSelectorTerms: 46 | - matchExpressions: 47 | - key: topology.kubernetes.io/zone 48 | operator: In 49 | values: 50 | - europe-north1-c 51 | config: 52 | jvm-options: 53 | initial_heap_size: "512m" 54 | max_heap_size: "512m" 55 | -------------------------------------------------------------------------------- /tests/testdata/default-three-rack-three-node-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 3 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | - name: r2 23 | - name: r3 24 | config: 25 | jvm-options: 26 | initial_heap_size: "512m" 27 | max_heap_size: "512m" 28 | -------------------------------------------------------------------------------- /tests/testdata/default-two-rack-four-node-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "3.11.15" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 4 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | - name: r2 23 | config: 24 | cassandra-yaml: 25 | allocate_tokens_for_local_replication_factor: 2 26 | jvm-options: 27 | initial_heap_size: "512m" 28 | max_heap_size: "512m" 29 | additional-jvm-opts: 30 | - "-Ddse.system_distributed_replication_dc_names=dc1" 31 | - "-Ddse.system_distributed_replication_per_dc=1" 32 | - "-Dcassandra.system_distributed_replication_dc_names=dc1" 33 | - "-Dcassandra.system_distributed_replication_per_dc=1" 34 | # - "-Dcassandra.ring_delay_ms=0" 35 | -------------------------------------------------------------------------------- /tests/testdata/default-two-rack-two-node-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | datacenterName: My_Super_Dc 8 | serverType: cassandra 9 | serverVersion: "4.1.7" 10 | managementApiAuth: 11 | insecure: {} 12 | size: 2 13 | storageConfig: 14 | cassandraDataVolumeClaimSpec: 15 | storageClassName: standard 16 | accessModes: 17 | - ReadWriteOnce 18 | resources: 19 | requests: 20 | storage: 1Gi 21 | racks: 22 | - name: r1 23 | - name: r2 24 | podTemplateSpec: 25 | spec: 26 | containers: 27 | - name: "cassandra" 28 | securityContext: 29 | runAsUser: 12345 30 | runAsGroup: 0 31 | runAsNonRoot: true 32 | config: 33 | cassandra-yaml: 34 | allocate_tokens_for_local_replication_factor: 2 35 | jvm-server-options: 36 | initial_heap_size: "512m" 37 | max_heap_size: "512m" 38 | additional-jvm-opts: 39 | - "-Dcassandra.system_distributed_replication_dc_names=My_Super_Dc" 40 | - "-Dcassandra.system_distributed_replication_per_dc=1" 41 | -------------------------------------------------------------------------------- /tests/testdata/default-two-rack-two-node-dc2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "4.0.6" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 2 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | - name: r2 23 | config: 24 | cassandra-yaml: 25 | allocate_tokens_for_local_replication_factor: 2 26 | jvm-server-options: 27 | initial_heap_size: "512m" 28 | max_heap_size: "512m" 29 | additional-jvm-opts: 30 | - "-Dcassandra.system_distributed_replication_dc_names=dc2" 31 | - "-Dcassandra.system_distributed_replication_per_dc=1" 32 | -------------------------------------------------------------------------------- /tests/testdata/encrypted-single-rack-2-node-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 2 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | config: 23 | jvm-options: 24 | initial_heap_size: "512m" 25 | max_heap_size: "512m" 26 | cassandra-yaml: 27 | allocate_tokens_for_local_replication_factor: 2 28 | server_encryption_options: 29 | internode_encryption: all 30 | keystore: /etc/encryption/node-keystore.jks 31 | keystore_password: dc2 32 | truststore: /etc/encryption/node-keystore.jks 33 | truststore_password: dc2 34 | -------------------------------------------------------------------------------- /tests/testdata/graph-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: dse 8 | serverVersion: "6.8.4" 9 | dseWorkloads: 10 | graphEnabled: true 11 | managementApiAuth: 12 | insecure: {} 13 | size: 1 14 | storageConfig: 15 | cassandraDataVolumeClaimSpec: 16 | storageClassName: standard 17 | accessModes: 18 | - ReadWriteOnce 19 | resources: 20 | requests: 21 | storage: 1Gi 22 | racks: 23 | - name: r1 24 | config: 25 | jvm-server-options: 26 | initial_heap_size: "2000m" 27 | max_heap_size: "2000m" 28 | cassandra-yaml: 29 | file_cache_size_in_mb: 100 30 | memtable_space_in_mb: 100 31 | -------------------------------------------------------------------------------- /tests/testdata/host-network-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 3 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | networking: 21 | hostNetwork: true 22 | racks: 23 | - name: r1 24 | - name: r2 25 | - name: r3 26 | config: 27 | jvm-options: 28 | initial_heap_size: "512m" 29 | max_heap_size: "512m" 30 | -------------------------------------------------------------------------------- /tests/testdata/image_config_parsing.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: config.k8ssandra.io/v1beta1 2 | kind: ImageConfig 3 | metadata: 4 | name: image-config 5 | images: 6 | system-logger: "k8ssandra/system-logger:latest" 7 | config-builder: "datastax/cass-config-builder:1.0-ubi8" 8 | k8ssandra-client: "k8ssandra/k8ssandra-client:v0.2.2" 9 | cassandra: 10 | "4.0.0": "k8ssandra/cassandra-ubi:latest" 11 | dse: 12 | "6.8.999": "datastax/dse-server-prototype:latest" 13 | imageRegistry: "localhost:5000" 14 | imagePullPolicy: Always 15 | imagePullSecret: 16 | name: my-secret-pull-registry 17 | defaults: 18 | # Note, postfix is ignored if repository is not set 19 | cassandra: 20 | repository: "cr.k8ssandra.io/k8ssandra/cass-management-api" 21 | suffix: "-ubi" 22 | dse: 23 | repository: "cr.dtsx.io/datastax/dse-mgmtapi-6_8" 24 | suffix: "-ubi8" 25 | -------------------------------------------------------------------------------- /tests/testdata/image_config_parsing_more_options.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: config.k8ssandra.io/v1beta1 2 | kind: ImageConfig 3 | metadata: 4 | name: image-config 5 | images: 6 | system-logger: "k8ssandra/system-logger:latest" 7 | config-builder: "datastax/cass-config-builder:1.0-ubi8" 8 | k8ssandra-client: "k8ssandra/k8ssandra-client:v0.2.2" 9 | cassandra: 10 | "4.0.0": "k8ssandra/cassandra-ubi:latest" 11 | dse: 12 | "6.8.999": "datastax/dse-server-prototype:latest" 13 | hcd: 14 | "1.0.0": "datastax/hcd:latest" 15 | medusa: "k8ssandra/medusa:latest" 16 | reaper: "k8ssandra/reaper:latest" 17 | imageRegistry: "localhost:5000" 18 | imagePullPolicy: Always 19 | imagePullSecret: 20 | name: my-secret-pull-registry 21 | imageNamespace: "enterprise" 22 | defaults: 23 | # Note, suffix is ignored if repository is not set 24 | cassandra: 25 | repository: "k8ssandra/cass-management-api" 26 | imageRegistry: "localhost:5001" 27 | imagePullPolicy: IfNotPresent 28 | imagePullSecret: 29 | name: my-secret-pull-registry-cassandra 30 | dse: 31 | repository: "datastax/dse-server" 32 | imageRegistry: "localhost:5002" 33 | imagePullPolicy: IfNotPresent 34 | imagePullSecret: 35 | name: my-secret-pull-registry-dse 36 | suffix: "-ubi7" 37 | config-builder: 38 | imageRegistry: "localhost:5003" 39 | imagePullPolicy: IfNotPresent 40 | imagePullSecret: 41 | name: my-secret-pull-registry-builder 42 | system-logger: 43 | imageRegistry: "localhost:5004" 44 | imagePullPolicy: Always 45 | imagePullSecret: 46 | name: my-secret-pull-registry-logger 47 | medusa: 48 | imageRegistry: "localhost:5005" 49 | -------------------------------------------------------------------------------- /tests/testdata/kind/kind_config_1_worker.yaml: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.x-k8s.io/v1alpha4 3 | networking: 4 | apiServerPort: 45451 5 | nodes: 6 | - role: control-plane 7 | - role: worker 8 | -------------------------------------------------------------------------------- /tests/testdata/kind/kind_config_3_workers.yaml: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.x-k8s.io/v1alpha4 3 | networking: 4 | apiServerPort: 45451 5 | nodes: 6 | - role: control-plane 7 | - role: worker 8 | - role: worker 9 | - role: worker 10 | -------------------------------------------------------------------------------- /tests/testdata/kind/kind_config_6_workers.yaml: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.x-k8s.io/v1alpha4 3 | networking: 4 | apiServerPort: 45451 5 | nodes: 6 | - role: control-plane 7 | - role: worker 8 | - role: worker 9 | - role: worker 10 | - role: worker 11 | - role: worker 12 | - role: worker 13 | -------------------------------------------------------------------------------- /tests/testdata/nodeport-service-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "3.11.10" 9 | managementApiAuth: 10 | insecure: {} 11 | networking: 12 | nodePort: 13 | native: 30001 14 | internode: 30002 15 | size: 2 16 | storageConfig: 17 | cassandraDataVolumeClaimSpec: 18 | storageClassName: standard 19 | accessModes: 20 | - ReadWriteOnce 21 | resources: 22 | requests: 23 | storage: 1Gi 24 | racks: 25 | - name: r1 26 | - name: r2 27 | config: 28 | cassandra-yaml: 29 | allocate_tokens_for_local_replication_factor: 2 30 | jvm-options: 31 | initial_heap_size: "512m" 32 | max_heap_size: "512m" 33 | -------------------------------------------------------------------------------- /tests/testdata/operator-1.7.1-oss-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "3.11.15" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 3 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | - name: r2 23 | - name: r3 24 | config: 25 | jvm-options: 26 | initial_heap_size: "512m" 27 | max_heap_size: "512m" 28 | -------------------------------------------------------------------------------- /tests/testdata/oss-one-node-dc-with-mtls.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "3.11.7" 9 | managementApiAuth: 10 | manual: 11 | clientSecretName: mgmt-api-client-credentials 12 | serverSecretName: mgmt-api-server-credentials 13 | size: 1 14 | storageConfig: 15 | cassandraDataVolumeClaimSpec: 16 | storageClassName: standard 17 | accessModes: 18 | - ReadWriteOnce 19 | resources: 20 | requests: 21 | storage: 1Gi 22 | racks: 23 | - name: r1 24 | config: 25 | jvm-options: 26 | initial_heap_size: "512m" 27 | max_heap_size: "512m" 28 | -------------------------------------------------------------------------------- /tests/testdata/oss-one-node-dc-without-mtls.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "4.0.4" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 1 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | config: 23 | jvm-server-options: 24 | initial_heap_size: "512m" 25 | max_heap_size: "512m" 26 | -------------------------------------------------------------------------------- /tests/testdata/oss-three-rack-three-node-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "3.11.14" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 3 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | - name: r2 23 | - name: r3 24 | config: 25 | jvm-options: 26 | initial_heap_size: "512m" 27 | max_heap_size: "512m" 28 | -------------------------------------------------------------------------------- /tests/testdata/oss-two-rack-six-node-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "3.11.7" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 6 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | - name: r2 23 | config: 24 | jvm-options: 25 | initial_heap_size: "512m" 26 | max_heap_size: "512m" 27 | -------------------------------------------------------------------------------- /tests/testdata/oss-upgrade-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | # Do not change serverVersion. This cassdc is intended for testing a canary 9 | # upgrade specifically from this version. 10 | serverVersion: "4.0.1" 11 | managementApiAuth: 12 | insecure: {} 13 | size: 3 14 | storageConfig: 15 | cassandraDataVolumeClaimSpec: 16 | storageClassName: standard 17 | accessModes: 18 | - ReadWriteOnce 19 | resources: 20 | requests: 21 | storage: 1Gi 22 | racks: 23 | - name: r1 24 | config: 25 | jvm-server-options: 26 | initial_heap_size: "512m" 27 | max_heap_size: "512m" -------------------------------------------------------------------------------- /tests/testdata/single-token-three-rack-three-node-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: cassandra 8 | serverVersion: "4.0.7" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 3 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 1Gi 20 | racks: 21 | - name: r1 22 | - name: r2 23 | - name: r3 24 | config: 25 | jvm-server-options: 26 | initial_heap_size: "512m" 27 | max_heap_size: "512m" 28 | cassandra-yaml: 29 | num_tokens: 1 30 | -------------------------------------------------------------------------------- /tests/testdata/smoke-test-dse.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster2 7 | serverType: dse 8 | serverVersion: "6.8.31" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 1 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 250Mi 20 | racks: 21 | - name: r1 22 | config: 23 | jvm-server-options: 24 | initial_heap_size: "512m" 25 | max_heap_size: "512m" 26 | cassandra-yaml: 27 | file_cache_size_in_mb: 100 28 | memtable_space_in_mb: 100 29 | -------------------------------------------------------------------------------- /tests/testdata/smoke-test-oss.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc2 5 | spec: 6 | clusterName: cluster 2 7 | serverType: cassandra 8 | serverVersion: "4.0.0" 9 | managementApiAuth: 10 | insecure: {} 11 | size: 1 12 | storageConfig: 13 | cassandraDataVolumeClaimSpec: 14 | storageClassName: standard 15 | accessModes: 16 | - ReadWriteOnce 17 | resources: 18 | requests: 19 | storage: 250Mi 20 | racks: 21 | - name: r1 22 | config: 23 | jvm-server-options: 24 | initial_heap_size: "512m" 25 | max_heap_size: "512m" 26 | cassandra-yaml: 27 | num_tokens: 16 28 | -------------------------------------------------------------------------------- /tests/testdata/solr-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: dse 8 | serverVersion: "6.8.4" 9 | dseWorkloads: 10 | searchEnabled: true 11 | managementApiAuth: 12 | insecure: {} 13 | size: 1 14 | storageConfig: 15 | cassandraDataVolumeClaimSpec: 16 | storageClassName: standard 17 | accessModes: 18 | - ReadWriteOnce 19 | resources: 20 | requests: 21 | storage: 1Gi 22 | racks: 23 | - name: r1 24 | config: 25 | jvm-server-options: 26 | initial_heap_size: "2000m" 27 | max_heap_size: "2000m" 28 | cassandra-yaml: 29 | file_cache_size_in_mb: 200 30 | memtable_space_in_mb: 200 31 | -------------------------------------------------------------------------------- /tests/testdata/spark-dc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: cluster1 7 | serverType: dse 8 | serverVersion: "6.8.4" 9 | dseWorkloads: 10 | analyticsEnabled: true 11 | managementApiAuth: 12 | insecure: {} 13 | size: 1 14 | storageConfig: 15 | cassandraDataVolumeClaimSpec: 16 | storageClassName: standard 17 | accessModes: 18 | - ReadWriteOnce 19 | resources: 20 | requests: 21 | storage: 1Gi 22 | racks: 23 | - name: r1 24 | config: 25 | jvm-server-options: 26 | initial_heap_size: "4000m" 27 | max_heap_size: "4000m" 28 | cassandra-yaml: 29 | file_cache_size_in_mb: 100 30 | memtable_space_in_mb: 100 31 | -------------------------------------------------------------------------------- /tests/testdata/tasks/flush_task.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: control.k8ssandra.io/v1alpha1 2 | kind: CassandraTask 3 | metadata: 4 | name: flush-node 5 | spec: 6 | datacenter: 7 | name: dc2 8 | namespace: cass-operator 9 | jobs: 10 | - name: flush-run 11 | command: flush 12 | args: 13 | pod_name: cluster2-dc2-r1-sts-0 14 | -------------------------------------------------------------------------------- /tests/testdata/tasks/move_node_task.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: control.k8ssandra.io/v1alpha1 2 | kind: CassandraTask 3 | metadata: 4 | name: move-node 5 | spec: 6 | datacenter: 7 | name: dc1 8 | namespace: test-node-move 9 | jobs: 10 | - name: move-run 11 | command: move 12 | args: 13 | new_tokens: 14 | cluster1-dc1-r1-sts-0: "-9223372036854775708" 15 | cluster1-dc1-r2-sts-0: "-3074457345618258603" 16 | cluster1-dc1-r3-sts-0: "3074457345618258602" 17 | -------------------------------------------------------------------------------- /tests/testdata/tasks/rebuild_task.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: control.k8ssandra.io/v1alpha1 2 | kind: CassandraTask 3 | metadata: 4 | name: rebuild-dc 5 | spec: 6 | datacenter: 7 | name: dc2 8 | namespace: test-decommission-dc 9 | jobs: 10 | - name: rebuild-dc2 11 | command: rebuild 12 | args: 13 | source_datacenter: My_Super_Dc 14 | -------------------------------------------------------------------------------- /tests/testdata/tasks/replace_node_task.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: control.k8ssandra.io/v1alpha1 2 | kind: CassandraTask 3 | metadata: 4 | name: replace-node 5 | spec: 6 | datacenter: 7 | name: dc1 8 | namespace: test-node-replace 9 | jobs: 10 | - name: replace-run 11 | command: replacenode 12 | args: 13 | pod_name: cluster1-dc1-r3-sts-0 14 | -------------------------------------------------------------------------------- /tests/testdata/tasks/rolling_restart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: control.k8ssandra.io/v1alpha1 2 | kind: CassandraTask 3 | metadata: 4 | name: rolling-restart 5 | spec: 6 | datacenter: 7 | name: dc2 8 | namespace: test-rolling-restart 9 | jobs: 10 | - name: restart-run 11 | command: restart 12 | -------------------------------------------------------------------------------- /tests/testdata/tasks/rolling_restart_override.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: control.k8ssandra.io/v1alpha1 2 | kind: CassandraTask 3 | metadata: 4 | name: rolling-restart 5 | spec: 6 | datacenter: 7 | name: dc1 8 | namespace: test-override-with-rolling-restart 9 | jobs: 10 | - name: restart-run 11 | command: restart 12 | -------------------------------------------------------------------------------- /tests/testdata/test-cdc/cassandra-datacenter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cassandra.datastax.com/v1beta1 2 | kind: CassandraDatacenter 3 | metadata: 4 | name: dc1 5 | spec: 6 | clusterName: test-cluster 7 | # The number of server nodes. 8 | size: 1 9 | config: 10 | cassandra-yaml: 11 | authenticator: AllowAllAuthenticator 12 | authorizer: AllowAllAuthorizer 13 | cdc: 14 | pulsarServiceUrl: pulsar://pulsar-proxy.pulsar.svc.cluster.local:6650 15 | topicPrefix: persistent://public/default/events- 16 | cdcWorkingDir: /var/lib/cassandra/cdc 17 | storageConfig: 18 | cassandraDataVolumeClaimSpec: 19 | storageClassName: standard 20 | accessModes: 21 | - ReadWriteOnce 22 | resources: 23 | requests: 24 | storage: 1Gi 25 | # Which server version to use. Required. 26 | serverVersion: "4.0.13" 27 | serverType: "cassandra" 28 | -------------------------------------------------------------------------------- /tests/testdata/test-cdc/testutils-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: cdc-testutil 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: cdc-testutil 10 | template: 11 | metadata: 12 | labels: 13 | app: cdc-testutil 14 | spec: 15 | containers: 16 | - name: testutils 17 | args: ["/bin/sh", "-c", "while true; do sleep 100; done"] 18 | image: k8ssandra/testutils:v0.0.2-SNAPSHOT 19 | -------------------------------------------------------------------------------- /tests/testdata/test-config-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: test-config 5 | type: Opaque 6 | stringData: 7 | config: |- 8 | { 9 | "cassandra-yaml": { 10 | "read_request_timeout": "5000ms" 11 | }, 12 | "jvm-options": { 13 | "initial_heap_size": "512M", 14 | "max_heap_size": "512M" 15 | } 16 | } -------------------------------------------------------------------------------- /tests/testdata/updated-test-config-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: test-config 5 | type: Opaque 6 | stringData: 7 | config: |- 8 | { 9 | "cassandra-yaml": { 10 | "read_request_timeout": "10000ms" 11 | }, 12 | "jvm-options": { 13 | "initial_heap_size": "512M", 14 | "max_heap_size": "512M" 15 | } 16 | } -------------------------------------------------------------------------------- /tests/upgrade_operator/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # This is the default kustomize template for tests. 2 | namespace: test-upgrade-operator 3 | 4 | apiVersion: kustomize.config.k8s.io/v1beta1 5 | kind: Kustomization 6 | resources: 7 | - github.com/k8ssandra/cass-operator/config/deployments/default?ref=v1.19.1 8 | -------------------------------------------------------------------------------- /tests/util/lib.go: -------------------------------------------------------------------------------- 1 | // Copyright DataStax, Inc. 2 | // Please see the included license file for details. 3 | 4 | package util 5 | 6 | import ( 7 | "fmt" 8 | "math/rand" 9 | "os" 10 | ) 11 | 12 | func RequireEnv(key string) string { 13 | val := os.Getenv(key) 14 | if val == "" { 15 | msg := fmt.Errorf("%s is a required environment variable", key) 16 | panic(msg) 17 | } 18 | return val 19 | } 20 | 21 | // Attempt to retrieve a value from an environment 22 | // variable if it is set. If not, use specified 23 | // default value 24 | func FromEnvOrDefault(key string, def string) string { 25 | var val string 26 | if v, ok := os.LookupEnv(key); ok { 27 | val = v 28 | } else { 29 | val = def 30 | } 31 | return val 32 | } 33 | 34 | // Attempt to retrieve a value from an environment 35 | // variable if it is set. If not, use fallback 36 | // function to generate value. 37 | func FromEnvOrF(key string, fallback func() string) string { 38 | var val string 39 | if v, ok := os.LookupEnv(key); ok { 40 | val = v 41 | } else { 42 | val = fallback() 43 | } 44 | return val 45 | } 46 | 47 | func EnvOrDefault(key string, def string) string { 48 | val := os.Getenv(key) 49 | if val == "" { 50 | val = def 51 | } 52 | return val 53 | } 54 | 55 | func PanicOnError(err error) { 56 | if err != nil { 57 | panic(err) 58 | } 59 | } 60 | 61 | // Generates a (non-cryptographically) random hex string of a given length 62 | func RandomHex(length int) string { 63 | hexRunes := []rune("0123456789ABCDEF") 64 | randRunes := make([]rune, length) 65 | for i := range randRunes { 66 | hexIndex := rand.Intn(len(hexRunes)) 67 | randRunes[i] = hexRunes[hexIndex] 68 | } 69 | return string(randRunes) 70 | } 71 | --------------------------------------------------------------------------------