├── .circleci ├── config.yml └── install_sonar-scanner.sh ├── .github ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── feature-request.md │ └── support-question.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── CONTRIBUTING.md ├── Changelog.md ├── Dockerfile ├── LICENSE ├── MAINTAINERS ├── Makefile ├── PROJECT ├── Readme.md ├── THIRD-PARTY.txt ├── api └── v2 │ ├── backrest.go │ ├── cassandrabackup_types.go │ ├── cassandrabackup_types_test.go │ ├── cassandracluster_types.go │ ├── cassandracluster_types_test.go │ ├── cassandrarestore_types.go │ ├── cassandrarestore_types_test.go │ ├── common │ └── test.go │ ├── groupversion_info.go │ ├── testdata │ ├── cassandracluster-1DC.yaml │ ├── cassandracluster-1DC1R1P.yaml │ ├── cassandracluster-2DC.yaml │ ├── cassandracluster-2DC5R.yaml │ ├── cassandracluster-NoTopo.yaml │ └── cassandracluster-TopoDCNoRack.yaml │ └── zz_generated.deepcopy.go ├── cassandra-stress ├── big_stress.yaml ├── cassandra-stress-big.yaml ├── cassandra-stress-huge.yaml ├── cassandra-stress-medium.yaml ├── cassandra-stress-normal.yaml ├── cassandra-stress-pig.yaml ├── cassandra-stress-small.yaml ├── cassandra-stress.yaml ├── huge_stress.yaml ├── medium_stress.yaml ├── normal_stress.yaml └── small_stress.yaml ├── casskop.iml ├── config ├── crd │ ├── bases │ │ ├── db.orange.com_cassandrabackups.yaml │ │ ├── db.orange.com_cassandraclusters.yaml │ │ └── db.orange.com_cassandrarestores.yaml │ ├── kustomization.yaml │ └── kustomizeconfig.yaml ├── manager │ └── manager.yaml ├── rbac │ ├── role.yaml │ ├── role_binding.yaml │ └── service_account.yaml └── samples │ ├── cassandra-configmap-pre-run.yaml │ ├── cassandra-configmap-v1.yaml │ ├── cassandra-configmap-v2.yaml │ ├── cassandracluster-demo-gke-region.yaml │ ├── cassandracluster-demo-gke-zone.yaml │ ├── cassandracluster-demo.yaml │ ├── cassandracluster.yaml │ ├── cc-local.yaml │ ├── gke-storage-ssd-wait.yaml │ ├── gke-storage-standard-wait.yaml │ ├── k3d │ ├── create-k3d-cluster-network-policies.sh │ ├── create-k3d-cluster.sh │ └── setup-requirements.sh │ ├── network-policies.yaml │ ├── prometheus-cassandra-service-monitor.yaml │ ├── prometheus-grafana-cassandra-dashboard-configmap.yaml │ ├── prometheus-grafana-cassandra-dashboard.json │ └── prometheus-values.yaml ├── controllers ├── cassandrabackup │ ├── backup.go │ ├── cassandrabackup_controller.go │ ├── reconcile.go │ ├── reconcile_test.go │ └── scheduler.go ├── cassandracluster │ ├── cassandra_status.go │ ├── cassandra_status_test.go │ ├── cassandra_util.go │ ├── cassandracluster_controller.go │ ├── decommission_test.go │ ├── deploy_cassandra.go │ ├── doc.go │ ├── generator.go │ ├── generator_test.go │ ├── node_operations.go │ ├── node_operations_test.go │ ├── pod.go │ ├── pod_operation.go │ ├── pod_operation_test.go │ ├── pod_test.go │ ├── poddisruptionbudget.go │ ├── pvc.go │ ├── reconcile.go │ ├── reconcile_test.go │ ├── scaleup_test.go │ ├── service.go │ ├── statefulset.go │ ├── statefulset_test.go │ └── testdata │ │ ├── cassandracluster-1DC.yaml │ │ ├── cassandracluster-2DC-configmap.yaml │ │ ├── cassandracluster-2DC-dc1-rack1-sts.yaml │ │ ├── cassandracluster-2DC.yaml │ │ ├── cassandracluster-3DC.yaml │ │ └── cassandracluster-backrest-vol.yaml ├── cassandrarestore │ ├── cassandrarestore_controller.go │ ├── reconcile.go │ ├── reconcile_test.go │ └── status.go └── common │ ├── common_controller.go │ └── testutils.go ├── deploy ├── cassandra │ └── psp.yaml ├── clusterRole-cassie.yaml ├── e2e-ide │ └── namespaced-manifests.yaml ├── psp-cassie.yaml └── psp-sa-cassie.yaml ├── docker ├── bootstrap │ ├── Dockerfile │ ├── Makefile │ ├── README.md │ ├── bootstrap.sh │ ├── dgoss │ │ ├── checks │ │ │ ├── goss.yaml │ │ │ └── goss_wait.yaml │ │ ├── runChecks.sh │ │ ├── test-default │ │ │ └── run.sh │ │ ├── test-with-pre-run │ │ │ ├── goss.yaml │ │ │ ├── pre_run.sh │ │ │ └── run.sh │ │ ├── test-without-volumes │ │ │ ├── goss.yaml │ │ │ ├── goss_wait.yaml │ │ │ └── run.sh │ │ └── util.sh │ └── files │ │ ├── exporter.conf │ │ ├── liveness-probe.sh │ │ ├── readiness-probe.sh │ │ └── run.sh ├── cassandra │ ├── Dockerfile │ └── Makefile └── circleci │ └── Dockerfile ├── documentation ├── backup.md ├── monitoring.md └── uml │ ├── architecture.puml │ └── crd.puml ├── go.mod ├── go.sum ├── hack └── boilerplate.go.txt ├── helm └── cassandra-operator │ ├── .helmignore │ ├── Chart.yaml │ ├── OWNERS │ ├── crds │ ├── db.orange.com_cassandrabackups.yaml │ ├── db.orange.com_cassandraclusters.yaml │ └── db.orange.com_cassandrarestores.yaml │ ├── readme.md │ ├── templates │ ├── NOTES.txt │ ├── _functions.tpl │ ├── deployment.yaml │ ├── role.yaml │ ├── rolebinding.yaml │ ├── service.yaml │ └── service_account.yaml │ └── values.yaml ├── kube.mk ├── main.go ├── monitoring ├── dashboards │ └── cassandra-grafana-dashboard.yaml ├── network-policies │ └── prometheus_net.yaml └── servicemonitor │ ├── prometheus-cassandra-service-monitor.yaml │ └── prometheus-casskop-service-monitor.yaml ├── multi-casskop ├── Dockerfile ├── Makefile ├── PROJECT ├── Readme.md ├── TODO.md ├── api │ └── v2 │ │ ├── cassandramulticluster_types.go │ │ ├── groupversion_info.go │ │ └── zz_generated.deepcopy.go ├── config │ ├── certmanager │ │ ├── certificate.yaml │ │ ├── kustomization.yaml │ │ └── kustomizeconfig.yaml │ ├── crd │ │ ├── bases │ │ │ └── multicluster_v1alpha1_cassandramulticluster_crd.yaml │ │ ├── kustomization.yaml │ │ ├── kustomizeconfig.yaml │ │ └── patches │ │ │ ├── cainjection_in_multicasskops.yaml │ │ │ └── webhook_in_multicasskops.yaml │ ├── default │ │ ├── kustomization.yaml │ │ ├── manager_auth_proxy_patch.yaml │ │ ├── manager_webhook_patch.yaml │ │ └── webhookcainjection_patch.yaml │ ├── manager │ │ ├── kustomization.yaml │ │ └── manager.yaml │ ├── prometheus │ │ ├── kustomization.yaml │ │ └── monitor.yaml │ ├── rbac │ │ ├── auth_proxy_client_clusterrole.yaml │ │ ├── auth_proxy_role.yaml │ │ ├── auth_proxy_role_binding.yaml │ │ ├── auth_proxy_service.yaml │ │ ├── kustomization.yaml │ │ ├── leader_election_role.yaml │ │ ├── leader_election_role_binding.yaml │ │ ├── multicasskop_editor_role.yaml │ │ ├── multicasskop_viewer_role.yaml │ │ ├── role.yaml │ │ ├── role_binding.yaml │ │ └── service_account.yaml │ ├── samples │ │ ├── gke │ │ │ ├── multi-casskop-gke.yaml │ │ │ └── terraform │ │ │ │ ├── cloud-dns.tf │ │ │ │ ├── env │ │ │ │ ├── master.tfvars │ │ │ │ └── slave.tfvars │ │ │ │ ├── gke-cluster.tf │ │ │ │ ├── kubernetes.tf │ │ │ │ ├── main.tf │ │ │ │ ├── nodes-pool.tf │ │ │ │ ├── post_run.sh │ │ │ │ └── pre_run.sh │ │ ├── multi-casskop.yaml │ │ └── multicasskops.db.orange.com_v2_multicasskop.yaml │ └── webhook │ │ ├── kustomization.yaml │ │ ├── kustomizeconfig.yaml │ │ └── service.yaml ├── controllers │ ├── clients.go │ ├── clusters.go │ ├── cmc_utils.go │ └── multi-casskop_controller.go ├── go.mod ├── go.sum ├── hack │ └── boilerplate.go.txt ├── helm │ └── multi-casskop │ │ ├── .helmignore │ │ ├── Chart.yaml │ │ ├── OWNERS │ │ ├── crds │ │ ├── db.orange.com_cassandrabackups.yaml │ │ ├── db.orange.com_cassandraclusters.yaml │ │ ├── db.orange.com_cassandrarestores.yaml │ │ ├── db.orange.com_multicasskops.yaml │ │ └── multicluster_v1alpha1_cassandramulticluster_crd.yaml │ │ ├── readme.md │ │ ├── templates │ │ ├── NOTES.txt │ │ ├── _functions.tpl │ │ ├── deployment.yaml │ │ ├── role.yaml │ │ ├── rolebinding.yaml │ │ ├── service.yaml │ │ └── service_account.yaml │ │ └── values.yaml ├── main.go └── version │ └── version.go ├── pkg ├── backrest │ ├── backrest.go │ └── backrest_test.go ├── cassandrabackup │ ├── client.go │ ├── client_test.go │ ├── common.go │ ├── config.go │ ├── mock_client.go │ ├── operations.go │ └── operations_test.go ├── common │ └── operations │ │ └── operations.go ├── errorfactory │ └── errorfactory.go ├── k8s │ ├── client_util.go │ ├── util.go │ └── util_test.go └── util │ └── util.go ├── plugins └── kubectl-casskop ├── shared.mk ├── static ├── casskop.png └── multi-casskop.png ├── test └── kuttl │ ├── kuttl-test.yaml │ ├── multi-dcs │ ├── 00-assert.yaml │ ├── 00-createCluster.yaml │ ├── 01-addDC.yaml │ ├── 01-assert.yaml │ ├── 02-assert.yaml │ ├── 02-unallowedScaleDown.yaml │ ├── 03-disableReplToDC2.yaml │ ├── 04-assert.yaml │ ├── 04-scaleDownDC2.yaml │ ├── 05-assert.yaml │ └── 05-removeDC.yaml │ ├── operations │ ├── 00-assert.yaml │ ├── 00-createCluster.yaml │ ├── 01-assert.yaml │ ├── 01-rollingRestart.yaml │ ├── 02-assert.yaml │ ├── 02-updateConfigmap.yaml │ ├── 03-assert.yaml │ └── 03-cleanup.yaml │ ├── scaling │ ├── 00-assert.yaml │ ├── 00-createCluster.yaml │ ├── 01-assert.yaml │ ├── 01-scaleUp.yaml │ ├── 02-assert.yaml │ └── 02-scaleDown.yaml │ └── sidecars │ ├── 00-assert.yaml │ └── 00-clusterWithTwoSidecars.yaml ├── tools ├── circleci-get-logs.sh ├── configure-dind-local-storage.sh ├── create_dind_cluster.sh ├── e2e_test_cleanup.sh ├── health │ ├── go.mod │ ├── go.sum │ └── main.go ├── local-provisioner.yaml ├── pre-commit ├── publish_helm_gcs.sh └── storageclass-local-storage.yaml ├── version └── version.go └── website ├── .gitignore ├── README.md ├── babel.config.js ├── blog ├── 2020-01-15-multicasskop_gke.md └── 2020-03-26-dynamics_sidecars_storage.md ├── docs ├── 1_concepts │ ├── 1_introduction.md │ └── 2_design_principes.md ├── 2_setup │ ├── 1_getting_started.md │ ├── 2_install_plugin.md │ ├── 3_multi_casskop.md │ ├── 4_platform_setup │ │ ├── 1_gke.md │ │ └── 2_minikube.md │ └── 5_upgrade_v1_to_v2.md ├── 3_configuration_deployment │ ├── 10_nodes_management.md │ ├── 11_cassandra_cluster_status.md │ ├── 1_customizable_install_with_helm.md │ ├── 2_cassandra_cluster.md │ ├── 3_storage.md │ ├── 4_cluster_topology.md │ ├── 5_cassandra_configuration.md │ ├── 5_sidecars.md │ └── 9_advanced_configuration.md ├── 5_operations │ ├── 0_implementation_architecture.md │ ├── 1_cluster_operations.md │ ├── 2_pods_operations.md │ ├── 3_5_backup_restore.md │ ├── 3_multi_casskop.md │ ├── 4_upgrade_operator.md │ └── 6_uninstall_casskop.md ├── 6_references │ ├── 1_cassandra_cluster.md │ ├── 2_topology.md │ ├── 3_cassandra_cluster_status.md │ ├── 4_multicasskop.md │ ├── 5_cassandra_backup.md │ └── 6_cassandra_restore.md ├── 7_troubleshooting │ ├── 1_operations_issues.md │ └── 2_gke_issues.md └── 8_contributing │ ├── 1_developer_guide.md │ ├── 2_release_guide.md │ ├── 3_reporting_bugs.md │ └── 4_credits.md ├── docusaurus.config.js ├── package.json ├── sidebars.js ├── src ├── css │ └── custom.css └── pages │ ├── index.js │ └── styles.module.css ├── static ├── .circleci │ └── config.yml ├── .nojekyll ├── img │ ├── 1_concepts │ │ └── multi-casskop.png │ ├── 3_configuration_deployment │ │ ├── topology-custom-example.png │ │ └── topology-gke-example.png │ ├── 8_contributing │ │ ├── ide_debug_action.png │ │ └── ide_debug_configutation.png │ ├── blog │ │ └── 2020-01-15-multicasskop_gke │ │ │ └── multicasskop_architecture.jpeg │ ├── cassandra.png │ ├── casskop_alone.png │ ├── dc.png │ ├── favicon.ico │ ├── kubernetes.png │ ├── logo.svg │ ├── namespace.png │ ├── open_source.svg │ ├── operator-sdk.png │ ├── orange.jpg │ ├── undraw_docusaurus_mountain.svg │ ├── undraw_docusaurus_react.svg │ └── undraw_docusaurus_tree.svg └── slides │ ├── Makefile │ ├── Slides-CassKop-demo.md │ ├── assets │ ├── dfy-50x53.png │ ├── dfy.png │ ├── edit-50.png │ ├── k8s.puml │ ├── kubernetes-operators │ │ ├── CassandraOperator2.png │ │ ├── cassandra-sts-uml.png │ │ ├── minions.jpeg │ │ ├── topology-custom-example.png │ │ └── topology-gke-example.png │ └── orange-50x50.png │ ├── css │ ├── mermaid.css │ └── remark-orange.css │ ├── home.md │ ├── index.html │ └── js │ ├── Chart.bundle.min.js │ ├── Chart.min.js │ ├── jquery-1.9.1.min.js │ ├── mermaid.min.js │ ├── plantUml.js │ ├── rawdeflate.js │ ├── remark-latest.min.js │ ├── remark-macros.js │ ├── remark-zoom.js │ └── remarkchart.min.js └── yarn.lock /.circleci/install_sonar-scanner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -d sonar-scanner-3.3.0.1492-linux ] 3 | then 4 | echo "Sonar Scanner already cached" 5 | else 6 | curl -o scanner.zip 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-3.3.0.1492-linux.zip' 7 | mkdir sonar-scanner 8 | unzip scanner.zip 9 | chmod +x sonar-scanner-3.3.0.1492-linux/bin/sonar-scanner 10 | fi 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: If things aren't working as expected. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Bug Report 11 | 12 | 18 | 19 | **What did you do?** 20 | A clear and concise description of the steps you took (or insert a code snippet). 21 | 22 | **What did you expect to see?** 23 | A clear and concise description of what you expected to happen (or insert a code snippet). 24 | 25 | **What did you see instead? Under which circumstances?** 26 | A clear and concise description of what you expected to happen (or insert a code snippet). 27 | 28 | 29 | **Environment** 30 | * casskop version: 31 | 32 | 33 | 34 | * go version: 35 | 36 | 37 | 38 | * Kubernetes version information: 39 | 40 | 41 | 42 | * Kubernetes cluster kind: 43 | 44 | * Cassandra version: 45 | 46 | 47 | 48 | **Possible Solution** 49 | 50 | 51 | **Additional context** 52 | Add any other context about the problem here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest a feature 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Feature Request 11 | 12 | **Is your feature request related to a problem? Please describe.** 13 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 14 | 15 | **Describe the solution you'd like to see** 16 | A clear and concise description of what would you like to happen. 17 | 18 | **Describe alternatives you've considered** 19 | A clear and concise description of any alternative solutions or features you've considered. 20 | 21 | **Additional context** 22 | Add any other context or screenshots about the feature request here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/support-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Support Question 3 | about: Any support questions you might have. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 17 | 18 | ## Type of question 19 | 20 | **Are you asking about community best practices, how to implement a specific feature, or about general context and help around casskop ?** 21 | 22 | 23 | ## Question 24 | 25 | **What did you do?** 26 | A clear and concise description of the steps you took (or insert a code snippet). 27 | 28 | **What did you expect to see?** 29 | A clear and concise description of what you expected to happen (or insert a code snippet). 30 | 31 | **What did you see instead? Under which circumstances?** 32 | A clear and concise description of what you expected to happen (or insert a code snippet). 33 | 34 | 35 | **Environment** 36 | * casskop version: 37 | 38 | insert release or Git SHA here 39 | 40 | * Kubernetes version information: 41 | 42 | insert output of `kubectl version` here 43 | 44 | * Kubernetes cluster kind: 45 | 46 | * Cassandra version: 47 | 48 | 49 | 50 | **Additional context** 51 | Add any other context about the question here. -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | | Q | A 2 | | --------------- | --- 3 | | Bug fix? | [] 4 | | New feature? | [] 5 | | API breaks? | [] 6 | | Deprecations? | [] 7 | | Related tickets | fixes #X, partially #Y, mentioned in #Z 8 | | License | Apache 2.0 9 | 10 | 11 | ### What's in this PR? 12 | 13 | 14 | 15 | ### Why? 16 | 17 | 18 | 19 | ### Additional context 20 | 21 | 22 | 23 | ### Checklist 24 | 25 | 26 | - [ ] Implementation tested 27 | - [ ] Logging code meets the guideline 28 | - [ ] User guide and development docs updated (if needed) 29 | - [ ] Append changelog 30 | 31 | ### To Do 32 | 33 | - [ ] If the PR is not complete but you want to discuss the approach, list what remains to be done here -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.17 as build 2 | 3 | ENV GO111MODULE=on 4 | 5 | RUN useradd -u 1000 casskop 6 | RUN mkdir -p /tmp && chown casskop /tmp 7 | 8 | ADD . /casskop 9 | 10 | WORKDIR /casskop 11 | 12 | RUN go mod download 13 | 14 | # Build 15 | RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o casskop main.go 16 | 17 | FROM gcr.io/distroless/base 18 | 19 | WORKDIR / 20 | COPY --from=build /etc/passwd /etc/passwd 21 | COPY --from=build /tmp /tmp 22 | COPY --from=build /casskop/casskop /usr/local/bin/casskop 23 | USER casskop 24 | 25 | LABEL org.opencontainers.image.documentation="https://github.com/Orange-OpenSource/casskop/blob/master/README.md" 26 | LABEL org.opencontainers.image.authors="Sébastien Allamand " 27 | LABEL org.opencontainers.image.source="https://github.com/Orange-OpenSource/casskop" 28 | LABEL org.opencontainers.image.vendor="Orange France - Digital Factory" 29 | LABEL org.opencontainers.image.version="0.1" 30 | LABEL org.opencontainers.image.description="Operateur des Gestion de Clusters Cassandra" 31 | LABEL org.opencontainers.image.url="https://github.com/Orange-OpenSource/casskop" 32 | LABEL org.opencontainers.image.title="Operateur Cassandra" 33 | 34 | LABEL org.label-schema.usage="https://github.com/Orange-OpenSource/casskop/blob/master/README.md" 35 | LABEL org.label-schema.docker.cmd.devel="N/A" 36 | LABEL org.label-schema.docker.cmd.test="N/A" 37 | LABEL org.label-schema.docker.cmd.help="N/A" 38 | LABEL org.label-schema.docker.cmd.debug="N/A" 39 | LABEL org.label-schema.docker.params="LOG_LEVEL=define loglevel,RESYNC_PERIOD=period in second to execute resynchronisation,WATCH_NAMESPACE=namespace to watch for cassandraclusters,OPERATOR_NAME=name of the operator instance pod" 40 | 41 | 42 | 43 | ENTRYPOINT ["/usr/local/bin/casskop"] 44 | -------------------------------------------------------------------------------- /MAINTAINERS: -------------------------------------------------------------------------------- 1 | # This is the official list of operator-sdk maintainers. 2 | # 3 | # Names should be added to this file like so: 4 | # Individual's name (@GITHUB_HANDLE) 5 | 6 | Sébastien Allamand (@allamand) 7 | Cyril Scetbon (@cscetbon) 8 | Jean Armel Luce (@jal06) 9 | Alexandre Guitton (@erdrix) 10 | Franck Dehay (@fdehay) -------------------------------------------------------------------------------- /PROJECT: -------------------------------------------------------------------------------- 1 | domain: db.orange.com 2 | layout: go.kubebuilder.io/v2 3 | repo: github.com/Orange-OpenSource/casskop 4 | resources: 5 | - group: db.orange.com 6 | kind: CassandraBackup 7 | version: v2 8 | - group: db.orange.com 9 | kind: CassandraCluster 10 | version: v2 11 | - group: db.orange.com 12 | kind: CassandraRestore 13 | version: v2 14 | version: 3-alpha 15 | plugins: 16 | go.operator-sdk.io/v2-alpha: {} 17 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | Logo 2 | 3 | # CassKop is now hosted at https://github.com/cscetbon/casskop 4 | 5 | -------------------------------------------------------------------------------- /THIRD-PARTY.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/THIRD-PARTY.txt -------------------------------------------------------------------------------- /api/v2/backrest.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "fmt" 5 | icarus "github.com/instaclustr/instaclustr-icarus-go-client/pkg/instaclustr_icarus" 6 | "github.com/mitchellh/mapstructure" 7 | "strconv" 8 | ) 9 | 10 | func ProgressPercentage(progress float64) string { 11 | return fmt.Sprintf("%v%%", strconv.Itoa(int(progress*100))) 12 | } 13 | 14 | func failureCause(errors []icarus.ErrorObject) []FailureCause { 15 | var failureCause []FailureCause 16 | mapstructure.Decode(errors, &failureCause) 17 | return failureCause 18 | } 19 | 20 | // BackRestCondition describes the observed state of a Restore at a certain point 21 | type BackRestCondition struct { 22 | Type string `json:"type"` 23 | // +optional 24 | LastTransitionTime string `json:"lastTransitionTime,omitempty"` 25 | // +optional 26 | FailureCause []FailureCause `json:"failureCause,omitempty"` 27 | } 28 | 29 | type BackRestStatus struct { 30 | TimeCreated string `json:"timeCreated,omitempty"` 31 | TimeStarted string `json:"timeStarted,omitempty"` 32 | TimeCompleted string `json:"timeCompleted,omitempty"` 33 | Condition *BackRestCondition `json:"condition,omitempty"` 34 | // Name of the pod the restore operation is executed on 35 | CoordinatorMember string `json:"coordinatorMember,omitempty"` 36 | // Progress is a percentage, 100% means the operation is completed, either successfully or with errors 37 | Progress string `json:"progress,omitempty"` 38 | // unique identifier of an operation, a random id is assigned to each operation after a request is submitted, 39 | // from caller's perspective, an id is sent back as a response to his request so he can further query state of that operation, 40 | // referencing id, by operations/{id} endpoint 41 | ID string `json:"id,omitempty"` 42 | } 43 | 44 | type FailureCause struct { 45 | // hostame of a node where this error has occurred 46 | Source string `json:"source,omitempty"` 47 | // message explaining the error 48 | Message string `json:"message,omitempty"` 49 | } 50 | 51 | -------------------------------------------------------------------------------- /api/v2/cassandrabackup_types_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Orange 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 | 15 | package v2 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/nsf/jsondiff" 21 | "github.com/stretchr/testify/assert" 22 | ) 23 | 24 | func TestValidateSchedule(t *testing.T) { 25 | assert := assert.New(t) 26 | 27 | backupSpec := &CassandraBackupSpec{ 28 | Schedule: "", 29 | } 30 | 31 | for _, schedule := range []string{"@midnight", "1 1 */2 11 *", "@daily"} { 32 | backupSpec.Schedule = schedule 33 | assert.Nilf(backupSpec.ValidateScheduleFormat(), "Schedule %s should be parseable", schedule) 34 | } 35 | 36 | backupSpec.Schedule = "@noon" // Unknown descriptor 37 | assert.NotNilf(backupSpec.ValidateScheduleFormat(), "Schedule %s should not be parseable", backupSpec.Schedule) 38 | } 39 | 40 | func TestCassandraBackupComputeLastAppliedConfiguration(t *testing.T) { 41 | assert := assert.New(t) 42 | 43 | backupSpec := &CassandraBackupSpec{ 44 | CassandraCluster: "cluster1", 45 | Datacenter: "dc1", 46 | Schedule: "@weekly", 47 | StorageLocation: "s3://cassie", 48 | SnapshotTag: "weekly", 49 | Entities: "k1.t1, k3.t3", 50 | } 51 | 52 | backup := &CassandraBackup{ 53 | Spec: *backupSpec, 54 | } 55 | 56 | lastAppliedConfiguration, _ := backup.ComputeLastAppliedAnnotation() 57 | result := `{"metadata":{"creationTimestamp":null}, 58 | "spec":{"cassandraCluster":"cluster1","datacenter":"dc1","storageLocation":"s3://cassie", 59 | "schedule":"@weekly","snapshotTag":"weekly","entities":"k1.t1, k3.t3"},"status":{} 60 | }` 61 | 62 | comparison, _ := jsondiff.Compare([]byte(lastAppliedConfiguration), []byte(result), &jsondiff.Options{}) 63 | 64 | assert.Equal(jsondiff.FullMatch, comparison) 65 | } 66 | -------------------------------------------------------------------------------- /api/v2/cassandrarestore_types_test.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Orange-OpenSource/casskop/api/v2/common" 7 | icarus "github.com/instaclustr/instaclustr-icarus-go-client/pkg/instaclustr_icarus" 8 | "github.com/mitchellh/mapstructure" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | const ( 13 | stateGetById = "RUNNING" 14 | operationID = "d3262073-8101-450f-9a11-c851760abd57" 15 | k8sSecretName = "cloud-backup-secrets" 16 | snapshotTag = "SnapshotTag1" 17 | storageLocation = "gcp://bucket/clustername/dcname/nodename" 18 | noDeleteDownloads = false 19 | schemaVersion = "test" 20 | concurrentConnections int32 = 15 21 | ) 22 | 23 | func TestComputeStatusFromRestoreOperation(t *testing.T) { 24 | assert := assert.New(t) 25 | 26 | var restoreOperation icarus.RestoreOperationResponse 27 | 28 | mapstructure.Decode(common.MockRestoreResponse( 29 | noDeleteDownloads, 30 | concurrentConnections, 31 | stateGetById, 32 | snapshotTag, 33 | operationID, 34 | k8sSecretName, 35 | storageLocation, 36 | "TRUNCATE", 37 | schemaVersion), &restoreOperation) 38 | 39 | cs := ComputeRestorationStatus(&restoreOperation) 40 | assert.Equal(BackRestStatus{ 41 | TimeCreated: "2020-06-10T04:53:05.976Z", 42 | TimeStarted: "2020-06-10T05:53:05.976Z", 43 | TimeCompleted: "2020-06-10T06:53:05.976Z", 44 | Condition: &BackRestCondition{ 45 | Type: string(RestoreRunning), 46 | LastTransitionTime: cs.Condition.LastTransitionTime, 47 | }, 48 | Progress: "10%", 49 | ID: operationID, 50 | }, cs) 51 | } 52 | -------------------------------------------------------------------------------- /api/v2/common/test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | func MockRestoreResponse( 4 | noDeleteDownloads bool, 5 | concurrentConnections int32, 6 | state, 7 | snapshotTag, 8 | operationId, 9 | k8sSecretName, 10 | storageLocation, 11 | restorationPhase, 12 | schemaVersion string) map[string]interface{} { 13 | 14 | return map[string]interface{}{ 15 | "type": "restore", 16 | "id": operationId, 17 | "state": state, 18 | "progress": 0.1, 19 | "creationTime": "2020-06-10T04:53:05.976Z", 20 | "startTime": "2020-06-10T05:53:05.976Z", 21 | "completionTime": "2020-06-10T06:53:05.976Z", 22 | "storageLocation": storageLocation, 23 | "concurrentConnections": concurrentConnections, 24 | "cassandraDirectory": "/var/lib/cassandra", 25 | "snapshotTag": snapshotTag, 26 | "entities": "", 27 | "restorationStrategyType": "HARDLINKS", 28 | "restorationPhase": restorationPhase, 29 | "noDeleteDownloads": noDeleteDownloads, 30 | "schemaVersion": schemaVersion, 31 | "k8sNamespace": "default", 32 | "k8sSecretName": k8sSecretName, 33 | "globalRequest": true, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /api/v2/groupversion_info.go: -------------------------------------------------------------------------------- 1 | // Package v2 contains API Schema definitions for the db.orange.com v2 API group 2 | // +kubebuilder:object:generate=true 3 | // +groupName=db.orange.com 4 | package v2 5 | 6 | import ( 7 | "k8s.io/apimachinery/pkg/runtime/schema" 8 | "sigs.k8s.io/controller-runtime/pkg/scheme" 9 | ) 10 | 11 | var ( 12 | // GroupVersion is group version used to register these objects 13 | GroupVersion = schema.GroupVersion{Group: "db.orange.com", Version: "v2"} 14 | 15 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 16 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 17 | 18 | // AddToScheme adds the types in this group-version to the given scheme. 19 | AddToScheme = SchemeBuilder.AddToScheme 20 | ) 21 | -------------------------------------------------------------------------------- /api/v2/testdata/cassandracluster-1DC.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "db.orange.com/v2" 2 | kind: "CassandraCluster" 3 | metadata: 4 | name: cassandra-demo 5 | labels: 6 | cluster: k8s.pic 7 | namespace: ns 8 | spec: 9 | nodesPerRacks: 7 10 | cassandraImage: cassandra:3.11.6 11 | serverVersion: 3.11.7 12 | rollingPartition: 0 13 | dataCapacity: "3Gi" 14 | dataStorageClass: "local-storage" 15 | hardAntiAffinity: false 16 | deletePVC: true 17 | autoPilot: true 18 | resources: 19 | requests: 20 | cpu: '1' 21 | memory: 2Gi 22 | limits: 23 | cpu: '1' 24 | memory: 2Gi 25 | topology: 26 | dc: 27 | - name: online 28 | labels: 29 | location.dfy.orange.com/site : mts 30 | rack: 31 | - name: rack1 32 | labels: 33 | location.dfy.orange.com/street : street1 34 | - name: rack2 35 | labels: 36 | location.dfy.orange.com/street : street2 37 | -------------------------------------------------------------------------------- /api/v2/testdata/cassandracluster-1DC1R1P.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "db.orange.com/v2" 2 | kind: "CassandraCluster" 3 | metadata: 4 | name: cassandra-demo 5 | labels: 6 | cluster: k8s.pic 7 | namespace: ns 8 | spec: 9 | nodesPerRacks: 1 10 | cassandraImage: cassandra:3.11.6 11 | serverVersion: 3.11.7 12 | rollingPartition: 0 13 | dataCapacity: "3Gi" 14 | dataStorageClass: "local-storage" 15 | hardAntiAffinity: false 16 | deletePVC: true 17 | autoPilot: true 18 | resources: 19 | requests: 20 | cpu: '1' 21 | memory: 2Gi 22 | limits: 23 | cpu: '1' 24 | memory: 2Gi 25 | topology: 26 | dc: 27 | - name: online 28 | labels: 29 | location.dfy.orange.com/site : mts 30 | rack: 31 | - name: rack1 32 | labels: 33 | location.dfy.orange.com/street : street1 34 | - name: rack2 35 | labels: 36 | location.dfy.orange.com/street : street2 37 | -------------------------------------------------------------------------------- /api/v2/testdata/cassandracluster-2DC.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "db.orange.com/v2" 2 | kind: "CassandraCluster" 3 | metadata: 4 | name: cassandra-demo 5 | labels: 6 | cluster: k8s.pic 7 | namespace: ns 8 | spec: 9 | nodesPerRacks: 6 10 | cassandraImage: cassandra:3.11.6 11 | serverVersion: 3.11.7 12 | rollingPartition: 0 13 | dataCapacity: "3Gi" 14 | dataStorageClass: "local-storage" 15 | hardAntiAffinity: false 16 | deletePVC: true 17 | config: 18 | jvm-options: 19 | log_gc: "true" 20 | autoPilot: true 21 | resources: 22 | requests: 23 | cpu: '1' 24 | memory: 2Gi 25 | limits: 26 | cpu: '1' 27 | memory: 2Gi 28 | topology: 29 | dc: 30 | - name: online 31 | config: 32 | cassandra-yaml: 33 | num_tokens: 200 34 | labels: 35 | location.dfy.orange.com/site : mts 36 | rack: 37 | - name: rack1 38 | labels: 39 | location.dfy.orange.com/street : street1 40 | - name: rack2 41 | labels: 42 | location.dfy.orange.com/street : street2 43 | - name: stats 44 | config: 45 | cassandra-yaml: 46 | num_tokens: 32 47 | nodesPerRacks: 2 48 | labels: 49 | location.dfy.orange.com/site : mts 50 | rack: 51 | - name: rack1 52 | labels: 53 | location.dfy.orange.com/street : street3 54 | - name: rack2 55 | labels: 56 | location.dfy.orange.com/street : street4 57 | -------------------------------------------------------------------------------- /api/v2/testdata/cassandracluster-2DC5R.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "db.orange.com/v2" 2 | kind: "CassandraCluster" 3 | metadata: 4 | name: cassandra-demo 5 | labels: 6 | cluster: k8s.pic 7 | namespace: ns 8 | spec: 9 | nodesPerRacks: 6 10 | cassandraImage: cassandra:3.11.6 11 | serverVersion: 3.11.7 12 | baseImage: cassandra 13 | version: latest 14 | rollingPartition: 0 15 | dataCapacity: "3Gi" 16 | dataStorageClass: "local-storage" 17 | hardAntiAffinity: false 18 | deletePVC: true 19 | autoPilot: true 20 | resources: 21 | requests: 22 | cpu: '1' 23 | memory: 2Gi 24 | limits: 25 | cpu: '1' 26 | memory: 2Gi 27 | topology: 28 | dc: 29 | - name: online 30 | labels: 31 | location.dfy.orange.com/site : mts 32 | rack: 33 | - name: rack1 34 | labels: 35 | location.dfy.orange.com/street : street1 36 | - name: rack2 37 | labels: 38 | location.dfy.orange.com/street : street2 39 | - name: rack3 40 | labels: 41 | location.dfy.orange.com/street : street3 42 | - name: rack4 43 | labels: 44 | location.dfy.orange.com/street : street4 45 | - name: rack5 46 | labels: 47 | location.dfy.orange.com/street : street5 48 | - name: stats 49 | nodesPerRacks: 2 50 | labels: 51 | location.dfy.orange.com/site : mts 52 | rack: 53 | - name: rack1 54 | labels: 55 | location.dfy.orange.com/street : street11 56 | - name: rack2 57 | labels: 58 | location.dfy.orange.com/street : street12 59 | - name: rack3 60 | labels: 61 | location.dfy.orange.com/street : street13 62 | - name: rack4 63 | labels: 64 | location.dfy.orange.com/street : street14 65 | -------------------------------------------------------------------------------- /api/v2/testdata/cassandracluster-NoTopo.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "db.orange.com/v2" 2 | kind: "CassandraCluster" 3 | metadata: 4 | name: cassandra-demo 5 | labels: 6 | cluster: k8s.pic 7 | namespace: ns 8 | spec: 9 | nodesPerRacks: 8 10 | cassandraImage: cassandra:3.11.6 11 | serverVersion: 3.11.7 12 | rollingPartition: 0 13 | dataCapacity: "3Gi" 14 | dataStorageClass: "local-storage" 15 | hardAntiAffinity: false 16 | deletePVC: true 17 | autoPilot: true 18 | resources: 19 | requests: 20 | cpu: '1' 21 | memory: 2Gi 22 | limits: 23 | cpu: '1' 24 | memory: 2Gi 25 | -------------------------------------------------------------------------------- /api/v2/testdata/cassandracluster-TopoDCNoRack.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "db.orange.com/v2" 2 | kind: "CassandraCluster" 3 | metadata: 4 | name: cassandra-demo 5 | labels: 6 | cluster: k8s.pic 7 | namespace: ns 8 | spec: 9 | nodesPerRacks: 8 10 | cassandraImage: cassandra:3.11.6 11 | serverVersion: 3.11.7 12 | rollingPartition: 0 13 | dataCapacity: "3Gi" 14 | dataStorageClass: "local-storage" 15 | hardAntiAffinity: false 16 | deletePVC: true 17 | autoPilot: true 18 | resources: 19 | requests: 20 | cpu: '1' 21 | memory: 2Gi 22 | limits: 23 | cpu: '1' 24 | memory: 2Gi 25 | topology: 26 | dc: 27 | - name: online 28 | -------------------------------------------------------------------------------- /cassandra-stress/big_stress.yaml: -------------------------------------------------------------------------------- 1 | keyspace: bench 2 | 3 | keyspace_definition: | 4 | CREATE KEYSPACE IF NOT EXISTS bench WITH REPLICATION = {'class': 'NetworkTopologyStrategy', 'dc1': '3'}; 5 | 6 | table: big_table 7 | 8 | table_definition: | 9 | CREATE TABLE IF NOT EXISTS bench.big_table ( 10 | id blob, 11 | sub_id blob, 12 | rec_type text, 13 | value double, 14 | time bigint, 15 | PRIMARY KEY (sub_id, time) 16 | ) WITH CLUSTERING ORDER BY (time DESC) 17 | AND bloom_filter_fp_chance = 0.1 18 | AND caching = {'keys':'ALL', 'rows_per_partition':'NONE'} 19 | AND comment = '' 20 | AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy'} 21 | AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'} 22 | AND dclocal_read_repair_chance = 0.05 23 | AND default_time_to_live = 0 24 | AND gc_grace_seconds = 1555200 25 | AND max_index_interval = 2048 26 | AND memtable_flush_period_in_ms = 0 27 | AND min_index_interval = 128 28 | AND read_repair_chance = 0.01 29 | AND speculative_retry = '99.0PERCENTILE'; 30 | 31 | columnspec: 32 | - name: id 33 | population: seq(1..100m) # 100 Millions potential ids size: fixed(16) 34 | - name: rec_type 35 | size: uniform(10..20) # rec_type is 10-20 chars 36 | population: uniform(1..10) # there are 10 types of rec_type 37 | - name: sub_id 38 | size: fixed(16) 39 | population: seq(1..100m) # 100 Millions unique machines 40 | - name: value 41 | population: gaussian(0..1000) # values range from 0-1000 and follow a gaussian distribution 42 | - name: time 43 | cluster: fixed(10) # 10 values updates per machine 44 | population: seq(0..99) 45 | 46 | ### Batch Ratio Distribution Specifications ### 47 | insert: 48 | partitions: fixed(1) 49 | # select: fixed(1)/100 # Inserts will be single row 50 | batchtype: UNLOGGED 51 | 52 | # A list of queries you wish to run against the schema # 53 | queries: 54 | query_by_sub_id: 55 | cql: SELECT sub_id, value, time FROM big_table WHERE sub_id = ? and time >= 90 LIMIT 10 56 | fields: samerow 57 | -------------------------------------------------------------------------------- /cassandra-stress/cassandra-stress-big.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: cassandra-stress-big 6 | labels: 7 | app: cassandra-stress 8 | spec: 9 | restartPolicy: Never 10 | volumes: 11 | - name: cassandra-stress-profile-volume 12 | configMap: 13 | name: cassandra-stress-big 14 | securityContext: 15 | fsGroup: 1 16 | runAsNonRoot: true 17 | runAsUser: 1006 18 | supplementalGroups: 19 | - 1 20 | containers: 21 | - name: cassie1-cassandra-stress 22 | image: cassandra 23 | imagePullPolicy: "IfNotPresent" 24 | securityContext: 25 | capabilities: 26 | add: ["IPC_LOCK"] 27 | command: ["/bin/sh"] 28 | args: ["-c", "cassandra-stress 'user profile=/opt/cassandra-stress/big_stress.yaml ops(insert=10,query_by_sub_id=8) duration=120m cl=one -node cassandra-demo -mode native cql3 user=bench password=monbench -rate threads=60 -pop seq=0..100M -tokenrange -graph file=/tmp/stress-big.html' && echo END && while true ; do sleep 60; done"] 29 | resources: 30 | limits: 31 | cpu: "8" 32 | memory: 32Gi 33 | requests: 34 | cpu: "8" 35 | memory: 32Gi 36 | volumeMounts: 37 | - name: cassandra-stress-profile-volume 38 | mountPath: /opt/cassandra-stress 39 | -------------------------------------------------------------------------------- /cassandra-stress/cassandra-stress-huge.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: cassandra-stress-huge 6 | labels: 7 | app: cassandra-stress 8 | spec: 9 | restartPolicy: Never 10 | volumes: 11 | - name: cassandra-stress-profile-volume 12 | configMap: 13 | name: cassandra-stress-huge 14 | securityContext: 15 | fsGroup: 1 16 | runAsNonRoot: true 17 | runAsUser: 1006 18 | supplementalGroups: 19 | - 1 20 | containers: 21 | - name: cassie1-cassandra-stress 22 | image: cassandra 23 | imagePullPolicy: "IfNotPresent" 24 | securityContext: 25 | capabilities: 26 | add: ["IPC_LOCK"] 27 | command: ["/bin/sh"] 28 | args: ["-c", "cassandra-stress 'user profile=/opt/cassandra-stress/huge_stress.yaml ops(insert=10,query_by_sub_id=10) duration=90m cl=one -node cassandra-demo -mode native cql3 user=bench password=monbench -rate threads=50 -pop seq=0..50m -graph file=/tmp/stress-huge1.html' && echo END && while true ; do sleep 60; done"] 29 | resources: 30 | limits: 31 | cpu: "8" 32 | memory: 32Gi 33 | requests: 34 | cpu: "8" 35 | memory: 32Gi 36 | volumeMounts: 37 | - name: cassandra-stress-profile-volume 38 | mountPath: /opt/cassandra-stress 39 | - name: cassie2-cassandra-stress 40 | image: cassandra 41 | imagePullPolicy: "IfNotPresent" 42 | securityContext: 43 | capabilities: 44 | add: ["IPC_LOCK"] 45 | command: ["/bin/sh"] 46 | args: ["-c", "cassandra-stress 'user profile=/opt/cassandra-stress/huge_stress.yaml ops(insert=10) n=50m cl=one -node cassandra-demo-dc1.cassandra-demo -mode native cql3 user=cassandra password=cassandra -rate threads=50 -pop seq=50000001..100m -graph file=/tmp/stress-huge2.html' && echo END && while true ; do sleep 60; done"] 47 | resources: 48 | limits: 49 | cpu: "8" 50 | memory: 32Gi 51 | requests: 52 | cpu: "8" 53 | memory: 32Gi 54 | volumeMounts: 55 | - name: cassandra-stress-profile-volume 56 | mountPath: /opt/cassandra-stress 57 | -------------------------------------------------------------------------------- /cassandra-stress/cassandra-stress-medium.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: cassandra-stress-medium 6 | labels: 7 | app: cassandra-stress 8 | spec: 9 | restartPolicy: Never 10 | volumes: 11 | - name: cassandra-stress-profile-volume 12 | configMap: 13 | name: cassandra-stress-medium 14 | securityContext: 15 | fsGroup: 1 16 | runAsNonRoot: true 17 | runAsUser: 1000 18 | supplementalGroups: 19 | - 1 20 | containers: 21 | - name: cassie1-cassandra-stress 22 | image: cassandra 23 | imagePullPolicy: "IfNotPresent" 24 | securityContext: 25 | capabilities: 26 | add: ["IPC_LOCK"] 27 | command: ["/bin/sh"] 28 | args: ["-c", "cassandra-stress 'user profile=/opt/cassandra-stress/medium_stress.yaml ops(insert=1,query_by_sub_id=1) n=5m cl=one -node cassandra-demo -mode native cql3 user=cassandra password=cassandra -rate threads=50 -pop seq=0..5m -graph file=/tmp/stress-medium1.html' && echo END && while true ; do sleep 60; done"] 29 | resources: 30 | limits: 31 | cpu: "8" 32 | memory: 32Gi 33 | requests: 34 | cpu: "8" 35 | memory: 32Gi 36 | volumeMounts: 37 | - name: cassandra-stress-profile-volume 38 | mountPath: /opt/cassandra-stress 39 | - name: cassie2-cassandra-stress 40 | image: cassandra 41 | imagePullPolicy: "IfNotPresent" 42 | securityContext: 43 | capabilities: 44 | add: ["IPC_LOCK"] 45 | command: ["/bin/sh"] 46 | args: ["-c", "cassandra-stress 'user profile=/opt/cassandra-stress/medium_stress.yaml ops(insert=1) n=5m cl=one -node cassandra-demo -mode native cql3 user=cassandra password=cassandra -rate threads=50 -pop seq=5000001..10m -graph file=/tmp/stress-medium2.html' && echo END && while true ; do sleep 60; done"] 47 | resources: 48 | limits: 49 | cpu: "8" 50 | memory: 32Gi 51 | requests: 52 | cpu: "8" 53 | memory: 32Gi 54 | volumeMounts: 55 | - name: cassandra-stress-profile-volume 56 | mountPath: /opt/cassandra-stress 57 | -------------------------------------------------------------------------------- /cassandra-stress/cassandra-stress-normal.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: cassandra-stress-normal 6 | labels: 7 | app: cassandra-stress 8 | spec: 9 | restartPolicy: Never 10 | volumes: 11 | - name: cassandra-stress-profile-volume 12 | configMap: 13 | name: cassandra-stress-normal 14 | securityContext: 15 | fsGroup: 1 16 | runAsNonRoot: true 17 | runAsUser: 1006 18 | supplementalGroups: 19 | - 1 20 | containers: 21 | - name: cassie1-cassandra-stress 22 | image: cassandra 23 | imagePullPolicy: "IfNotPresent" 24 | securityContext: 25 | capabilities: 26 | add: ["IPC_LOCK"] 27 | command: ["/bin/sh"] 28 | args: ["-c", "cassandra-stress 'user profile=/opt/cassandra-stress/normal_stress.yaml ops(insert=10,query_by_sub_id=8) duration=120m cl=one -node cassandra-demo -mode native cql3 user=bench password=monbench -rate threads=30 -pop seq=0..100M -tokenrange -graph file=/tmp/stress-normal.html' && echo END && while true ; do sleep 60; done"] 29 | resources: 30 | limits: 31 | cpu: "3" 32 | memory: 8Gi 33 | requests: 34 | cpu: "3" 35 | memory: 8Gi 36 | volumeMounts: 37 | - name: cassandra-stress-profile-volume 38 | mountPath: /opt/cassandra-stress 39 | -------------------------------------------------------------------------------- /cassandra-stress/cassandra-stress-pig.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: cassandra-stress-pig 6 | labels: 7 | app: cassandra-stress 8 | spec: 9 | restartPolicy: Never 10 | volumes: 11 | - name: cassandra-stress-profile-volume 12 | configMap: 13 | name: cassandra-stress-pig 14 | securityContext: 15 | fsGroup: 1 16 | runAsNonRoot: true 17 | runAsUser: 1006 18 | supplementalGroups: 19 | - 1 20 | containers: 21 | - name: cassie1-cassandra-stress 22 | image: cassandra 23 | imagePullPolicy: "IfNotPresent" 24 | securityContext: 25 | capabilities: 26 | add: ["IPC_LOCK"] 27 | command: ["/bin/sh"] 28 | args: ["-c", "cassandra-stress 'user profile=/opt/cassandra-stress/pig_stress.yaml ops(insert=1,likelyquery0=1) duration=60m cl=local_one -node cassandra-demo -mode native cql3 user=bench password=monbench -rate threads=30 -graph file=/tmp/stress-pig.html' && echo END && while true ; do sleep 60; done"] 29 | resources: 30 | limits: 31 | cpu: "32" 32 | memory: 32Gi 33 | requests: 34 | cpu: "16" 35 | memory: 32Gi 36 | volumeMounts: 37 | - name: cassandra-stress-profile-volume 38 | mountPath: /opt/cassandra-stress 39 | -------------------------------------------------------------------------------- /cassandra-stress/cassandra-stress-small.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: cassandra-stress-small 6 | labels: 7 | app: cassandra-stress 8 | spec: 9 | restartPolicy: Never 10 | volumes: 11 | - name: cassandra-stress-profile-volume 12 | configMap: 13 | name: cassandra-stress-small 14 | securityContext: 15 | fsGroup: 1 16 | runAsNonRoot: true 17 | runAsUser: 1000 18 | supplementalGroups: 19 | - 1 20 | containers: 21 | - name: cassie1-cassandra-stress 22 | image: cassandra 23 | imagePullPolicy: "IfNotPresent" 24 | securityContext: 25 | capabilities: 26 | add: ["IPC_LOCK"] 27 | command: ["/bin/sh"] 28 | args: ["-c", "cassandra-stress 'user profile=/opt/cassandra-stress/small_stress.yaml ops(insert=2,query_by_sub_id=1) duration=1m cl=one -node cassandra-demo -mode native cql3 user=cassandra password=cassandra -rate threads=20 -pop seq=0..1M -graph file=/tmp/stress-small.html' && echo END && while true ; do sleep 60; done"] 29 | resources: 30 | limits: 31 | cpu: 1 32 | memory: 2Gi 33 | requests: 34 | cpu: 1 35 | memory: 2Gi 36 | volumeMounts: 37 | - name: cassandra-stress-profile-volume 38 | mountPath: /opt/cassandra-stress 39 | -------------------------------------------------------------------------------- /cassandra-stress/cassandra-stress.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: cassandra-stress 6 | spec: 7 | containers: 8 | - name: cassandra-stress 9 | image: "cassandra" 10 | imagePullPolicy: "IfNotPresent" 11 | command: ["cassandra-stress", "user", "profile=/opt/cassandra-stress/cass_insert_bac.yaml", 12 | "ops(insert=3,read1=1)", "-node cassandra-bench-online-rack1-0.cassandra-bench-online-rack1", 13 | "-mode native cql3", "-rate threads=1"] 14 | resources: 15 | limits: 16 | cpu: 2 17 | memory: 4Gi 18 | requests: 19 | cpu: 2 20 | memory: 4Gi 21 | volumeMounts: 22 | - name: cassandra-stress-profile-volume 23 | mountPath: /opt/cassandra-stress 24 | volumes: 25 | - name: cassandra-stress-profile-volume 26 | configMap: 27 | name: cassandra-stress-insert-bac 28 | restartPolicy: Never 29 | 30 | -------------------------------------------------------------------------------- /cassandra-stress/medium_stress.yaml: -------------------------------------------------------------------------------- 1 | keyspace: bench 2 | 3 | keyspace_definition: | 4 | CREATE KEYSPACE IF NOT EXISTS bench WITH REPLICATION = {'class': 'NetworkTopologyStrategy', 'dc1': '3'}; 5 | 6 | table: medium_table 7 | 8 | table_definition: | 9 | CREATE TABLE IF NOT EXISTS bench.medium_table ( 10 | id blob, 11 | sub_id blob, 12 | rec_type text, 13 | value double, 14 | time bigint, 15 | PRIMARY KEY (sub_id, time) 16 | ) WITH CLUSTERING ORDER BY (time DESC) 17 | AND bloom_filter_fp_chance = 0.1 18 | AND caching = {'keys':'ALL', 'rows_per_partition':'NONE'} 19 | AND comment = '' 20 | AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy'} 21 | AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'} 22 | AND dclocal_read_repair_chance = 0.05 23 | AND default_time_to_live = 0 24 | AND gc_grace_seconds = 1555200 25 | AND max_index_interval = 2048 26 | AND memtable_flush_period_in_ms = 0 27 | AND min_index_interval = 128 28 | AND read_repair_chance = 0.01 29 | AND speculative_retry = '99.0PERCENTILE'; 30 | 31 | columnspec: 32 | - name: id 33 | population: seq(1..100m) # 100 Millions potential ids size: fixed(16) 34 | - name: rec_type 35 | size: uniform(10..20) # rec_type is 10-20 chars 36 | population: uniform(1..10) # there are 10 types of rec_type 37 | - name: sub_id 38 | size: fixed(16) 39 | population: seq(1..100m) # 100 Millions unique machines 40 | - name: value 41 | population: gaussian(0..1000) # values range from 0-1000 and follow a gaussian distribution 42 | - name: time 43 | cluster: fixed(10) # 10 values updates per machine 44 | population: seq(0..99) 45 | 46 | ### Batch Ratio Distribution Specifications ### 47 | insert: 48 | partitions: fixed(1) 49 | # select: fixed(1)/100 # Inserts will be single row 50 | batchtype: UNLOGGED 51 | 52 | # A list of queries you wish to run against the schema # 53 | queries: 54 | query_by_sub_id: 55 | cql: SELECT sub_id, value, time FROM medium_table WHERE sub_id = ? and time >= 90 LIMIT 10 56 | fields: samerow 57 | -------------------------------------------------------------------------------- /cassandra-stress/normal_stress.yaml: -------------------------------------------------------------------------------- 1 | keyspace: bench 2 | 3 | keyspace_definition: | 4 | CREATE KEYSPACE IF NOT EXISTS bench WITH REPLICATION = {'class': 'NetworkTopologyStrategy', 'dc1': '3'}; 5 | 6 | table: normal_table 7 | 8 | table_definition: | 9 | CREATE TABLE IF NOT EXISTS bench.normal_table ( 10 | id blob, 11 | sub_id blob, 12 | value double, 13 | PRIMARY KEY (sub_id) 14 | ) WITH bloom_filter_fp_chance = 0.1 15 | AND caching = {'keys':'ALL', 'rows_per_partition':'NONE'} 16 | AND comment = '' 17 | AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy'} 18 | AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'} 19 | AND dclocal_read_repair_chance = 0.05 20 | AND default_time_to_live = 0 21 | AND gc_grace_seconds = 1555200 22 | AND max_index_interval = 2048 23 | AND memtable_flush_period_in_ms = 0 24 | AND min_index_interval = 128 25 | AND read_repair_chance = 0.01 26 | AND speculative_retry = '99.0PERCENTILE'; 27 | 28 | columnspec: 29 | - name: id 30 | population: seq(1..100m) # 100 Millions potential ids size: fixed(16) 31 | - name: sub_id 32 | size: fixed(16) 33 | population: seq(1..100m) # 100 Miullions unique machines 34 | - name: value 35 | population: gaussian(0..1000) # values range from 0-1000 and follow a gaussian distribution 36 | 37 | ### Batch Ratio Distribution Specifications ### 38 | insert: 39 | partitions: fixed(1) 40 | # select: fixed(1)/100 # Inserts will be single row 41 | batchtype: UNLOGGED 42 | 43 | # A list of queries you wish to run against the schema # 44 | queries: 45 | query_by_sub_id: 46 | cql: SELECT sub_id, value FROM normal_table WHERE sub_id = ? LIMIT 10 47 | fields: samerow 48 | -------------------------------------------------------------------------------- /cassandra-stress/small_stress.yaml: -------------------------------------------------------------------------------- 1 | keyspace: bench 2 | 3 | keyspace_definition: | 4 | CREATE KEYSPACE IF NOT EXISTS bench WITH REPLICATION = {'class': 'NetworkTopologyStrategy', 'dc1': '3'}; 5 | 6 | table: small_table 7 | 8 | table_definition: | 9 | CREATE TABLE IF NOT EXISTS bench.small_table ( 10 | id blob, 11 | sub_id blob, 12 | value double, 13 | PRIMARY KEY (sub_id) 14 | ) WITH bloom_filter_fp_chance = 0.1 15 | AND caching = {'keys':'ALL', 'rows_per_partition':'NONE'} 16 | AND comment = '' 17 | AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy'} 18 | AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'} 19 | AND dclocal_read_repair_chance = 0.05 20 | AND default_time_to_live = 0 21 | AND gc_grace_seconds = 1555200 22 | AND max_index_interval = 2048 23 | AND memtable_flush_period_in_ms = 0 24 | AND min_index_interval = 128 25 | AND read_repair_chance = 0.01 26 | AND speculative_retry = '99.0PERCENTILE'; 27 | 28 | columnspec: 29 | - name: id 30 | population: seq(1..1m) # 200 000 potential ids size: fixed(16) 31 | - name: sub_id 32 | size: fixed(16) 33 | population: seq(1..1m) # 200 000 unique machines 34 | - name: value 35 | population: gaussian(0..1000) # values range from 0-1000 and follow a gaussian distribution 36 | 37 | ### Batch Ratio Distribution Specifications ### 38 | insert: 39 | partitions: fixed(1) 40 | # select: fixed(1)/100 # Inserts will be single row 41 | batchtype: UNLOGGED 42 | 43 | # A list of queries you wish to run against the schema # 44 | queries: 45 | query_by_sub_id: 46 | cql: SELECT sub_id, value FROM small_table WHERE sub_id = ? LIMIT 10 47 | fields: samerow 48 | -------------------------------------------------------------------------------- /casskop.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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/db.orange.com_cassandrabackups.yaml 6 | - bases/db.orange.com_cassandraclusters.yaml 7 | - bases/db.orange.com_cassandrarestores.yaml 8 | # +kubebuilder:scaffold:crdkustomizeresource 9 | 10 | # the following config is for teaching kustomize how to do kustomization for CRDs. 11 | configurations: 12 | - kustomizeconfig.yaml 13 | -------------------------------------------------------------------------------- /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 | group: apiextensions.k8s.io 8 | path: spec/conversion/webhookClientConfig/service/name 9 | 10 | namespace: 11 | - kind: CustomResourceDefinition 12 | group: apiextensions.k8s.io 13 | path: spec/conversion/webhookClientConfig/service/namespace 14 | create: false 15 | 16 | varReference: 17 | - path: metadata/annotations 18 | -------------------------------------------------------------------------------- /config/manager/manager.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: casskop 5 | labels: 6 | app: casskop 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | name: casskop 12 | template: 13 | metadata: 14 | labels: 15 | name: casskop 16 | app: casskop 17 | spec: 18 | serviceAccountName: casskop 19 | securityContext: 20 | runAsUser: 1000 21 | containers: 22 | - name: casskop 23 | # Replace this with the built image name 24 | image: REPLACE_IMAGE 25 | ports: 26 | - containerPort: 60000 27 | name: metrics 28 | livenessProbe: 29 | httpGet: 30 | path: /healthz 31 | port: 8081 32 | initialDelaySeconds: 15 33 | periodSeconds: 20 34 | readinessProbe: 35 | httpGet: 36 | path: /readyz 37 | port: 8081 38 | initialDelaySeconds: 5 39 | periodSeconds: 10 40 | command: 41 | - casskop 42 | imagePullPolicy: Always 43 | env: 44 | - name: WATCH_NAMESPACE 45 | valueFrom: 46 | fieldRef: 47 | fieldPath: metadata.namespace 48 | - name: POD_NAME 49 | valueFrom: 50 | fieldRef: 51 | fieldPath: metadata.name 52 | - name: OPERATOR_NAME 53 | value: "casskop" 54 | -------------------------------------------------------------------------------- /config/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: Role 3 | metadata: 4 | creationTimestamp: null 5 | name: casskop 6 | rules: 7 | - apiGroups: 8 | - db.orange.com 9 | resources: 10 | - '*' 11 | - cassandraclusters 12 | verbs: 13 | - '*' 14 | - apiGroups: 15 | - "" 16 | resources: 17 | - pods 18 | - pods/exec 19 | - services 20 | - endpoints 21 | - persistentvolumeclaims 22 | - events 23 | - configmaps 24 | - secrets 25 | verbs: 26 | - '*' 27 | - apiGroups: 28 | - "" 29 | resources: 30 | - namespaces 31 | verbs: 32 | - get 33 | - apiGroups: 34 | - apps 35 | resources: 36 | - deployments 37 | - daemonsets 38 | - replicasets 39 | - statefulsets 40 | verbs: 41 | - '*' 42 | - apiGroups: 43 | - policy 44 | resources: 45 | - poddisruptionbudgets 46 | verbs: 47 | - '*' 48 | - apiGroups: 49 | - monitoring.coreos.com 50 | resources: 51 | - servicemonitors 52 | verbs: 53 | - get 54 | - create 55 | - apiGroups: 56 | - apps 57 | resourceNames: 58 | - casskop 59 | resources: 60 | - deployments/finalizers 61 | verbs: 62 | - update 63 | -------------------------------------------------------------------------------- /config/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | kind: RoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: casskop 5 | subjects: 6 | - kind: ServiceAccount 7 | name: casskop 8 | roleRef: 9 | kind: Role 10 | name: casskop 11 | apiGroup: rbac.authorization.k8s.io 12 | -------------------------------------------------------------------------------- /config/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: casskop 5 | --- 6 | apiVersion: v1 7 | kind: ServiceAccount 8 | metadata: 9 | name: cassandra-cluster-node 10 | -------------------------------------------------------------------------------- /config/samples/cassandra-configmap-pre-run.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: cassandra-configmap-pre-run 5 | data: 6 | pre_run.sh: |- 7 | echo "** this is a pre-scrip for run.sh that can be edit with configmap" 8 | test "$(hostname)" == 'cassandra-demo-dc1-rack1-0' && echo "do specific action there" 9 | test "$(hostname)" == 'cassandra-demo-dc1-rack1-1' && echo "sleep 60" && sleep 60 10 | echo "** end of pre_run.sh script, continue with run.sh" 11 | 12 | -------------------------------------------------------------------------------- /config/samples/cassandra-configmap-v1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: cassandra-configmap-v1 5 | data: 6 | 7 | pre_run.sh: |- 8 | echo " ** this is pre_run.sh script executed before run.sh **" 9 | #Examples: 10 | echo "Change default Authenticator & Authorizer" 11 | sed -ri 's/(authenticator:).*/\1 PasswordAuthenticator/' /etc/cassandra/cassandra.yaml 12 | sed -ri 's/(authorizer:).*/\1 CassandraAuthorizer/' /etc/cassandra/cassandra.yaml 13 | #test "$(hostname)" == 'cassandra-demo-dc1-rack2-0' && echo "update param" && sed -i 's/windows_timer_interval: 1/windows_timer_interval: 2/' /etc/cassandra/cassandra.yaml 14 | #test "$(hostname)" == 'cassandra-demo-dc1-rack3-0' && echo "-Dcassandra.replace_address_first_boot=172.31.183.209" > /etc/cassandra/jvm.options 15 | #test "$(hostname)" == 'cassandra-demo-dc2-rack1-0' && echo "-Dcassandra.override_decommission=true" > /etc/cassandra/jvm.options 16 | echo " ** end of pre_run.sh script, continue with run.sh **" 17 | 18 | post_run.sh: |- 19 | echo "Check Configured seeds by bootstrap" 20 | grep "seeds:" /etc/cassandra/cassandra.yaml 21 | -------------------------------------------------------------------------------- /config/samples/cassandracluster-demo-gke-region.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: jolokia-auth 5 | type: Opaque 6 | data: 7 | password: TTBucDQ1NXcwcmQ= 8 | username: am9sb2tpYS11c2Vy 9 | --- 10 | apiVersion: "db.orange.com/v2" 11 | kind: "CassandraCluster" 12 | metadata: 13 | name: cassandra-demo 14 | labels: 15 | cluster: k8s.kaas 16 | spec: 17 | cassandraImage: cassandra 18 | configMapName: cassandra-configmap-v1 19 | dataCapacity: "20Gi" 20 | dataStorageClass: "standard-wait" 21 | imagepullpolicy: IfNotPresent 22 | imageJolokiaSecret: 23 | name: jolokia-auth 24 | hardAntiAffinity: false # Do we ensure only 1 cassandra on each node ? 25 | deletePVC: true 26 | autoPilot: false 27 | config: 28 | jvm-options: 29 | log_gc: "true" 30 | autoUpdateSeedList: false 31 | maxPodUnavailable: 1 32 | runAsUser: 1000 33 | resources: 34 | requests: 35 | cpu: '1' 36 | memory: 2Gi 37 | limits: 38 | cpu: '1' 39 | memory: 2Gi 40 | topology: 41 | dc: 42 | - name: dc1 43 | nodesPerRacks: 1 44 | config: 45 | cassandra-yaml: 46 | num_tokens: 256 47 | labels: 48 | failure-domain.beta.kubernetes.io/region: europe-west1 49 | rack: 50 | - name: rack1 51 | labels: 52 | failure-domain.beta.kubernetes.io/zone: europe-west1-b 53 | - name: rack2 54 | labels: 55 | failure-domain.beta.kubernetes.io/zone: europe-west1-c 56 | - name: rack3 57 | labels: 58 | failure-domain.beta.kubernetes.io/zone: europe-west1-d 59 | #UNCOMMENT FOR DEMO 60 | # - name: dc2 61 | # nodesPerRacks: 1 62 | # config: 63 | # cassandra-yaml: 64 | # num_tokens: 256 65 | # labels: 66 | # failure-domain.beta.kubernetes.io/region: europe-west1 67 | # rack: 68 | # - name: rack1 69 | # labels: 70 | # failure-domain.beta.kubernetes.io/zone: europe-west1-b 71 | # - name: rack2 72 | # labels: 73 | # failure-domain.beta.kubernetes.io/zone: europe-west1-c 74 | # - name: rack3 75 | # labels: 76 | # failure-domain.beta.kubernetes.io/zone: europe-west1-d 77 | # 78 | -------------------------------------------------------------------------------- /config/samples/cassandracluster-demo-gke-zone.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: jolokia-auth 5 | type: Opaque 6 | data: 7 | password: TTBucDQ1NXcwcmQ= 8 | username: am9sb2tpYS11c2Vy 9 | --- 10 | apiVersion: "db.orange.com/v2" 11 | kind: "CassandraCluster" 12 | metadata: 13 | name: cassandra-demo 14 | labels: 15 | cluster: k8s.kaas 16 | spec: 17 | cassandraImage: cassandra:3.11 18 | configMapName: cassandra-configmap-v1 19 | dataCapacity: "20Gi" 20 | dataStorageClass: "standard-wait" 21 | imagepullpolicy: IfNotPresent 22 | imageJolokiaSecret: 23 | name: jolokia-auth 24 | hardAntiAffinity: false # Do we ensure only 1 cassandra on each node ? 25 | deletePVC: true 26 | autoPilot: false 27 | config: 28 | jvm-options: 29 | log_gc: "true" 30 | autoUpdateSeedList: true 31 | maxPodUnavailable: 1 32 | runAsUser: 999 33 | resources: 34 | requests: 35 | cpu: '1' 36 | memory: 2Gi 37 | limits: 38 | cpu: '1' 39 | memory: 2Gi 40 | topology: 41 | dc: 42 | - name: dc1 43 | nodesPerRacks: 1 44 | numTokens: 256 45 | labels: 46 | failure-domain.beta.kubernetes.io/region: europe-west1 47 | rack: 48 | - name: rack1 49 | labels: 50 | failure-domain.beta.kubernetes.io/zone: europe-west1-b 51 | - name: rack2 52 | labels: 53 | failure-domain.beta.kubernetes.io/zone: europe-west1-b 54 | - name: rack3 55 | labels: 56 | failure-domain.beta.kubernetes.io/zone: europe-west1-b 57 | #UNCOMMENT FOR DEMO 58 | # - name: dc2 59 | # nodesPerRacks: 1 60 | # numTokens: 256 61 | # labels: 62 | # failure-domain.beta.kubernetes.io/region: europe-west1 63 | # rack: 64 | # - name: rack1 65 | # labels: 66 | # failure-domain.beta.kubernetes.io/zone: europe-west1-b 67 | # - name: rack2 68 | # labels: 69 | # failure-domain.beta.kubernetes.io/zone: europe-west1-b 70 | # - name: rack3 71 | # labels: 72 | # failure-domain.beta.kubernetes.io/zone: europe-west1-b 73 | # 74 | -------------------------------------------------------------------------------- /config/samples/cassandracluster-demo.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "db.orange.com/v2" 2 | kind: "CassandraCluster" 3 | metadata: 4 | name: cassandra-demo 5 | labels: 6 | cluster: k8s.kaas 7 | spec: 8 | cassandraImage: cassandra:3.11 9 | configMapName: cassandra-configmap-v1 10 | dataCapacity: "20Gi" 11 | dataStorageClass: "standard" 12 | imagepullpolicy: IfNotPresent 13 | hardAntiAffinity: false # Do we ensure only 1 cassandra on each node ? 14 | deletePVC: true 15 | autoPilot: false 16 | gcStdout: true 17 | autoUpdateSeedList: true 18 | maxPodUnavailable: 1 19 | runAsUser: 1000 20 | resources: 21 | requests: 22 | cpu: '1' 23 | memory: 2Gi 24 | limits: 25 | cpu: '1' 26 | memory: 2Gi 27 | topology: 28 | dc: 29 | - name: dc1 30 | nodesPerRacks: 1 31 | config: 32 | cassandra-yaml: 33 | num_tokens: 256 34 | rack: 35 | - name: rack1 36 | labels: 37 | location.physical/rack : "1" 38 | - name: rack2 39 | labels: 40 | location.physical/rack : "2" 41 | - name: rack3 42 | labels: 43 | location.physical/rack : "3" 44 | - name: dc2 45 | nodesPerRacks: 1 46 | config: 47 | cassandra-yaml: 48 | num_tokens: 256 49 | labels: 50 | failure-domain.beta.kubernetes.io/region: "europe-west1" 51 | failure-domain.beta.kubernetes.io/zone: "europe-west1-b" 52 | rack: 53 | - name: rack1 54 | labels: 55 | location.physical/rack : "1" 56 | - name: rack2 57 | labels: 58 | location.physical/rack : "2" 59 | - name: rack3 60 | labels: 61 | location.physical/rack : "3" 62 | 63 | -------------------------------------------------------------------------------- /config/samples/cassandracluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "db.orange.com/v2" 2 | kind: "CassandraCluster" 3 | metadata: 4 | name: cassandra-demo 5 | labels: 6 | cluster: k8s.kaas 7 | spec: 8 | cassandraImage: cassandra:3.11 9 | bootstrapImage: orangeopensource/cassandra-bootstrap:0.1.8 10 | configMapName: cassandra-configmap-v1 11 | dataCapacity: "200Mi" 12 | dataStorageClass: local-path 13 | imagepullpolicy: IfNotPresent 14 | hardAntiAffinity: false # Do we ensure only 1 cassandra on each node ? 15 | deletePVC: true 16 | autoPilot: false 17 | config: 18 | jvm-options: 19 | log_gc: "true" 20 | autoUpdateSeedList: false 21 | maxPodUnavailable: 1 22 | runAsUser: 999 23 | resources: 24 | requests: 25 | cpu: '1' 26 | memory: 2Gi 27 | limits: 28 | cpu: '1' 29 | memory: 2Gi 30 | topology: 31 | dc: 32 | - name: dc1 33 | nodesPerRacks: 1 34 | rack: 35 | - name: rack1 36 | - name: rack2 37 | - name: rack3 38 | -------------------------------------------------------------------------------- /config/samples/cc-local.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "db.orange.com/v2" 2 | kind: "CassandraCluster" 3 | metadata: 4 | name: cassandra-demo 5 | spec: 6 | nodesPerRacks: 3 7 | cassandraImage: cassandra:3.11 8 | #configMapName: cassandra-jvm-configmap-full 9 | #imagePullSecret: 10 | # name: advisedev # To authenticate on docker registry 11 | rollingPartition: 0 12 | imagePullPolicy: "IfNotPresent" 13 | dataCapacity: "1Gi" 14 | dataStorageClass: local-path 15 | hardAntiAffinity: false 16 | deletePVC: true 17 | autoPilot: true 18 | autoUpdateSeedList: false 19 | resources: 20 | requests: 21 | cpu: '512m' 22 | memory: 512Mi 23 | limits: 24 | cpu: '1' 25 | memory: 1Gi 26 | topology: 27 | dc: 28 | - name: dc1 29 | rack: 30 | - name: rack1 31 | -------------------------------------------------------------------------------- /config/samples/gke-storage-ssd-wait.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | annotations: 5 | storageclass.beta.kubernetes.io/is-default-class: "true" 6 | name: ssd-wait 7 | provisioner: kubernetes.io/gce-pd 8 | volumeBindingMode: "WaitForFirstConsumer" 9 | parameters: 10 | type: pd-ssd 11 | 12 | -------------------------------------------------------------------------------- /config/samples/gke-storage-standard-wait.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | annotations: 5 | storageclass.beta.kubernetes.io/is-default-class: "true" 6 | name: standard-wait 7 | provisioner: kubernetes.io/gce-pd 8 | volumeBindingMode: "WaitForFirstConsumer" 9 | parameters: 10 | # type: pd-ssd 11 | type: pd-standard 12 | 13 | -------------------------------------------------------------------------------- /config/samples/k3d/create-k3d-cluster-network-policies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -o calico.yaml https://raw.githubusercontent.com/rancher/k3d/main/docs/usage/guides/calico.yaml 4 | CLUSTER=local-casskop 5 | k3d cluster delete $CLUSTER 6 | k3d cluster create $CLUSTER --k3s-server-arg '--flannel-backend=none' \ 7 | --volume $PWD/calico.yaml:/var/lib/rancher/k3s/server/manifests/calico.yaml 8 | . $(dirname $0)/setup-requirements.sh 9 | kubectl apply -f $(dirname $0)/../network-policies.yaml 10 | -------------------------------------------------------------------------------- /config/samples/k3d/create-k3d-cluster.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CLUSTER=local-casskop 4 | k3d cluster delete $CLUSTER 5 | k3d cluster create $CLUSTER 6 | . $(dirname $0)/setup-requirements.sh 7 | -------------------------------------------------------------------------------- /config/samples/k3d/setup-requirements.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | kubectx k3d-$CLUSTER 4 | 5 | NAMESPACE=ns1 6 | kubectl create namespace $NAMESPACE 7 | kubens $NAMESPACE 8 | kubectl apply -f config/crd/bases/ 9 | kubectl apply -f config/rbac/service_account.yaml 10 | -------------------------------------------------------------------------------- /config/samples/prometheus-cassandra-service-monitor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | name: prometheus-cassandra 5 | labels: 6 | app: cassandra 7 | release: prometheus-monitoring 8 | spec: 9 | jobLabel: kube-prometheus-cassandra-k8s 10 | selector: 11 | matchLabels: 12 | k8s-app: exporter-cassandra-jmx 13 | namespaceSelector: 14 | any: true 15 | endpoints: 16 | - port: promjmx 17 | interval: 15s 18 | relabelings: 19 | - sourceLabels: [__meta_kubernetes_pod_name] 20 | targetLabel: instance 21 | regex: (.*) 22 | replacement: $1 23 | action: replace 24 | - sourceLabels: [__meta_kubernetes_pod_label_cassandracluster] 25 | targetLabel: cassandra_cluster 26 | regex: (.*) 27 | replacement: $1 28 | action: replace 29 | - sourceLabels: [__meta_kubernetes_pod_label_cassandraclusters_db_orange_com_dc] 30 | targetLabel: cassandra_datacenter 31 | regex: (.*) 32 | replacement: $1 33 | action: replace 34 | - sourceLabels: [__meta_kubernetes_pod_label_cassandraclusters_db_orange_com_rack] 35 | targetLabel: cassandra_rack 36 | regex: (.*) 37 | replacement: $1 38 | action: replace 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /controllers/cassandrabackup/scheduler.go: -------------------------------------------------------------------------------- 1 | package cassandrabackup 2 | 3 | import ( 4 | "fmt" 5 | 6 | api "github.com/Orange-OpenSource/casskop/api/v2" 7 | cron "github.com/robfig/cron/v3" 8 | corev1 "k8s.io/api/core/v1" 9 | "k8s.io/client-go/tools/record" 10 | ) 11 | 12 | type entryType struct { 13 | ID cron.EntryID 14 | Schedule string 15 | } 16 | type Scheduler struct { 17 | entries map[string]entryType 18 | cronClient *cron.Cron 19 | } 20 | 21 | func NewScheduler() Scheduler { 22 | cronClient := cron.New() 23 | cronClient.Start() 24 | return Scheduler{entries: make(map[string]entryType), cronClient: cronClient} 25 | } 26 | 27 | // Contains check if a cron task already exists 28 | func (schedule Scheduler) Contains(backupName string) bool { 29 | _, found := schedule.entries[backupName] 30 | return found 31 | } 32 | 33 | // AddOrUpdate a cron task 34 | func (schedule Scheduler) AddOrUpdate(cassandraBackup *api.CassandraBackup, 35 | task func(), recorder *record.EventRecorder) (skipped bool, err error) { 36 | 37 | backupName := cassandraBackup.Name 38 | 39 | if schedule.Contains(backupName) && schedule.entries[backupName].Schedule == cassandraBackup.Spec.Schedule { 40 | return true, nil 41 | } 42 | 43 | schedule.Remove(backupName) 44 | 45 | entryID, err := schedule.cronClient.AddFunc(cassandraBackup.Spec.Schedule, task) 46 | if err == nil { 47 | schedule.entries[backupName] = entryType{entryID, cassandraBackup.Spec.Schedule} 48 | (*recorder).Event( 49 | cassandraBackup, 50 | corev1.EventTypeNormal, 51 | "BackupTaskscheduled", 52 | fmt.Sprintf("Controller scheduled task %s to back up cluster %s under snapshot %s with schedule %s", 53 | cassandraBackup.Name, cassandraBackup.Spec.CassandraCluster, cassandraBackup.Spec.SnapshotTag, 54 | cassandraBackup.Spec.Schedule)) 55 | } 56 | return false, err 57 | } 58 | 59 | func (schedule Scheduler) Remove(backupName string) { 60 | if schedule.Contains(backupName) { 61 | schedule.cronClient.Remove(schedule.entries[backupName].ID) 62 | delete(schedule.entries, backupName) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /controllers/cassandracluster/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Orange 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 | 15 | // Package cassandra contains the reconciliation logic for the vault Custom Resource. 16 | package cassandracluster 17 | -------------------------------------------------------------------------------- /controllers/cassandracluster/pvc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Orange 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 | 15 | package cassandracluster 16 | 17 | import ( 18 | "context" 19 | 20 | "k8s.io/api/core/v1" 21 | "sigs.k8s.io/controller-runtime/pkg/client" 22 | 23 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 | "k8s.io/apimachinery/pkg/labels" 25 | "k8s.io/apimachinery/pkg/types" 26 | ) 27 | 28 | func (rcc *CassandraClusterReconciler) GetPVC(namespace, name string) (*v1.PersistentVolumeClaim, error) { 29 | 30 | o := &v1.PersistentVolumeClaim{ 31 | TypeMeta: metav1.TypeMeta{ 32 | Kind: "PersistentVolumeClaim", 33 | APIVersion: "v1", 34 | }, 35 | ObjectMeta: metav1.ObjectMeta{ 36 | Name: name, 37 | Namespace: namespace, 38 | }, 39 | } 40 | return o, rcc.Client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: namespace}, o) 41 | } 42 | 43 | func (rcc *CassandraClusterReconciler) ListPVC(namespace string, 44 | selector map[string]string) (*v1.PersistentVolumeClaimList, error) { 45 | 46 | clientOpt := &client.ListOptions{Namespace: namespace, LabelSelector: labels.SelectorFromSet(selector)} 47 | opt := []client.ListOption{ 48 | clientOpt, 49 | } 50 | 51 | o := &v1.PersistentVolumeClaimList{ 52 | TypeMeta: metav1.TypeMeta{ 53 | Kind: "PersistentVolumeClaim", 54 | APIVersion: "v1", 55 | }, 56 | } 57 | 58 | return o, rcc.Client.List(context.TODO(), o, opt...) 59 | } 60 | 61 | func (rcc *CassandraClusterReconciler) deletePVC(pvc *v1.PersistentVolumeClaim) error { 62 | 63 | return rcc.Client.Delete(context.TODO(), pvc) 64 | 65 | } 66 | -------------------------------------------------------------------------------- /controllers/cassandracluster/service.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Orange 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 | 15 | package cassandracluster 16 | 17 | import ( 18 | "context" 19 | 20 | "k8s.io/api/core/v1" 21 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 22 | ) 23 | 24 | func (rcc *CassandraClusterReconciler) DeleteService(namespace, name string) error { 25 | 26 | svc := &v1.Service{ 27 | TypeMeta: metav1.TypeMeta{ 28 | Kind: "Service", 29 | APIVersion: "v1", 30 | }, 31 | ObjectMeta: metav1.ObjectMeta{ 32 | Name: name, 33 | Namespace: namespace, 34 | }, 35 | } 36 | return rcc.Client.Delete(context.TODO(), svc) 37 | } 38 | -------------------------------------------------------------------------------- /controllers/cassandracluster/testdata/cassandracluster-1DC.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-demo 5 | labels: 6 | cluster: k8s.pic 7 | namespace: ns 8 | spec: 9 | dataCapacity: 3Gi 10 | nodesPerRacks: 3 11 | deletePVC: true 12 | autoPilot: true 13 | resources: 14 | limits: &limits 15 | cpu: 1 16 | memory: 2Gi 17 | requests: *limits 18 | topology: 19 | dc: 20 | - name: dc1 21 | rack: 22 | - name: rack1 23 | -------------------------------------------------------------------------------- /controllers/cassandracluster/testdata/cassandracluster-2DC-configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "db.orange.com/v2" 2 | kind: "CassandraCluster" 3 | metadata: 4 | name: cassandra-e2e 5 | labels: 6 | cluster: 2DC-configmap 7 | namespace: ns 8 | spec: 9 | nodesPerRacks: 1 10 | cassandraImage: cassandra:latest 11 | imagePullPolicy: "IfNotPresent" 12 | rollingPartition: 0 13 | configMapName: cassandra-configmap-v1 14 | dataCapacity: "1Gi" 15 | dataStorageClass: "local-storage" 16 | hardAntiAffinity: false 17 | deletePVC: true 18 | autoPilot: true 19 | gcStdout: true 20 | autoUpdateSeedList: false 21 | resources: 22 | requests: &requests 23 | cpu: 500m 24 | memory: 1Gi 25 | limits: *requests 26 | topology: 27 | dc: 28 | - name: dc1 29 | rack: 30 | - name: rack1 31 | - name: dc2 32 | numTokens: 32 33 | nodesPerRacks: 1 34 | rack: 35 | - name: rack1 36 | -------------------------------------------------------------------------------- /controllers/cassandracluster/testdata/cassandracluster-3DC.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "db.orange.com/v2" 2 | kind: "CassandraCluster" 3 | metadata: 4 | name: cassandra-demo 5 | labels: 6 | cluster: k8s.pic 7 | namespace: ns 8 | spec: 9 | nodesPerRacks: 1 10 | cassandraImage: cassandra:seed-dev 11 | imagePullSecret: 12 | name: advisedev # To authenticate on docker registry 13 | rollingPartition: 0 14 | dataCapacity: "3Gi" 15 | dataStorageClass: "local-storage" 16 | hardAntiAffinity: false 17 | deletePVC: true 18 | autoPilot: true 19 | resources: 20 | requests: 21 | cpu: '1' 22 | memory: 2Gi 23 | limits: 24 | cpu: '1' 25 | memory: 2Gi 26 | topology: 27 | dc: 28 | - name: dc1 29 | labels: 30 | location.dfy.orange.com/site : mts 31 | rack: 32 | - name: rack1 33 | labels: 34 | location.dfy.orange.com/street : street1 35 | - name: rack2 36 | labels: 37 | location.dfy.orange.com/street : street2 38 | - name: dc2 39 | nodesPerRacks: 1 40 | labels: 41 | location.dfy.orange.com/site : mts 42 | rack: 43 | - name: rack1 44 | labels: 45 | location.dfy.orange.com/street : street3 46 | - name: dc3 47 | nodesPerRacks: 1 48 | labels: 49 | location.dfy.orange.com/site : mts 50 | rack: 51 | - name: rack1 52 | labels: 53 | location.dfy.orange.com/street : street3 54 | 55 | -------------------------------------------------------------------------------- /controllers/cassandrarestore/cassandrarestore_controller.go: -------------------------------------------------------------------------------- 1 | package cassandrarestore 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | "math/rand" 6 | ctrl "sigs.k8s.io/controller-runtime" 7 | "time" 8 | 9 | api "github.com/Orange-OpenSource/casskop/api/v2" 10 | "k8s.io/apimachinery/pkg/api/meta" 11 | "sigs.k8s.io/controller-runtime/pkg/event" 12 | "sigs.k8s.io/controller-runtime/pkg/predicate" 13 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 14 | ) 15 | 16 | const ( 17 | AnnotationLastApplied string = "cassandrarestores.db.orange.com/last-applied-configuration" 18 | ) 19 | 20 | // initialize local pseudorandom generator 21 | var random = rand.New(rand.NewSource(time.Now().Unix())) 22 | 23 | 24 | func (r *CassandraRestoreReconciler) SetupWithManager(mgr ctrl.Manager) error { 25 | pred := predicate.Funcs{ 26 | CreateFunc: func(e event.CreateEvent) bool { 27 | object, err := meta.Accessor(e.Object) 28 | if err != nil { 29 | return false 30 | } 31 | restore, _ := object.(*api.CassandraRestore) 32 | reqLogger := logrus.WithFields(logrus.Fields{"Request.Namespace": restore.Namespace, 33 | "Request.Name": restore.Name}) 34 | cond := api.GetRestoreCondition(&restore.Status, api.RestoreRequired) 35 | if cond != nil { 36 | reqLogger.Infof("Restore is already scheduled on Cluster member %s", 37 | restore.Status.CoordinatorMember) 38 | return false 39 | } 40 | 41 | return true 42 | }, 43 | UpdateFunc: func(e event.UpdateEvent) bool { 44 | object, err := meta.Accessor(e.ObjectNew) 45 | if err != nil { 46 | return false 47 | } 48 | restore, _ := object.(*api.CassandraRestore) 49 | reqLogger := logrus.WithFields(logrus.Fields{"Request.Namespace": restore.Namespace, 50 | "Request.Name": restore.Name}) 51 | new := e.ObjectNew.(*api.CassandraRestore) 52 | if len(new.Status.CoordinatorMember)<1 { 53 | return false 54 | } 55 | if new.Status.Condition == nil { 56 | return true 57 | } 58 | restoreConditionType := api.RestoreConditionType(new.Status.Condition.Type) 59 | if restoreConditionType.IsCompleted() { 60 | reqLogger.Info("Restore is completed, skipping.") 61 | return false 62 | } 63 | 64 | if restoreConditionType.IsInError() { 65 | reqLogger.Info("Restore is in error state, skipping.") 66 | return false 67 | } 68 | return true 69 | }, 70 | } 71 | return ctrl.NewControllerManagedBy(mgr). 72 | For(&api.CassandraRestore{}). 73 | WithEventFilter(pred). 74 | Complete(r) 75 | } 76 | 77 | var _ reconcile.Reconciler = &CassandraRestoreReconciler{} 78 | -------------------------------------------------------------------------------- /controllers/cassandrarestore/status.go: -------------------------------------------------------------------------------- 1 | package cassandrarestore 2 | 3 | import ( 4 | "context" 5 | "emperror.dev/errors" 6 | api "github.com/Orange-OpenSource/casskop/api/v2" 7 | "github.com/sirupsen/logrus" 8 | "sigs.k8s.io/controller-runtime/pkg/client" 9 | ) 10 | 11 | func UpdateRestoreStatus(c client.Client, restore *api.CassandraRestore, status api.BackRestStatus, 12 | reqLogger *logrus.Entry) error { 13 | patch := client.MergeFrom(restore.DeepCopy()) 14 | restore.Status = status 15 | 16 | if err := c.Patch(context.Background(), restore, patch); err != nil { 17 | return errors.WrapIfWithDetails(err, "could not update status for restore", 18 | "restore", restore) 19 | } 20 | 21 | return nil 22 | } -------------------------------------------------------------------------------- /controllers/common/common_controller.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | api "github.com/Orange-OpenSource/casskop/api/v2" 6 | "github.com/Orange-OpenSource/casskop/pkg/cassandrabackup" 7 | "github.com/sirupsen/logrus" 8 | corev1 "k8s.io/api/core/v1" 9 | "sigs.k8s.io/controller-runtime/pkg/client" 10 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 11 | ) 12 | 13 | // RequeueWithError is a convenience wrapper around logging an error message 14 | // separate from the stacktrace and then passing the error through to the controller 15 | // manager 16 | func RequeueWithError(logger *logrus.Entry, msg string, err error) (reconcile.Result, error) { 17 | // Info log the error message and then let the reconciler dump the stacktrace 18 | logger.Info(msg) 19 | return reconcile.Result{}, err 20 | } 21 | 22 | // reconciled returns an empty result with nil error to signal a successful reconcile 23 | // to the controller manager 24 | func Reconciled() (reconcile.Result, error) { 25 | return reconcile.Result{}, nil 26 | } 27 | 28 | // NewCassandraBackupConnection is a convenience wrapper for creating a sidecars connection 29 | // and creating a safer close function 30 | func NewCassandraBackupConnection(client client.Client, cluster *api.CassandraCluster, 31 | pod *corev1.Pod) (csClient cassandrabackup.Client, err error) { 32 | // Get a cassandra backup connection 33 | logrus.Info(fmt.Sprintf("Retrieving Cassandra Sidecar client for %s/%s", cluster.Namespace, cluster.Name)) 34 | csClient, err = cassandrabackup.ClientFromCluster(client, cluster, pod) 35 | if err != nil { 36 | return 37 | } 38 | return 39 | } 40 | -------------------------------------------------------------------------------- /controllers/common/testutils.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Orange-OpenSource/casskop/api/v2" 6 | "github.com/ghodss/yaml" 7 | "github.com/sirupsen/logrus" 8 | "github.com/stretchr/testify/assert" 9 | "io/ioutil" 10 | v12 "k8s.io/api/apps/v1" 11 | "os" 12 | "path/filepath" 13 | "testing" 14 | ) 15 | 16 | func HelperLoadBytes(t *testing.T, name string) []byte { 17 | path := filepath.Join("testdata", name) // relative path 18 | bytes, err := ioutil.ReadFile(path) 19 | if err != nil { 20 | t.Fatal(err) 21 | } 22 | return bytes 23 | } 24 | 25 | func HelperGetStatefulset(t *testing.T, dcRackName string) *v12.StatefulSet { 26 | var sts v12.StatefulSet 27 | name := fmt.Sprintf("cassandracluster-2DC-%s-sts.yaml", dcRackName) 28 | yaml.Unmarshal(HelperLoadBytes(t, name), &sts) 29 | return &sts 30 | } 31 | 32 | func HelperInitCassandraBackup(cassandraBackupYaml string) v2.CassandraBackup { 33 | var cassandraBackup v2.CassandraBackup 34 | if err := yaml.Unmarshal([]byte(cassandraBackupYaml), &cassandraBackup); err != nil { 35 | logrus.Error(err) 36 | os.Exit(-1) 37 | } 38 | return cassandraBackup 39 | } 40 | 41 | func AssertEvent(t *testing.T, event chan string, message string) { 42 | assert := assert.New(t) 43 | eventMessage := <-event 44 | assert.Contains(eventMessage, message) 45 | } 46 | 47 | -------------------------------------------------------------------------------- /deploy/cassandra/psp.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: cassandra 5 | --- 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: Role 8 | metadata: 9 | name: cassandra 10 | rules: 11 | - apiGroups: ['policy'] 12 | resources: ['podsecuritypolicies'] 13 | verbs: ['use'] 14 | - apiGroups: [""] 15 | resources: ["pods", "configmaps", "secrets" ] 16 | verbs: ["get", "list", "watch"] 17 | - apiGroups: [""] 18 | resources: ["pods/exec"] 19 | verbs: ["get","create"] 20 | --- 21 | kind: RoleBinding 22 | apiVersion: rbac.authorization.k8s.io/v1 23 | metadata: 24 | name: cassandra 25 | subjects: 26 | - kind: ServiceAccount 27 | name: cassandra 28 | roleRef: 29 | kind: Role 30 | name: cassandra 31 | apiGroup: rbac.authorization.k8s.io 32 | --- 33 | apiVersion: policy/v1beta1 34 | kind: PodSecurityPolicy 35 | metadata: 36 | name: cassandra 37 | annotations: 38 | seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default' 39 | seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default' 40 | spec: 41 | privileged: false 42 | allowPrivilegeEscalation: false 43 | requiredDropCapabilities: 44 | - KILL 45 | - MKNOD 46 | - SETUID 47 | - SETGID 48 | volumes: 49 | - 'configMap' 50 | - 'emptyDir' 51 | - 'projected' 52 | - 'secret' 53 | - 'downwardAPI' 54 | - 'persistentVolumeClaim' 55 | hostNetwork: false 56 | hostIPC: false 57 | hostPID: false 58 | runAsUser: 59 | rule: 'MustRunAsNonRoot' 60 | seLinux: 61 | rule: 'RunAsAny' 62 | supplementalGroups: 63 | rule: 'MustRunAs' 64 | ranges: 65 | - min: 1 66 | max: 65535 67 | fsGroup: 68 | rule: 'MustRunAs' 69 | ranges: 70 | - min: 1 71 | max: 65535 72 | readOnlyRootFilesystem: false 73 | -------------------------------------------------------------------------------- /deploy/clusterRole-cassie.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | annotations: 5 | labels: 6 | addonmanager.kubernetes.io/mode: Reconcile 7 | kubernetes.io/cluster-service: "true" 8 | name: psp:cassie 9 | rules: 10 | - apiGroups: 11 | - policy 12 | resourceNames: 13 | - cassie 14 | resources: 15 | - podsecuritypolicies 16 | verbs: 17 | - use 18 | -------------------------------------------------------------------------------- /deploy/psp-cassie.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: PodSecurityPolicy 3 | metadata: 4 | annotations: 5 | seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default 6 | seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default 7 | labels: 8 | addonmanager.kubernetes.io/mode: Reconcile 9 | kubernetes.io/cluster-service: "true" 10 | name: cassie 11 | spec: 12 | allowPrivilegeEscalation: true 13 | allowedCapabilities: 14 | - IPC_LOCK 15 | allowedUnsafeSysctls: 16 | - vm.max_map_count 17 | forbiddenSysctls: 18 | - kernel.* 19 | - net.* 20 | - dev.* 21 | - fs.* 22 | fsGroup: 23 | ranges: 24 | - max: 65535 25 | min: 1 26 | rule: MustRunAs 27 | requiredDropCapabilities: 28 | - AUDIT_CONTROL 29 | - AUDIT_READ 30 | - AUDIT_WRITE 31 | - BLOCK_SUSPEND 32 | - CHOWN 33 | - DAC_OVERRIDE 34 | - DAC_READ_SEARCH 35 | - FOWNER 36 | - FSETID 37 | - IPC_OWNER 38 | - KILL 39 | - LEASE 40 | - LINUX_IMMUTABLE 41 | - MAC_ADMIN 42 | - MAC_OVERRIDE 43 | - MKNOD 44 | - NET_ADMIN 45 | - NET_BIND_SERVICE 46 | - NET_BROADCAST 47 | - NET_RAW 48 | - SETGID 49 | - SETFCAP 50 | - SETPCAP 51 | - SETUID 52 | - SYS_ADMIN 53 | - SYS_BOOT 54 | - SYS_CHROOT 55 | - SYS_MODULE 56 | - SYS_NICE 57 | - SYS_PACCT 58 | - SYS_PTRACE 59 | - SYS_RAWIO 60 | - SYS_TIME 61 | - SYS_TTY_CONFIG 62 | - SYSLOG 63 | - WAKE_ALARM 64 | runAsUser: 65 | rule: MustRunAsNonRoot 66 | seLinux: 67 | rule: RunAsAny 68 | supplementalGroups: 69 | ranges: 70 | - max: 65535 71 | min: 1 72 | rule: MustRunAs 73 | volumes: 74 | - configMap 75 | - emptyDir 76 | - projected 77 | - secret 78 | - downwardAPI 79 | - persistentVolumeClaim 80 | -------------------------------------------------------------------------------- /deploy/psp-sa-cassie.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | annotations: 5 | name: psp:sa:cassie 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: psp:cassie 10 | subjects: 11 | - apiGroup: rbac.authorization.k8s.io 12 | kind: Group 13 | name: system:serviceaccounts:default 14 | -------------------------------------------------------------------------------- /docker/bootstrap/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Orange 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 | 15 | PROJECT_ID?=orangeopensource 16 | ifeq ($(CI_REGISTRY_IMAGE),) 17 | PROJECT?=${PROJECT_ID}/cassandra-bootstrap 18 | else 19 | PROJECT:=$(CI_REGISTRY_IMAGE) 20 | endif 21 | 22 | VERSION:=0.1.9 23 | TAG?=${VERSION} 24 | ifeq ($(CIRCLE_BRANCH),master) 25 | BRANCH:=latest 26 | else ifeq ($(CIRCLE_TAG),) 27 | BRANCH=$(CIRCLE_BRANCH) 28 | else 29 | BRANCH=$(CIRCLE_TAG) 30 | endif 31 | 32 | .PHONY: all build build-cqlsh build-openjre build-openjre-cqlsh push push-cqlsh 33 | 34 | all: build 35 | 36 | build: 37 | docker build --pull \ 38 | --build-arg https_proxy=$(https_proxy) --build-arg http_proxy=$(http_proxy) \ 39 | -t ${PROJECT}:${TAG} . 40 | 41 | push: 42 | docker push ${PROJECT}:${TAG} 43 | 44 | -------------------------------------------------------------------------------- /docker/bootstrap/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Cassandra bootsrap image for CassKop 5 | 6 | This image aims to be used as an init-container to bootstrap Cassandra images to run with CassKop Kubernetes operator. It generates all the configuration necessary for the cassandra container to run. Our bootstrap image does the following : 7 | - Copies any default config files from CassKop bootstrapper image to /etc/cassandra mounted path which will replace those used in Cassandra image 8 | - Copies files from any mounted configmap (CassKop sets CONFIGMAP env var) 9 | - Copies any extra libraries from this bootstrap image to the /extra-lib (the default image provides instaclustr's cassandra-exporter and Jolokia agent) 10 | - Copies tools from /bootstrap/tools to /opt/bin 11 | - Executes script ${CONFIGMAP}/pre_run.sh if provided 12 | - Executes script run.sh 13 | - Executes script ${CONFIGMAP}/post_run.sh if provided 14 | 15 | ## Custom boostrap image Requirements 16 | 17 | In order to use your own bootstrap image, CassKop requires that it provides the binary curl in /bootstrap/tools (used by default readiness/liveness probes) and generates the cassandra configuration files correctly (see [run.sh](files/run.sh)). The easiest is to start with our image and just overwrite what you want to change in order to miss anything like the activation of Jolokia that is used by CassKop. As a recommendation, whenever you think you need a custom bootstrap image, try first to do your changes through a pre-run.sh script. Take a look at [that example](dgoss/test-with-pre-run/pre_run.sh). -------------------------------------------------------------------------------- /docker/bootstrap/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # Copies any default config files from CassKop bootstrapper image to /etc/cassandra volume which will replace the one used in cassandra image 5 | cp -rLv /${BOOTSTRAP_CONF}/* /etc/cassandra/ 6 | 7 | # Copies any extra libraries from this bootstrapper image to the extra-lib empty-dir 8 | if [[ -d /${BOOTSTRAP_LIBS} && ! -z `ls -A /${BOOTSTRAP_LIBS}` ]] ; then 9 | echo "We have additional libraries, we copy them over" 10 | cp -v ${BOOTSTRAP_LIBS}/* $CASSANDRA_LIBS/ 11 | fi 12 | 13 | cp -v /${BOOTSTRAP_TOOLS}/* $CASSANDRA_TOOLS/ 14 | 15 | if [ -f ${CONFIGMAP}/pre_run.sh ]; then 16 | echo "We found pre_run.sh script, we execute it" 17 | ${CONFIGMAP}/pre_run.sh 18 | fi 19 | 20 | # Bootstrap Cassandra configuration 21 | echo " == We execute bootstrap script run.sh" 22 | /${BOOTSTRAP_CONF}/run.sh 23 | 24 | if [ -f ${CONFIGMAP}/post_run.sh ]; then 25 | echo " == We found post_run.sh script, we execute it" 26 | ${CONFIGMAP}/post_run.sh 27 | fi 28 | 29 | echo '**** bootstrap ended ****' 30 | -------------------------------------------------------------------------------- /docker/bootstrap/dgoss/checks/goss_wait.yaml: -------------------------------------------------------------------------------- 1 | addr: 2 | # client 3 | tcp://{{.Env.HOSTNAME}}:9042: 4 | reachable: true 5 | 6 | -------------------------------------------------------------------------------- /docker/bootstrap/dgoss/runChecks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | testScriptDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | if [[ -z ${IMAGE_TO_TEST} ]] ; then 6 | echo Expected IMAGE_TO_TEST to be specified 7 | exit 1 8 | fi 9 | 10 | for testDirectory in `find ${testScriptDir}/test-* -type d` ; do 11 | echo ===== Running ${testDirectory} ===== 12 | bash ${testDirectory}/run.sh 13 | echo ===== End of ${testDirectory} ===== 14 | echo 15 | done 16 | -------------------------------------------------------------------------------- /docker/bootstrap/dgoss/test-default/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | testScriptDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | cd ${testScriptDir} 6 | 7 | source ../util.sh 8 | 9 | createDgossVolumes 10 | createInitConfigContainer 11 | createCassandraBootstrapContainer 12 | createAndCheckCassandraContainer 13 | -------------------------------------------------------------------------------- /docker/bootstrap/dgoss/test-with-pre-run/goss.yaml: -------------------------------------------------------------------------------- 1 | file: 2 | /etc/cassandra/cassandra.yaml: 3 | exists: true 4 | contains: 5 | - "max_hints_delivery_threads: 8" 6 | - "authenticator: PasswordAuthenticator" 7 | - "authorizer: CassandraAuthorizer" 8 | -------------------------------------------------------------------------------- /docker/bootstrap/dgoss/test-with-pre-run/pre_run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "** this is a pre-scrip for run.sh that can be edit with configmap" 4 | 5 | grep max_hints_delivery_threads /etc/cassandra/cassandra.yaml 6 | sed -i 's/max_hints_delivery_threads: 2/max_hints_delivery_threads: 8/' /etc/cassandra/cassandra.yaml 7 | grep max_hints_delivery_threads /etc/cassandra/cassandra.yaml 8 | 9 | echo "Change default Authenticator & Authorizer" 10 | sed -ri 's/(authenticator:).*/\1 PasswordAuthenticator/' /etc/cassandra/cassandra.yaml 11 | sed -ri 's/(authorizer:).*/\1 CassandraAuthorizer/' /etc/cassandra/cassandra.yaml 12 | -------------------------------------------------------------------------------- /docker/bootstrap/dgoss/test-with-pre-run/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | testScriptDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | cd ${testScriptDir} 6 | 7 | source ../util.sh 8 | 9 | 10 | createDgossVolumes 11 | # Add test file to user config map 12 | createInitConfigContainer 13 | createPreRunConfigMapFile 14 | createCassandraBootstrapContainer 15 | 16 | # check using test specific `goss.yaml` 17 | GOSS_SLEEP=0 dgoss run \ 18 | -v ${BOOTSTRAP_VOLUME}:/etc/cassandra \ 19 | -v ${EXTRA_LIB_VOLUME}:/extra-lib \ 20 | ${CASSANDRA_IMAGE} 21 | -------------------------------------------------------------------------------- /docker/bootstrap/dgoss/test-without-volumes/goss.yaml: -------------------------------------------------------------------------------- 1 | addr: 2 | # intra-nodes 3 | tcp://{{.Env.HOSTNAME}}:7000: 4 | reachable: true 5 | timeout: 5000 6 | # cassandra prometheus exporter 7 | tcp://{{.Env.HOSTNAME}}:9500: 8 | reachable: false 9 | # cassandra jmx port 10 | tcp://localhost:7199: 11 | reachable: true 12 | tcp://{{.Env.HOSTNAME}}:7199: 13 | reachable: true 14 | timeout: 5000 15 | # jolokia rest service 16 | tcp://{{.Env.HOSTNAME}}:8778: 17 | reachable: false 18 | # client 19 | tcp://{{.Env.HOSTNAME}}:9042: 20 | reachable: true 21 | timeout: 5000 22 | http: 23 | file: 24 | /etc/cassandra/jvm.options: 25 | exists: true 26 | contains: ["-XX:PrintFLSStatistics=1"] 27 | /etc/cassandra/cassandra.yaml: 28 | exists: true 29 | /etc/cassandra/cassandra-rackdc.properties: 30 | exists: true 31 | contains: ["dc=dc1", "rack=rack1"] 32 | 33 | /etc/cassandra/cassandra-env.sh: 34 | exists: true 35 | contains: 36 | - "!jolokia-agent.jar" 37 | - "!javaagent:/extra-lib/cassandra-exporter-agent.jar=@/etc/cassandra/exporter.conf" 38 | 39 | /etc/cassandra/liveness-probe.sh: 40 | exists: true 41 | 42 | /etc/cassandra/readiness-probe.sh: 43 | exists: true 44 | 45 | /etc/cassandra/run.sh: 46 | exists: true 47 | 48 | /extra-lib/cassandra-exporter-agent.jar: 49 | exists: false 50 | 51 | /extra-lib/jolokia-agent.jar: 52 | exists: false 53 | -------------------------------------------------------------------------------- /docker/bootstrap/dgoss/test-without-volumes/goss_wait.yaml: -------------------------------------------------------------------------------- 1 | addr: 2 | # client 3 | tcp://{{.Env.HOSTNAME}}:9042: 4 | reachable: true 5 | 6 | -------------------------------------------------------------------------------- /docker/bootstrap/dgoss/test-without-volumes/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | testScriptDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | cd ${testScriptDir} 6 | 7 | source ../util.sh 8 | 9 | 10 | createDgossVolumes 11 | # Add test file to user config map 12 | createInitConfigContainer 13 | createCassandraBootstrapContainerNoExtraLib 14 | 15 | # check using test specific `goss.yaml` 16 | GOSS_WAIT_OPTS='-r 90s -s 1s > /dev/null' dgoss run \ 17 | -v ${BOOTSTRAP_VOLUME}:/etc/cassandra \ 18 | ${CASSANDRA_IMAGE} 19 | -------------------------------------------------------------------------------- /docker/bootstrap/files/exporter.conf: -------------------------------------------------------------------------------- 1 | --listen=:9500 2 | -------------------------------------------------------------------------------- /docker/bootstrap/files/liveness-probe.sh: -------------------------------------------------------------------------------- 1 | readiness-probe.sh -------------------------------------------------------------------------------- /docker/bootstrap/files/readiness-probe.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2019 Orange 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Add Jolokia credentials, if defined in environment. 18 | if [[ -n $JOLOKIA_USER ]] && [[ -n $JOLOKIA_PASSWORD ]]; then 19 | USER_OPT="--user $JOLOKIA_USER:$JOLOKIA_PASSWORD" 20 | fi 21 | 22 | # We check when the node is up and in normal state 23 | CURL="/opt/bin/curl $USER_OPT -s --connect-timeout 0.5" 24 | BASE_CMD="http://$POD_IP:8778/jolokia/read/org.apache.cassandra.db:type=StorageService" 25 | 26 | if $CURL ${BASE_CMD}/LiveNodes | grep -q $POD_IP; then 27 | [[ $DEBUG ]] && echo Up 28 | exit 0 29 | fi 30 | 31 | [[ $DEBUG ]] && echo Not Up 32 | exit 1 33 | -------------------------------------------------------------------------------- /docker/cassandra/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM cassandra:3.11 2 | 3 | RUN apt-get update \ 4 | && apt-get -qq -y install libcap2-bin \ 5 | && setcap cap_ipc_lock=ep $(readlink -f $(which java)) 6 | -------------------------------------------------------------------------------- /docker/cassandra/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Orange 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 | 15 | PROJECT_ID?=orangeopensource 16 | ifeq ($(CI_REGISTRY_IMAGE),) 17 | PROJECT?=${PROJECT_ID}/cassandra-image 18 | else 19 | PROJECT:=$(CI_REGISTRY_IMAGE) 20 | endif 21 | 22 | VERSION:=3.11 23 | TAG?=${VERSION} 24 | 25 | ifdef CIRCLE_BRANCH 26 | #removing / for fork which lead to docker error 27 | BRANCH := $(subst /,-,$(CIRCLE_BRANCH)) 28 | else 29 | ifdef CIRCLE_TAG 30 | BRANCH := $(CIRCLE_TAG) 31 | else 32 | BRANCH=$(shell git rev-parse --abbrev-ref HEAD) 33 | endif 34 | endif 35 | 36 | .PHONY: all build build-cqlsh build-openjre build-openjre-cqlsh push push-cqlsh 37 | 38 | all: build 39 | 40 | params: 41 | @echo "CIRCLE_BRANCH = '$(CIRCLE_BRANCH)'" 42 | @echo "CIRCLE_TAG = '$(CIRCLE_TAG)'" 43 | @echo "Version = '$(VERSION)'" 44 | @echo "Branch = '$(BRANCH)'" 45 | @echo "Tag = '$(TAG)'" 46 | 47 | 48 | build: params 49 | docker build --pull \ 50 | --build-arg https_proxy=$(https_proxy) --build-arg http_proxy=$(http_proxy) \ 51 | -t ${PROJECT}:${TAG} . 52 | 53 | push: params 54 | ifeq ($(BRANCH),master) 55 | docker push ${PROJECT}:${TAG} 56 | endif 57 | docker tag ${PROJECT}:${TAG} ${PROJECT}:${BRANCH} 58 | docker push ${PROJECT}:${BRANCH} 59 | 60 | -------------------------------------------------------------------------------- /documentation/backup.md: -------------------------------------------------------------------------------- 1 | # Backup or restore your data 2 | 3 | In order to provide Backup/Restore abilities we use InstaCluster's [cassandra-sidecar project] 4 | (https://github.com/instaclustr/cassandra-sidecar) and add it to each Cassandra node to spawn. 5 | 6 | We have a designated controller called controller_cassandrabackup that is in charge of managing backups and interacts with the corresponding cassandra sidecars. Depending on the operation you wanna do you create a specific kubernetes object. We'll probably update our kubectl plugin to provide some of those features, access the list of backups etc.. 7 | 8 | ## Backup operation 9 | 10 | In order to backup, you create an object of type CassandraBackup 11 | 12 | ```yaml 13 | apiVersion: db.orange.com/v2 14 | kind: CassandraBackup 15 | metadata: 16 | name: test-cassandra-backup 17 | labels: 18 | app: cassandra 19 | spec: 20 | cassandracluster: test-cluster 21 | datacenter: dc1 22 | storageLocation: s3://cassie 23 | snapshotTag: SnapshotTag2 24 | secret: cloud-backup-secrets 25 | schedule: "@midnight" 26 | entities: k1.t1,k2.t3 27 | ``` 28 | 29 | ### Life cycle of the CassandraBackup object 30 | 31 | When this object gets created, CassKop does a few checks to ensure : 32 | - the specified Cassandra cluster exists 33 | - if there is a secret that it has the expected parameters depending on the chosen backend 34 | - if there is a schedule that its format is correct 35 | 36 | Then, if all those checks pass, it triggers the backup if there is no schedule, or creates a Cron task with the specified schedule. 37 | 38 | When this object gets deleted, if there is a scheduled task, it is unscheduled. 39 | 40 | When this object gets updated, and the change is located in the spec section, CassKop unschedules the existing task and schedules a new one with the new parameters provided. 41 | 42 | 43 | -------------------------------------------------------------------------------- /documentation/monitoring.md: -------------------------------------------------------------------------------- 1 | # Monitoring 2 | 3 | ## Install Prometheus operator 4 | 5 | ``` 6 | helm install prometheus-monitoring stable/prometheus-operator --set prometheusOperator.createCustomResource=false --set grafana.plugins="{briangann-gauge-panel,grafana-clock-panel,grafana-piechart-panel,grafana-polystat-panel,savantly-heatmap-panel,vonage-status-panel}" --set grafana.image.tag=7.0.1 7 | ``` 8 | 9 | ## Install our dashboard 10 | 11 | ``` 12 | kubectl apply -f monitoring/dashboards/ 13 | ``` 14 | 15 | We provide a dashboard that is used to monitor clusters in production. Thanks to Ahmed Eljami for his contribution. 16 | 17 | ## Install Service monitor 18 | 19 | You can update our service monitor if you want to create different service monitors like one per cluster for example. Otherwise just install ours: 20 | ``` 21 | kubectl apply -f monitoring/servicemonitor/prometheus-cassandra-service-monitor.yaml 22 | ``` 23 | 24 | Our ServiceMonitor monitors services created by CassKop that have label k8s-app set to exporter-cassandra-jmx. This service references the jmx exporter that is used by CassKop. -------------------------------------------------------------------------------- /documentation/uml/architecture.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | left to right direction 4 | package "CassandraOperator" #orange { 5 | [CassandraCluster] 6 | } 7 | 8 | package "Client" #lightblue { 9 | [Client-1] 10 | [Client-2] 11 | } 12 | 13 | package dc1 #orange{ 14 | 15 | node "rack1" { 16 | database "cassandra-dc1-r1-0" 17 | database "cassandra-dc1-r1-1" 18 | database "cassandra-dc1-r1-2" 19 | } 20 | 21 | node "rack2" { 22 | database "cassandra-dc1-r2-0" 23 | database "cassandra-dc1-r2-1" 24 | database "cassandra-dc1-r2-2" 25 | } 26 | 27 | cloud { 28 | [Statefulset-dc1-r1] 29 | } 30 | cloud { 31 | [Service-dc1] 32 | } 33 | cloud { 34 | [Statefulset-dc1-r2] 35 | } 36 | 37 | } 38 | 39 | 40 | package dc2 #lightgrey{ 41 | 42 | node "rack3" { 43 | database "cassandra-dc2-r1-0" 44 | database "cassandra-dc2-r1-1" 45 | database "cassandra-dc2-r1-2" 46 | } 47 | 48 | 49 | cloud { 50 | [Statefulset-dc2-r1] 51 | [Service-dc2] 52 | } 53 | 54 | } 55 | 56 | [Client-1] --> [Service-dc1] #blue 57 | [Client-2] --> [Service-dc1] #blue 58 | 59 | [Service-dc1] --> [cassandra-dc1-r1-0] #blue 60 | [Service-dc1] --> [cassandra-dc1-r1-1] #blue 61 | [Service-dc1] --> [cassandra-dc1-r1-2] #blue 62 | 63 | [Service-dc1] --> [cassandra-dc1-r2-0] #blue 64 | [Service-dc1] --> [cassandra-dc1-r2-1] #blue 65 | [Service-dc1] --> [cassandra-dc1-r2-2] #blue 66 | 67 | 68 | [CassandraCluster] .-> [Statefulset-dc1-r1] 69 | [CassandraCluster] .-> [Statefulset-dc1-r2] 70 | 71 | [Statefulset-dc1-r1] .-> [cassandra-dc1-r1-0] 72 | [Statefulset-dc1-r1] .-> [cassandra-dc1-r1-1] 73 | [Statefulset-dc1-r1] .-> [cassandra-dc1-r1-2] 74 | 75 | [Statefulset-dc1-r2] .-> [cassandra-dc1-r2-0] 76 | [Statefulset-dc1-r2] .-> [cassandra-dc1-r2-1] 77 | [Statefulset-dc1-r2] .-> [cassandra-dc1-r2-2] 78 | 79 | 80 | [CassandraCluster] .-> [Statefulset-dc2-r1] 81 | 82 | 83 | [Statefulset-dc2-r1] .-> [cassandra-dc2-r1-0] 84 | [Statefulset-dc2-r1] .-> [cassandra-dc2-r1-1] 85 | [Statefulset-dc2-r1] .-> [cassandra-dc2-r1-2] 86 | 87 | 88 | 89 | 90 | @enduml 91 | -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/hack/boilerplate.go.txt -------------------------------------------------------------------------------- /helm/cassandra-operator/.helmignore: -------------------------------------------------------------------------------- 1 | .git 2 | OWNERS -------------------------------------------------------------------------------- /helm/cassandra-operator/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: A Helm chart for CassKop - the Orange Cassandra Kubernetes operator 3 | name: cassandra-operator 4 | home: https://github.com/Orange-OpenSource/casskop 5 | sources: 6 | - https://github.com/Orange-OpenSource/casskop 7 | version: 2.1.0 8 | appVersion: 2.1.0-release 9 | maintainers: 10 | - name: cscetbon 11 | email: cscetbon@gmail.com 12 | - name: fdehay 13 | email: franck.dehay@orange.com 14 | keywords: 15 | - operator 16 | - cassandra 17 | - casskop 18 | -------------------------------------------------------------------------------- /helm/cassandra-operator/OWNERS: -------------------------------------------------------------------------------- 1 | approvers: 2 | - allamand 3 | - jal06 4 | - Orange-csetbon 5 | reviewers: 6 | - allamand 7 | - jal06 8 | - Orange-csetbon 9 | -------------------------------------------------------------------------------- /helm/cassandra-operator/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Congratulations. You have just deployed CassKop the Cassandra Operator. 2 | Check its status by running: 3 | kubectl --namespace {{ .Release.Namespace }} get pods -l "release={{ .Release.Name }}" 4 | 5 | Visit https://github.com/Orange-OpenSource/casskop for instructions on hot to create & configure Cassandra clusters using the operator. 6 | -------------------------------------------------------------------------------- /helm/cassandra-operator/templates/_functions.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "cassandra-operator.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "cassandra-operator.fullname" -}} 15 | {{- if .Values.fullnameOverride -}} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 17 | {{- else -}} 18 | {{- $name := default .Chart.Name .Values.nameOverride -}} 19 | {{- if contains $name .Release.Name -}} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 21 | {{- else -}} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 23 | {{- end -}} 24 | {{- end -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Return the appropriate apiVersion value to use for the capi-operator managed k8s resources 29 | */}} 30 | {{- define "cassandra-operator.apiVersion" -}} 31 | {{- printf "%s" "cassandraclusters.db.orange.com/v2" -}} 32 | {{- end -}} 33 | 34 | -------------------------------------------------------------------------------- /helm/cassandra-operator/templates/role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbacEnable }} 2 | kind: Role 3 | apiVersion: rbac.authorization.k8s.io/v1beta1 4 | metadata: 5 | labels: 6 | app: {{ template "cassandra-operator.name" . }} 7 | chart: {{ .Chart.Name }}-{{ .Chart.Version }} 8 | heritage: {{ .Release.Service }} 9 | release: {{ .Release.Name }} 10 | name: {{ template "cassandra-operator.name" . }} 11 | rules: 12 | - apiGroups: 13 | - db.orange.com 14 | resources: 15 | - "cassandraclusters" 16 | - "cassandrabackups" 17 | - "cassandrarestores" 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - deletecollection 27 | - apiGroups: 28 | - db.orange.com 29 | resources: 30 | - cassandraclusters/status 31 | - cassandrabackups/status 32 | - cassandrarestores/status 33 | verbs: 34 | - get 35 | - update 36 | - patch 37 | - apiGroups: 38 | - "" 39 | resources: 40 | - pods 41 | - pods/exec 42 | - services 43 | - endpoints 44 | - persistentvolumeclaims 45 | - events 46 | - configmaps 47 | - secrets 48 | verbs: 49 | - create 50 | - delete 51 | - get 52 | - list 53 | - patch 54 | - update 55 | - watch 56 | - apiGroups: 57 | - "" 58 | resources: 59 | - namespaces 60 | verbs: 61 | - get 62 | - apiGroups: 63 | - apps 64 | resources: 65 | - deployments 66 | - daemonsets 67 | - replicasets 68 | - statefulsets 69 | verbs: 70 | - create 71 | - delete 72 | - get 73 | - list 74 | - patch 75 | - update 76 | - watch 77 | - apiGroups: 78 | - policy 79 | resources: 80 | - poddisruptionbudgets 81 | verbs: 82 | - create 83 | - delete 84 | - get 85 | - list 86 | - patch 87 | - update 88 | - watch 89 | - apiGroups: 90 | - monitoring.coreos.com 91 | resources: 92 | - servicemonitors 93 | verbs: 94 | - "get" 95 | - "create" 96 | --- 97 | apiVersion: rbac.authorization.k8s.io/v1 98 | kind: Role 99 | metadata: 100 | labels: 101 | app: {{ template "cassandra-operator.name" . }} 102 | chart: {{ .Chart.Name }}-{{ .Chart.Version }} 103 | heritage: {{ .Release.Service }} 104 | release: {{ .Release.Name }} 105 | name: {{ template "cassandra-operator.name" . }}-cluster-node 106 | rules: 107 | - apiGroups: [""] 108 | resources: ["pods", "configmaps", "secrets" ] 109 | verbs: ["get", "list", "watch"] 110 | - apiGroups: [""] 111 | resources: ["pods/exec"] 112 | verbs: ["get","create"] 113 | {{- end }} 114 | -------------------------------------------------------------------------------- /helm/cassandra-operator/templates/rolebinding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbacEnable }} 2 | kind: RoleBinding 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | metadata: 5 | labels: 6 | app: {{ template "cassandra-operator.name" . }} 7 | chart: {{ .Chart.Name }}-{{ .Chart.Version }} 8 | heritage: {{ .Release.Service }} 9 | release: {{ .Release.Name }} 10 | name: {{ template "cassandra-operator.name" . }} 11 | subjects: 12 | - kind: ServiceAccount 13 | name: {{ template "cassandra-operator.name" . }} 14 | roleRef: 15 | kind: Role 16 | name: {{ template "cassandra-operator.name" . }} 17 | apiGroup: rbac.authorization.k8s.io 18 | {{- range .Values.clusterServiceAccountsName }} 19 | --- 20 | kind: RoleBinding 21 | apiVersion: rbac.authorization.k8s.io/v1 22 | metadata: 23 | labels: 24 | app: {{ template "cassandra-operator.name" $ }} 25 | chart: {{ $.Chart.Name }}-{{ $.Chart.Version }} 26 | heritage: {{ $.Release.Service }} 27 | release: {{ $.Release.Name }} 28 | name: {{ . }}-cluster-node 29 | subjects: 30 | - kind: ServiceAccount 31 | name: {{ . }} 32 | roleRef: 33 | kind: Role 34 | name: {{ template "cassandra-operator.name" $ }}-cluster-node 35 | apiGroup: rbac.authorization.k8s.io 36 | {{- end }} 37 | {{- end }} 38 | -------------------------------------------------------------------------------- /helm/cassandra-operator/templates/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.metricService }} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ template "cassandra-operator.name" . }}-metrics 6 | labels: 7 | component: app 8 | app: {{ template "cassandra-operator.name" . }}-metrics 9 | chart: {{ .Chart.Name }}-{{ .Chart.Version }} 10 | heritage: {{ .Release.Service }} 11 | release: {{ .Release.Name }} 12 | spec: 13 | selector: 14 | app: {{ template "cassandra-operator.name" . }} 15 | ports: 16 | - name: metrics 17 | port: 8383 18 | protocol: TCP 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /helm/cassandra-operator/templates/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app: {{ template "cassandra-operator.name" . }} 6 | chart: {{ .Chart.Name }}-{{ .Chart.Version }} 7 | heritage: {{ .Release.Service }} 8 | release: {{ .Release.Name }} 9 | name: {{ template "cassandra-operator.name" . }} 10 | {{- range .Values.clusterServiceAccountsName }} 11 | --- 12 | apiVersion: v1 13 | kind: ServiceAccount 14 | metadata: 15 | labels: 16 | app: {{ template "cassandra-operator.name" $ }} 17 | chart: {{ $.Chart.Name }}-{{ $.Chart.Version }} 18 | heritage: {{ $.Release.Service }} 19 | release: {{ $.Release.Name }} 20 | name: {{ . }} 21 | {{- end }} 22 | -------------------------------------------------------------------------------- /helm/cassandra-operator/values.yaml: -------------------------------------------------------------------------------- 1 | ## Cassandra Operator Image 2 | ## 3 | image: 4 | repository: orangeopensource/casskop 5 | tag: v2.1.0-release 6 | pullPolicy: Always 7 | imagePullSecrets: 8 | enabled: false 9 | # name: 10 | 11 | ## Prometheus-operator resource limits & requests 12 | ## Ref: https://kubernetes.io/docs/user-guide/compute-resources/ 13 | resources: 14 | requests: 15 | cpu: 10m 16 | memory: 50Mi 17 | limits: 18 | cpu: 1 19 | memory: 512Mi 20 | 21 | readinessProbe: 22 | timeouts: 23 | initialDelaySeconds: 4 24 | periodSeconds: 10 25 | failureThreshold: 1 26 | livenessProbe: 27 | timeouts: 28 | initialDelaySeconds: 4 29 | periodSeconds: 10 30 | failureThreshold: 1 31 | 32 | ## If true, create & deploy the CRD 33 | ## 34 | createCustomResource: true 35 | 36 | ## If true, create & use RBAC resources 37 | ## 38 | rbacEnable: true 39 | 40 | ## if true deploy service for metrics access 41 | metricService: false 42 | 43 | debug: 44 | enabled: false 45 | 46 | ## 47 | clusterServiceAccountsName: 48 | - cassandra-cluster-node 49 | -------------------------------------------------------------------------------- /monitoring/servicemonitor/prometheus-cassandra-service-monitor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | name: prometheus-cassandra 5 | labels: 6 | app: cassandra 7 | release: prometheus-monitoring 8 | spec: 9 | jobLabel: kube-prometheus-cassandra-k8s 10 | selector: 11 | matchLabels: 12 | k8s-app: exporter-cassandra-jmx 13 | namespaceSelector: 14 | any: true 15 | endpoints: 16 | - port: promjmx 17 | interval: 15s 18 | relabelings: 19 | - sourceLabels: [__meta_kubernetes_pod_name] 20 | targetLabel: instance 21 | regex: (.*) 22 | replacement: $1 23 | action: replace 24 | - sourceLabels: [__meta_kubernetes_pod_label_cassandracluster] 25 | targetLabel: cassandra_cluster 26 | regex: (.*) 27 | replacement: $1 28 | action: replace 29 | - sourceLabels: [__meta_kubernetes_pod_label_cassandraclusters_db_orange_com_dc] 30 | targetLabel: cassandra_datacenter 31 | regex: (.*) 32 | replacement: $1 33 | action: replace 34 | - sourceLabels: [__meta_kubernetes_pod_label_cassandraclusters_db_orange_com_rack] 35 | targetLabel: cassandra_rack 36 | regex: (.*) 37 | replacement: $1 38 | action: replace 39 | -------------------------------------------------------------------------------- /monitoring/servicemonitor/prometheus-casskop-service-monitor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | name: prometheus-casskop 5 | labels: 6 | app: cassandra 7 | release: prometheus-monitoring 8 | spec: 9 | jobLabel: kube-prometheus-cassandra-k8s 10 | selector: 11 | matchLabels: 12 | name: cassandra-operator 13 | namespaceSelector: 14 | any: true 15 | endpoints: 16 | - port: http-metrics 17 | interval: 15s 18 | -------------------------------------------------------------------------------- /multi-casskop/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.17 as build 2 | 3 | ENV GO111MODULE=on 4 | 5 | RUN useradd -u 1000 multi-casskop 6 | 7 | COPY . /workspace 8 | WORKDIR /workspace/multi-casskop 9 | 10 | RUN go mod edit -replace github.com/Orange-OpenSource/casskop=/workspace 11 | # cache deps before building and copying source so that we don't need to re-download as much 12 | # and so that source changes don't invalidate our downloaded layer 13 | RUN go mod download 14 | RUN go mod vendor 15 | 16 | # Build 17 | RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o multi-casskop main.go 18 | 19 | FROM gcr.io/distroless/base 20 | 21 | WORKDIR / 22 | COPY --from=build /etc/passwd /etc/passwd 23 | COPY --from=build /tmp /tmp 24 | COPY --from=build /workspace/multi-casskop/multi-casskop /usr/local/bin/multi-casskop 25 | 26 | ENV OPERATOR=/usr/local/bin/multi-casskop \ 27 | USER_UID=1000 \ 28 | USER_NAME=multi-casskop 29 | 30 | ENTRYPOINT ["/usr/local/bin/multi-casskop"] 31 | 32 | USER ${USER_UID} 33 | -------------------------------------------------------------------------------- /multi-casskop/PROJECT: -------------------------------------------------------------------------------- 1 | domain: multicasskops.db.orange.com 2 | layout: go.kubebuilder.io/v2 3 | repo: github.com/Orange-OpenSource/casskop 4 | version: 3-alpha 5 | plugins: 6 | go.operator-sdk.io/v2-alpha: {} 7 | -------------------------------------------------------------------------------- /multi-casskop/TODO.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Features 4 | 5 | - [x] **Feature01**: CassKop's special feature using the unlockNextOperation which allows to recover when CassKop fails, 6 | must be treated with really good care as this parameter is removed when activated by local CassKop. I think We must 7 | prevent to let this parameter be set at MultiCasskop level, and not to be removed from local CassandraCluster 8 | if it has been set up locally (remove from the difference detection) 9 | 10 | - [ ] **Feature02**: Auto compute and update seedlist at MultiCassKop level 11 | 12 | - [x] **Feature03**: Specify the namespace we want to deploy onto for each kubernetes contexts 13 | 14 | - [x] **Feature04**: Allow to delete CassandraClusters when deleting MultiCasskop 15 | Make uses of a Finalizer to keep track of last MultiCasskop before deleting 16 | 17 | - [x] **Feature05**: Managing rollingUpdate changes on CassandraCluster objects (Casskop may remove this flag, and 18 | multiCassKop re-set-it...) 19 | 20 | 21 | ## Bugs 22 | 23 | - [x] **Bug01**: when changing parameter on a deployed cluster (for instance cassandra image), both clusters applied modification 24 | in the same time, this is not good, we need to only applied on one cluster and when OK apply to the next one 25 | -------------------------------------------------------------------------------- /multi-casskop/api/v2/cassandramulticluster_types.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | apicc "github.com/Orange-OpenSource/casskop/api/v2" 5 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 6 | ) 7 | 8 | // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! 9 | // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. 10 | 11 | // MultiCasskopSpec defines the desired state of MultiCasskop 12 | // +k8s:openapi-gen=true 13 | type MultiCasskopSpec struct { 14 | DeleteCassandraCluster *bool `json:"deleteCassandraCluster,omitempty"` 15 | Base apicc.CassandraCluster `json:"base,omitempty"` 16 | Override map[string]apicc.CassandraCluster `json:"override,omitempty"` 17 | } 18 | 19 | // MultiCasskopStatus defines the observed state of MultiCasskop 20 | // +k8s:openapi-gen=true 21 | type MultiCasskopStatus struct { 22 | // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster 23 | // Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file 24 | // Add custom validation using kubebuilder tags: https://book.kubebuilder.io/beyond_basics/generating_crd.html 25 | } 26 | 27 | // +kubebuilder:object:root=true 28 | 29 | // MultiCasskop is the Schema for the MultiCasskops API 30 | // +k8s:openapi-gen=true 31 | type MultiCasskop struct { 32 | metav1.TypeMeta `json:",inline"` 33 | metav1.ObjectMeta `json:"metadata,omitempty"` 34 | 35 | Spec MultiCasskopSpec `json:"spec,omitempty"` 36 | Status MultiCasskopStatus `json:"status,omitempty"` 37 | } 38 | 39 | // +kubebuilder:object:root=true 40 | 41 | // MultiCasskopList contains a list of MultiCasskop 42 | type MultiCasskopList struct { 43 | metav1.TypeMeta `json:",inline"` 44 | metav1.ListMeta `json:"metadata,omitempty"` 45 | Items []MultiCasskop `json:"items"` 46 | } 47 | 48 | func init() { 49 | SchemeBuilder.Register(&MultiCasskop{}, &MultiCasskopList{}) 50 | } 51 | -------------------------------------------------------------------------------- /multi-casskop/api/v2/groupversion_info.go: -------------------------------------------------------------------------------- 1 | /* 2 | 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 v2 contains API Schema definitions for the multicasskops.db.orange.com v2 API group 18 | // +kubebuilder:object:generate=true 19 | // +groupName=multicasskops.db.orange.com.multicasskops.db.orange.com 20 | package v2 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: "multicasskops.db.orange.com.multicasskops.db.orange.com", Version: "v2"} 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 | -------------------------------------------------------------------------------- /multi-casskop/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 0.11 check https://docs.cert-manager.io/en/latest/tasks/upgrading/index.html for 4 | # breaking changes 5 | apiVersion: cert-manager.io/v1alpha2 6 | kind: Issuer 7 | metadata: 8 | name: selfsigned-issuer 9 | namespace: system 10 | spec: 11 | selfSigned: {} 12 | --- 13 | apiVersion: cert-manager.io/v1alpha2 14 | kind: Certificate 15 | metadata: 16 | name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml 17 | namespace: system 18 | spec: 19 | # $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize 20 | dnsNames: 21 | - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc 22 | - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local 23 | issuerRef: 24 | kind: Issuer 25 | name: selfsigned-issuer 26 | secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize 27 | -------------------------------------------------------------------------------- /multi-casskop/config/certmanager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - certificate.yaml 3 | 4 | configurations: 5 | - kustomizeconfig.yaml 6 | -------------------------------------------------------------------------------- /multi-casskop/config/certmanager/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This configuration is for teaching kustomize how to update name ref and var substitution 2 | nameReference: 3 | - kind: Issuer 4 | group: cert-manager.io 5 | fieldSpecs: 6 | - kind: Certificate 7 | group: cert-manager.io 8 | path: spec/issuerRef/name 9 | 10 | varReference: 11 | - kind: Certificate 12 | group: cert-manager.io 13 | path: spec/commonName 14 | - kind: Certificate 15 | group: cert-manager.io 16 | path: spec/dnsNames 17 | -------------------------------------------------------------------------------- /multi-casskop/config/crd/bases/multicluster_v1alpha1_cassandramulticluster_crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: multicasskops.db.orange.com 5 | spec: 6 | group: db.orange.com 7 | names: 8 | kind: MultiCasskop 9 | listKind: MultiCasskopList 10 | plural: multicasskops 11 | singular: multicasskop 12 | scope: Namespaced 13 | subresources: 14 | status: {} 15 | version: v2 16 | versions: 17 | - name: v1 18 | served: true 19 | storage: false 20 | - name: v2 21 | served: true 22 | storage: true 23 | -------------------------------------------------------------------------------- /multi-casskop/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/multicasskops.db.orange.com.multicasskops.db.orange.com_multicasskops.yaml 6 | # +kubebuilder:scaffold:crdkustomizeresource 7 | 8 | patchesStrategicMerge: 9 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. 10 | # patches here are for enabling the conversion webhook for each CRD 11 | #- patches/webhook_in_multicasskops.yaml 12 | # +kubebuilder:scaffold:crdkustomizewebhookpatch 13 | 14 | # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. 15 | # patches here are for enabling the CA injection for each CRD 16 | #- patches/cainjection_in_multicasskops.yaml 17 | # +kubebuilder:scaffold:crdkustomizecainjectionpatch 18 | 19 | # the following config is for teaching kustomize how to do kustomization for CRDs. 20 | configurations: 21 | - kustomizeconfig.yaml 22 | -------------------------------------------------------------------------------- /multi-casskop/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 | group: apiextensions.k8s.io 8 | path: spec/conversion/webhookClientConfig/service/name 9 | 10 | namespace: 11 | - kind: CustomResourceDefinition 12 | group: apiextensions.k8s.io 13 | path: spec/conversion/webhookClientConfig/service/namespace 14 | create: false 15 | 16 | varReference: 17 | - path: metadata/annotations 18 | -------------------------------------------------------------------------------- /multi-casskop/config/crd/patches/cainjection_in_multicasskops.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | # CRD conversion requires k8s 1.13 or later. 3 | apiVersion: apiextensions.k8s.io/v1beta1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 8 | name: multicasskops.multicasskops.db.orange.com.multicasskops.db.orange.com 9 | -------------------------------------------------------------------------------- /multi-casskop/config/crd/patches/webhook_in_multicasskops.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables conversion webhook for CRD 2 | # CRD conversion requires k8s 1.13 or later. 3 | apiVersion: apiextensions.k8s.io/v1beta1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | name: multicasskops.multicasskops.db.orange.com.multicasskops.db.orange.com 7 | spec: 8 | conversion: 9 | strategy: Webhook 10 | webhookClientConfig: 11 | # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, 12 | # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) 13 | caBundle: Cg== 14 | service: 15 | namespace: system 16 | name: webhook-service 17 | path: /convert 18 | -------------------------------------------------------------------------------- /multi-casskop/config/default/manager_auth_proxy_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch inject a sidecar container which is a HTTP proxy for the 2 | # controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: controller-manager 7 | namespace: system 8 | spec: 9 | template: 10 | spec: 11 | containers: 12 | - name: kube-rbac-proxy 13 | image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0 14 | args: 15 | - "--secure-listen-address=0.0.0.0:8443" 16 | - "--upstream=http://127.0.0.1:8080/" 17 | - "--logtostderr=true" 18 | - "--v=10" 19 | ports: 20 | - containerPort: 8443 21 | name: https 22 | - name: manager 23 | args: 24 | - "--metrics-addr=127.0.0.1:8080" 25 | - "--enable-leader-election" 26 | -------------------------------------------------------------------------------- /multi-casskop/config/default/manager_webhook_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: manager 11 | ports: 12 | - containerPort: 9443 13 | name: webhook-server 14 | protocol: TCP 15 | volumeMounts: 16 | - mountPath: /tmp/k8s-webhook-server/serving-certs 17 | name: cert 18 | readOnly: true 19 | volumes: 20 | - name: cert 21 | secret: 22 | defaultMode: 420 23 | secretName: webhook-server-cert 24 | -------------------------------------------------------------------------------- /multi-casskop/config/default/webhookcainjection_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch add annotation to admission webhook config and 2 | # the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize. 3 | apiVersion: admissionregistration.k8s.io/v1beta1 4 | kind: MutatingWebhookConfiguration 5 | metadata: 6 | name: mutating-webhook-configuration 7 | annotations: 8 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 9 | --- 10 | apiVersion: admissionregistration.k8s.io/v1beta1 11 | kind: ValidatingWebhookConfiguration 12 | metadata: 13 | name: validating-webhook-configuration 14 | annotations: 15 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 16 | -------------------------------------------------------------------------------- /multi-casskop/config/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manager.yaml 3 | -------------------------------------------------------------------------------- /multi-casskop/config/manager/manager.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: multi-casskop 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | name: multi-casskop 10 | template: 11 | metadata: 12 | labels: 13 | name: multi-casskop 14 | spec: 15 | serviceAccountName: multi-casskop 16 | containers: 17 | - name: multi-casskop 18 | # Replace this with the built image name 19 | image: REPLACE_IMAGE 20 | command: 21 | - multi-casskop 22 | imagePullPolicy: Always 23 | env: 24 | - name: WATCH_NAMESPACE 25 | valueFrom: 26 | fieldRef: 27 | fieldPath: metadata.namespace 28 | - name: POD_NAME 29 | valueFrom: 30 | fieldRef: 31 | fieldPath: metadata.name 32 | - name: OPERATOR_NAME 33 | value: "multi-casskop" 34 | -------------------------------------------------------------------------------- /multi-casskop/config/prometheus/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - monitor.yaml 3 | -------------------------------------------------------------------------------- /multi-casskop/config/prometheus/monitor.yaml: -------------------------------------------------------------------------------- 1 | 2 | # Prometheus Monitor Service (Metrics) 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: ServiceMonitor 5 | metadata: 6 | labels: 7 | control-plane: controller-manager 8 | name: controller-manager-metrics-monitor 9 | namespace: system 10 | spec: 11 | endpoints: 12 | - path: /metrics 13 | port: https 14 | selector: 15 | matchLabels: 16 | control-plane: controller-manager 17 | -------------------------------------------------------------------------------- /multi-casskop/config/rbac/auth_proxy_client_clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1beta1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics-reader 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | -------------------------------------------------------------------------------- /multi-casskop/config/rbac/auth_proxy_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: proxy-role 5 | rules: 6 | - apiGroups: ["authentication.k8s.io"] 7 | resources: 8 | - tokenreviews 9 | verbs: ["create"] 10 | - apiGroups: ["authorization.k8s.io"] 11 | resources: 12 | - subjectaccessreviews 13 | verbs: ["create"] 14 | -------------------------------------------------------------------------------- /multi-casskop/config/rbac/auth_proxy_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: proxy-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: proxy-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: system 13 | -------------------------------------------------------------------------------- /multi-casskop/config/rbac/auth_proxy_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | name: controller-manager-metrics-service 7 | namespace: system 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | control-plane: controller-manager 15 | -------------------------------------------------------------------------------- /multi-casskop/config/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - role.yaml 3 | - role_binding.yaml 4 | - leader_election_role.yaml 5 | - leader_election_role_binding.yaml 6 | # Comment the following 4 lines if you want to disable 7 | # the auth proxy (https://github.com/brancz/kube-rbac-proxy) 8 | # which protects your /metrics endpoint. 9 | - auth_proxy_service.yaml 10 | - auth_proxy_role.yaml 11 | - auth_proxy_role_binding.yaml 12 | - auth_proxy_client_clusterrole.yaml 13 | -------------------------------------------------------------------------------- /multi-casskop/config/rbac/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: leader-election-role 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - configmaps 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - create 16 | - update 17 | - patch 18 | - delete 19 | - apiGroups: 20 | - "" 21 | resources: 22 | - configmaps/status 23 | verbs: 24 | - get 25 | - update 26 | - patch 27 | - apiGroups: 28 | - "" 29 | resources: 30 | - events 31 | verbs: 32 | - create 33 | - patch 34 | -------------------------------------------------------------------------------- /multi-casskop/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: default 12 | namespace: system 13 | -------------------------------------------------------------------------------- /multi-casskop/config/rbac/multicasskop_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit multicasskops. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: multicasskop-editor-role 6 | rules: 7 | - apiGroups: 8 | - multicasskops.db.orange.com.multicasskops.db.orange.com 9 | resources: 10 | - multicasskops 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - multicasskops.db.orange.com.multicasskops.db.orange.com 21 | resources: 22 | - multicasskops/status 23 | verbs: 24 | - get 25 | -------------------------------------------------------------------------------- /multi-casskop/config/rbac/multicasskop_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view multicasskops. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: multicasskop-viewer-role 6 | rules: 7 | - apiGroups: 8 | - multicasskops.db.orange.com.multicasskops.db.orange.com 9 | resources: 10 | - multicasskops 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - apiGroups: 16 | - multicasskops.db.orange.com.multicasskops.db.orange.com 17 | resources: 18 | - multicasskops/status 19 | verbs: 20 | - get 21 | -------------------------------------------------------------------------------- /multi-casskop/config/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: Role 3 | metadata: 4 | creationTimestamp: null 5 | name: multi-casskop 6 | rules: 7 | - apiGroups: 8 | - db.orange.com 9 | resources: 10 | - '*' 11 | verbs: 12 | - '*' 13 | -------------------------------------------------------------------------------- /multi-casskop/config/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | kind: RoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: multi-casskop 5 | subjects: 6 | - kind: ServiceAccount 7 | name: multi-casskop 8 | roleRef: 9 | kind: Role 10 | name: multi-casskop 11 | apiGroup: rbac.authorization.k8s.io 12 | -------------------------------------------------------------------------------- /multi-casskop/config/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: multi-casskop 5 | -------------------------------------------------------------------------------- /multi-casskop/config/samples/gke/terraform/env/master.tfvars: -------------------------------------------------------------------------------- 1 | cluster_region = "europe-west1" 2 | cluster_zone = "europe-west1-b" 3 | username = "demo" 4 | password = "demodemodemodemo" 5 | master_state = "master" 6 | create_dns = true -------------------------------------------------------------------------------- /multi-casskop/config/samples/gke/terraform/env/slave.tfvars: -------------------------------------------------------------------------------- 1 | project = "poc-rtc" 2 | cluster_region = "europe-west1" 3 | cluster_zone = "europe-west1-c" 4 | username = "demo" 5 | password = "demodemodemodemo" 6 | master_state = "slave" 7 | create_dns = false -------------------------------------------------------------------------------- /multi-casskop/config/samples/gke/terraform/post_run.sh: -------------------------------------------------------------------------------- 1 | echo "Check Configured seeds by bootstrap" 2 | grep "seeds:" /etc/cassandra/cassandra.yaml 3 | -------------------------------------------------------------------------------- /multi-casskop/config/samples/gke/terraform/pre_run.sh: -------------------------------------------------------------------------------- 1 | echo "Change default Authenticator & Authorizer" 2 | sed -ri 's/(authenticator:).*/\1 PasswordAuthenticator/' /etc/cassandra/cassandra.yaml 3 | sed -ri 's/(authorizer:).*/\1 CassandraAuthorizer/' /etc/cassandra/cassandra.yaml 4 | #test "$(hostname)" == 'cassandra-demo-dc1-rack2-0' && echo "update param" && sed -i 's/windows_timer_interval: 1/windows_timer_interval: 2/' /etc/cassandra/cassandra.yaml 5 | #test "$(hostname)" == 'cassandra-demo-dc1-rack3-0' && echo "-Dcassandra.replace_address_first_boot=" >> /etc/cassandra/jvm.options 6 | echo "** end of pre_run.sh script, continue with run.sh" 7 | -------------------------------------------------------------------------------- /multi-casskop/config/samples/multicasskops.db.orange.com_v2_multicasskop.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: multicasskops.db.orange.com.multicasskops.db.orange.com/v2 2 | kind: MultiCasskop 3 | metadata: 4 | name: multicasskop-sample 5 | spec: 6 | # Add fields here 7 | foo: bar 8 | -------------------------------------------------------------------------------- /multi-casskop/config/webhook/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manifests.yaml 3 | - service.yaml 4 | 5 | configurations: 6 | - kustomizeconfig.yaml 7 | -------------------------------------------------------------------------------- /multi-casskop/config/webhook/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # the following config is for teaching kustomize where to look at when substituting vars. 2 | # It requires kustomize v2.1.0 or newer to work properly. 3 | nameReference: 4 | - kind: Service 5 | version: v1 6 | fieldSpecs: 7 | - kind: MutatingWebhookConfiguration 8 | group: admissionregistration.k8s.io 9 | path: webhooks/clientConfig/service/name 10 | - kind: ValidatingWebhookConfiguration 11 | group: admissionregistration.k8s.io 12 | path: webhooks/clientConfig/service/name 13 | 14 | namespace: 15 | - kind: MutatingWebhookConfiguration 16 | group: admissionregistration.k8s.io 17 | path: webhooks/clientConfig/service/namespace 18 | create: true 19 | - kind: ValidatingWebhookConfiguration 20 | group: admissionregistration.k8s.io 21 | path: webhooks/clientConfig/service/namespace 22 | create: true 23 | 24 | varReference: 25 | - path: metadata/annotations 26 | -------------------------------------------------------------------------------- /multi-casskop/config/webhook/service.yaml: -------------------------------------------------------------------------------- 1 | 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: webhook-service 6 | namespace: system 7 | spec: 8 | ports: 9 | - port: 443 10 | targetPort: 9443 11 | selector: 12 | control-plane: controller-manager 13 | -------------------------------------------------------------------------------- /multi-casskop/controllers/clients.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Orange 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 | package controllers 15 | 16 | import ( 17 | "sigs.k8s.io/controller-runtime/pkg/client" 18 | ) 19 | 20 | // Client is the k8s client to use to connect to each kubernetes 21 | type Client struct { 22 | Name string 23 | Client client.Client 24 | } 25 | 26 | // Clients defined each client (local & remotes) to access to k8s cluster. 27 | type Clients struct { 28 | Local *Client 29 | Remotes []*Client 30 | } 31 | 32 | // Convert local & remotes clients to a merged list. 33 | // Simplify loop on clients 34 | func (clients *Clients) FlatClients() []*Client { 35 | flatClients := append([]*Client{clients.Local}, clients.Remotes...) 36 | return flatClients 37 | } 38 | -------------------------------------------------------------------------------- /multi-casskop/hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | 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 | */ -------------------------------------------------------------------------------- /multi-casskop/helm/multi-casskop/.helmignore: -------------------------------------------------------------------------------- 1 | .git 2 | OWNERS -------------------------------------------------------------------------------- /multi-casskop/helm/multi-casskop/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: A Helm chart for MultiCassKop - the Orange Multiple Cassandra Kubernetes operator 3 | name: multi-casskop 4 | home: https://github.com/Orange-OpenSource/casskop/multi-casskop 5 | sources: 6 | - https://github.com/Orange-OpenSource/casskop/multi-casskop 7 | version: 2.1.0 8 | appVersion: 2.1.0-release 9 | maintainers: 10 | - name: cscetbon 11 | email: cscetbon@gmail.com 12 | - name: fdehay 13 | email: franck.dehay@orange.com 14 | keywords: 15 | - operator 16 | - cassandra 17 | - casskop 18 | - multi-casskop 19 | - multi-clusters 20 | -------------------------------------------------------------------------------- /multi-casskop/helm/multi-casskop/OWNERS: -------------------------------------------------------------------------------- 1 | approvers: 2 | - allamand 3 | - jal06 4 | - Orange-csetbon 5 | - fdehay 6 | reviewers: 7 | - allamand 8 | - jal06 9 | - Orange-csetbon 10 | - fdehay 11 | -------------------------------------------------------------------------------- /multi-casskop/helm/multi-casskop/crds/db.orange.com_multicasskops.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: multicasskops.db.orange.com 5 | spec: 6 | group: db.orange.com 7 | names: 8 | kind: MultiCasskop 9 | listKind: MultiCasskopList 10 | plural: multicasskops 11 | singular: multicasskop 12 | scope: Namespaced 13 | subresources: 14 | status: {} 15 | version: v2 16 | versions: 17 | - name: v1 18 | served: true 19 | storage: false 20 | - name: v2 21 | served: true 22 | storage: true 23 | -------------------------------------------------------------------------------- /multi-casskop/helm/multi-casskop/crds/multicluster_v1alpha1_cassandramulticluster_crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: multicasskops.db.orange.com 5 | spec: 6 | group: db.orange.com 7 | names: 8 | kind: MultiCasskop 9 | listKind: MultiCasskopList 10 | plural: multicasskops 11 | singular: multicasskop 12 | scope: Namespaced 13 | subresources: 14 | status: {} 15 | version: v2 16 | versions: 17 | - name: v1 18 | served: true 19 | storage: false 20 | - name: v2 21 | served: true 22 | storage: true 23 | -------------------------------------------------------------------------------- /multi-casskop/helm/multi-casskop/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Congratulations. You have just deployed Multi-CassKop Operator. 2 | Check its status by running: 3 | kubectl --namespace {{ .Release.Namespace }} get pods -l "release={{ .Release.Name }}" 4 | 5 | Visit https://github.com/Orange-OpenSource/casskop/multi-casskop for instructions on hot to create & configure Cassandra clusters using the operator. 6 | -------------------------------------------------------------------------------- /multi-casskop/helm/multi-casskop/templates/_functions.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "multi-casskop.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "multi-casskop.fullname" -}} 15 | {{- if .Values.fullnameOverride -}} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 17 | {{- else -}} 18 | {{- $name := default .Chart.Name .Values.nameOverride -}} 19 | {{- if contains $name .Release.Name -}} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 21 | {{- else -}} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 23 | {{- end -}} 24 | {{- end -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Return the appropriate apiVersion value to use for the capi-operator managed k8s resources 29 | */}} 30 | {{- define "multi-casskop.apiVersion" -}} 31 | {{- printf "%s" "multicasskop.db.orange.com/v2" -}} 32 | {{- end -}} 33 | 34 | -------------------------------------------------------------------------------- /multi-casskop/helm/multi-casskop/templates/role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbacEnable }} 2 | kind: Role 3 | apiVersion: rbac.authorization.k8s.io/v1beta1 4 | metadata: 5 | labels: 6 | app: {{ template "multi-casskop.name" . }} 7 | chart: {{ .Chart.Name }}-{{ .Chart.Version }} 8 | heritage: {{ .Release.Service }} 9 | release: {{ .Release.Name }} 10 | name: {{ template "multi-casskop.name" . }} 11 | rules: 12 | - apiGroups: 13 | - db.orange.com 14 | resources: 15 | - multicasskops 16 | - cassandraclusters 17 | verbs: 18 | - create 19 | - delete 20 | - get 21 | - list 22 | - patch 23 | - update 24 | - watch 25 | - deletecollection 26 | - apiGroups: 27 | - db.orange.com 28 | resources: 29 | - multicasskops/status 30 | - cassandraclusters/status 31 | verbs: 32 | - get 33 | - update 34 | - patch 35 | - apiGroups: 36 | - "" 37 | resources: 38 | - namespaces 39 | verbs: 40 | - get 41 | {{- end }} 42 | -------------------------------------------------------------------------------- /multi-casskop/helm/multi-casskop/templates/rolebinding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbacEnable }} 2 | kind: RoleBinding 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | metadata: 5 | labels: 6 | app: {{ template "multi-casskop.name" . }} 7 | chart: {{ .Chart.Name }}-{{ .Chart.Version }} 8 | heritage: {{ .Release.Service }} 9 | release: {{ .Release.Name }} 10 | name: {{ template "multi-casskop.name" . }} 11 | subjects: 12 | - kind: ServiceAccount 13 | name: {{ template "multi-casskop.name" . }} 14 | roleRef: 15 | kind: Role 16 | name: {{ template "multi-casskop.name" . }} 17 | apiGroup: rbac.authorization.k8s.io 18 | {{- end }} 19 | -------------------------------------------------------------------------------- /multi-casskop/helm/multi-casskop/templates/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.metricService }} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ template "multi-casskop.name" . }}-metrics 6 | labels: 7 | component: app 8 | app: {{ template "multi-casskop.name" . }}-metrics 9 | chart: {{ .Chart.Name }}-{{ .Chart.Version }} 10 | heritage: {{ .Release.Service }} 11 | release: {{ .Release.Name }} 12 | spec: 13 | selector: 14 | app: {{ template "multi-casskop.name" . }} 15 | ports: 16 | - name: metrics 17 | port: 9710 18 | protocol: TCP 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /multi-casskop/helm/multi-casskop/templates/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app: {{ template "multi-casskop.name" . }} 6 | chart: {{ .Chart.Name }}-{{ .Chart.Version }} 7 | heritage: {{ .Release.Service }} 8 | release: {{ .Release.Name }} 9 | name: {{ template "multi-casskop.name" . }} 10 | -------------------------------------------------------------------------------- /multi-casskop/helm/multi-casskop/values.yaml: -------------------------------------------------------------------------------- 1 | ## Cassandra Operator Image 2 | ## 3 | image: 4 | repository: orangeopensource/multi-casskop 5 | tag: v2.1.0-release 6 | pullPolicy: Always 7 | imagePullSecrets: 8 | enabled: false 9 | 10 | resources: 11 | requests: 12 | cpu: 10m 13 | memory: 50Mi 14 | limits: 15 | cpu: 1 16 | memory: 512Mi 17 | 18 | ## If true, create & deploy the CRD 19 | ## 20 | createCustomResource: true 21 | 22 | ## If true, create & use RBAC resources 23 | ## 24 | rbacEnable: true 25 | 26 | ## if true deploy service for metrics access 27 | metricService: false 28 | 29 | debug: 30 | enabled: false 31 | 32 | command: /usr/local/bin/multi-casskop 33 | 34 | #this can be surcharge with --set k8s.local=k8s-cluster1 --set k8s.remote={k8s-cluster2,k8s-cluster3} 35 | k8s: 36 | local: k8s-cluster1 37 | remote: 38 | - k8s-cluster2 39 | -------------------------------------------------------------------------------- /multi-casskop/version/version.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Orange 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 | 15 | package version 16 | 17 | var ( 18 | Version = "2.1.0" 19 | ) 20 | -------------------------------------------------------------------------------- /pkg/cassandrabackup/client.go: -------------------------------------------------------------------------------- 1 | package cassandrabackup 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | api "github.com/Orange-OpenSource/casskop/api/v2" 8 | icarus "github.com/instaclustr/instaclustr-icarus-go-client/pkg/instaclustr_icarus" 9 | corev1 "k8s.io/api/core/v1" 10 | controllerclient "sigs.k8s.io/controller-runtime/pkg/client" 11 | ) 12 | 13 | type Client interface { 14 | PerformRestoreOperation(restoreOperation icarus.RestoreOperationRequest) (*icarus.RestoreOperationResponse, error) 15 | RestoreOperationByID(operationId string) (*icarus.RestoreOperationResponse, error) 16 | PerformBackupOperation(request icarus.BackupOperationRequest) (*icarus.BackupOperationResponse, error) 17 | BackupOperationByID(id string) (response *icarus.BackupOperationResponse, err error) 18 | Build() error 19 | } 20 | 21 | type client struct { 22 | Client 23 | config *Config 24 | podClient *icarus.APIClient 25 | 26 | newClient func(*icarus.Configuration) *icarus.APIClient 27 | } 28 | 29 | func New(config *Config) Client { 30 | return &client{config: config, newClient: icarus.NewAPIClient} 31 | } 32 | 33 | func (cs *client) Build() error { 34 | cs.podClient = cs.newClient( cs.cassandraBackupSidecarConfig()) 35 | return nil 36 | } 37 | 38 | func ClientFromCluster(k8sClient controllerclient.Client, cluster *api.CassandraCluster, 39 | pod *corev1.Pod) (Client, error) { 40 | config := ClusterConfig(k8sClient, cluster, pod) 41 | 42 | client := New(config) 43 | err := client.Build() 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | return client, nil 49 | } 50 | 51 | func (cs *client) cassandraBackupSidecarConfig() (config *icarus.Configuration) { 52 | config = icarus.NewConfiguration() 53 | 54 | protocol := "http" 55 | 56 | if cs.config.UseSSL { 57 | config.Scheme = "HTTPS" 58 | transport := &http.Transport{TLSClientConfig: cs.config.TLSConfig} 59 | config.HTTPClient = &http.Client{Transport: transport, Timeout: cs.config.Timeout} 60 | protocol = "https" 61 | } 62 | 63 | config.BasePath = fmt.Sprintf("%s://%s:%d", protocol,cs.config.Host, cs.config.Port) 64 | //config.Host = cs.config.Host 65 | 66 | return config 67 | } -------------------------------------------------------------------------------- /pkg/cassandrabackup/client_test.go: -------------------------------------------------------------------------------- 1 | package cassandrabackup 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestNew(t *testing.T) { 12 | opts := newMockOpts() 13 | if client := New(opts); client == nil { 14 | t.Error("Expected new client, got nil") 15 | } 16 | } 17 | 18 | func TestBuild(t *testing.T) { 19 | client := newMockClient() 20 | if err := client.Build(); err != nil { 21 | t.Error("Expected to build mock client, got error:", err) 22 | } 23 | } 24 | 25 | func TestGetCassandraPodSidecarConfig(t *testing.T) { 26 | assert := assert.New(t) 27 | 28 | client := newMockClient() 29 | client.config.UseSSL = true 30 | client.config.TLSConfig = &tls.Config{} 31 | 32 | conf := client.cassandraBackupSidecarConfig() 33 | 34 | assert.Equal("HTTPS", conf.Scheme) 35 | assert.Equal(fmt.Sprintf("https://%s:4567", hostnamePodA), conf.BasePath) 36 | } 37 | -------------------------------------------------------------------------------- /pkg/cassandrabackup/common.go: -------------------------------------------------------------------------------- 1 | package cassandrabackup 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | var ErrCassandraSidecarNotReturned200 = errors.New("Non 200 response from cassandra backup sidecar") 8 | var ErrCassandraSidecarNotReturned201 = errors.New("Non 201 response from cassandra backup sidecar") 9 | var ErrNoCassandraBackupClientAvailable = errors.New("Cannot create a cassandra backup client") -------------------------------------------------------------------------------- /pkg/cassandrabackup/config.go: -------------------------------------------------------------------------------- 1 | package cassandrabackup 2 | 3 | import ( 4 | "crypto/tls" 5 | "time" 6 | 7 | api "github.com/Orange-OpenSource/casskop/api/v2" 8 | "github.com/Orange-OpenSource/casskop/pkg/k8s" 9 | corev1 "k8s.io/api/core/v1" 10 | controllerclient "sigs.k8s.io/controller-runtime/pkg/client" 11 | ) 12 | 13 | const ( 14 | DefaultCassandraSidecarPort = 4567 15 | DefaultCassandraBackupSecure = false 16 | ) 17 | 18 | type Config struct { 19 | UseSSL bool 20 | TLSConfig *tls.Config 21 | Port int32 22 | Host string 23 | Timeout time.Duration 24 | } 25 | 26 | func ClusterConfig(client controllerclient.Client, cluster *api.CassandraCluster, pod *corev1.Pod) *Config { 27 | conf := &Config{} 28 | conf.UseSSL = DefaultCassandraBackupSecure 29 | conf.Port = DefaultCassandraSidecarPort 30 | conf.Host = k8s.PodHostname(*pod) 31 | 32 | if conf.Timeout == 0 { 33 | conf.Timeout = 1 * time.Minute 34 | } 35 | 36 | return conf 37 | } 38 | -------------------------------------------------------------------------------- /pkg/common/operations/operations.go: -------------------------------------------------------------------------------- 1 | package operations 2 | 3 | const ( 4 | RUNNING = "RUNNING" 5 | PENDING = "PENDING" 6 | COMPLETED = "COMPLETED" 7 | FAILED = "FAILED" 8 | UNKNOWN = "UNKNOWN" 9 | ) 10 | -------------------------------------------------------------------------------- /pkg/errorfactory/errorfactory.go: -------------------------------------------------------------------------------- 1 | package errorfactory 2 | 3 | import "emperror.dev/errors" 4 | 5 | // ResourceNotReady states that resource is not ready 6 | type ResourceNotReady struct{ error } 7 | 8 | // APIFailure states that something went wrong with the api 9 | type APIFailure struct{ error } 10 | 11 | // StatusUpdateError states that the operator failed to update the Status 12 | type StatusUpdateError struct{ error } 13 | 14 | // CassandraBackupSidecarNotReady states that Sidecar is not ready to receive connection 15 | type CassandraBackupSidecarNotReady struct{ error } 16 | 17 | // CassandraBackupOperationRunning states that Sidecar Operation is still running 18 | type CassandraBackupOperationRunning struct{ error } 19 | 20 | //CassandraBackupOperationFailure states that Sidecar Operation was not found (Sidecar restart?) or failed 21 | type CassandraBackupOperationFailure struct{ error } 22 | 23 | // New creates a new error factory error 24 | func New(t interface{}, err error, msg string, wrapArgs ...interface{}) error { 25 | wrapped := errors.WrapIfWithDetails(err, msg, wrapArgs...) 26 | switch t.(type) { 27 | case ResourceNotReady: 28 | return ResourceNotReady{wrapped} 29 | case APIFailure: 30 | return APIFailure{wrapped} 31 | case StatusUpdateError: 32 | return StatusUpdateError{wrapped} 33 | case CassandraBackupSidecarNotReady: 34 | return CassandraBackupSidecarNotReady{wrapped} 35 | case CassandraBackupOperationRunning: 36 | return CassandraBackupOperationRunning{wrapped} 37 | case CassandraBackupOperationFailure: 38 | return CassandraBackupOperationFailure{wrapped} 39 | } 40 | return wrapped 41 | } 42 | -------------------------------------------------------------------------------- /pkg/util/util.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Banzai Cloud 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 | 15 | package util 16 | 17 | const( 18 | TimeStampLayout = "Mon, 2 Jan 2006 15:04:05 GMT" 19 | ) 20 | 21 | // StringSliceContains returns true if list contains s 22 | func StringSliceContains(list []string, s string) bool { 23 | for _, v := range list { 24 | if v == s { 25 | return true 26 | } 27 | } 28 | return false 29 | } 30 | 31 | // StringSliceRemove will remove s from list 32 | func StringSliceRemove(list []string, s string) []string { 33 | for i, v := range list { 34 | if v == s { 35 | list = append(list[:i], list[i+1:]...) 36 | } 37 | } 38 | return list 39 | } -------------------------------------------------------------------------------- /static/casskop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/static/casskop.png -------------------------------------------------------------------------------- /static/multi-casskop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/static/multi-casskop.png -------------------------------------------------------------------------------- /test/kuttl/kuttl-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestSuite 3 | testDirs: 4 | - . 5 | timeout: 600 6 | -------------------------------------------------------------------------------- /test/kuttl/multi-dcs/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: cassandra-e2e-dc1-rack1 5 | status: 6 | currentReplicas: 1 7 | replicas: 1 8 | --- 9 | apiVersion: db.orange.com/v2 10 | kind: CassandraCluster 11 | metadata: 12 | name: cassandra-e2e 13 | status: 14 | lastClusterAction: Initializing 15 | lastClusterActionStatus: Done 16 | phase: Running 17 | -------------------------------------------------------------------------------- /test/kuttl/multi-dcs/00-createCluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-e2e 5 | spec: 6 | nodesPerRacks: 1 7 | cassandraImage: cassandra:3.11.9 8 | dataCapacity: "256Mi" 9 | deletePVC: true 10 | autoPilot: true 11 | autoUpdateSeedList: true 12 | dataStorageClass: local-path 13 | resources: 14 | limits: 15 | memory: 512Mi 16 | cpu: 200m 17 | topology: 18 | dc: 19 | - name: dc1 20 | rack: 21 | - name: rack1 22 | -------------------------------------------------------------------------------- /test/kuttl/multi-dcs/01-addDC.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-e2e 5 | spec: 6 | topology: 7 | dc: 8 | - name: dc1 9 | rack: 10 | - name: rack1 11 | - name: dc2 12 | rack: 13 | - name: rack1 14 | -------------------------------------------------------------------------------- /test/kuttl/multi-dcs/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: cassandra-e2e-dc1-rack1 5 | status: 6 | currentReplicas: 1 7 | replicas: 1 8 | --- 9 | apiVersion: apps/v1 10 | kind: StatefulSet 11 | metadata: 12 | name: cassandra-e2e-dc2-rack1 13 | status: 14 | currentReplicas: 1 15 | replicas: 1 16 | --- 17 | apiVersion: db.orange.com/v2 18 | kind: CassandraCluster 19 | metadata: 20 | name: cassandra-e2e 21 | status: 22 | lastClusterAction: Initializing 23 | lastClusterActionStatus: Done 24 | phase: Running 25 | -------------------------------------------------------------------------------- /test/kuttl/multi-dcs/02-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: cassandra-e2e-dc1-rack1 5 | status: 6 | currentReplicas: 1 7 | replicas: 1 8 | --- 9 | apiVersion: apps/v1 10 | kind: StatefulSet 11 | metadata: 12 | name: cassandra-e2e-dc2-rack1 13 | status: 14 | currentReplicas: 1 15 | replicas: 1 16 | --- 17 | apiVersion: db.orange.com/v2 18 | kind: CassandraCluster 19 | metadata: 20 | name: cassandra-e2e 21 | status: 22 | lastClusterAction: CorrectCRDConfig 23 | lastClusterActionStatus: Done 24 | phase: Running 25 | -------------------------------------------------------------------------------- /test/kuttl/multi-dcs/02-unallowedScaleDown.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-e2e 5 | spec: 6 | topology: 7 | dc: 8 | - name: dc1 9 | nodesPerRacks: 0 10 | -------------------------------------------------------------------------------- /test/kuttl/multi-dcs/03-disableReplToDC2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestStep 3 | commands: 4 | # Replicate system_auth, system_traces and system_distributed to dc1 only 5 | - script: | 6 | for keyspace in system_auth system_traces system_distributed 7 | do 8 | kubectl exec -n $NAMESPACE cassandra-e2e-dc1-rack1-0 -- cqlsh -e "ALTER KEYSPACE $keyspace WITH replication = {'class': 'NetworkTopologyStrategy', 'dc1': '1'}" 9 | done 10 | -------------------------------------------------------------------------------- /test/kuttl/multi-dcs/04-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: cassandra-e2e-dc1-rack1 5 | status: 6 | currentReplicas: 1 7 | replicas: 1 8 | --- 9 | apiVersion: apps/v1 10 | kind: StatefulSet 11 | metadata: 12 | name: cassandra-e2e-dc2-rack1 13 | status: 14 | replicas: 0 15 | --- 16 | apiVersion: db.orange.com/v2 17 | kind: CassandraCluster 18 | metadata: 19 | name: cassandra-e2e 20 | status: 21 | lastClusterAction: UpdateSeedList 22 | lastClusterActionStatus: Done 23 | phase: Running 24 | -------------------------------------------------------------------------------- /test/kuttl/multi-dcs/04-scaleDownDC2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-e2e 5 | spec: 6 | topology: 7 | dc: 8 | - name: dc1 9 | rack: 10 | - name: rack1 11 | - name: dc2 12 | nodesPerRacks: 0 13 | rack: 14 | - name: rack1 15 | -------------------------------------------------------------------------------- /test/kuttl/multi-dcs/05-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: cassandra-e2e-dc1-rack1 5 | status: 6 | currentReplicas: 1 7 | replicas: 1 8 | --- 9 | apiVersion: db.orange.com/v2 10 | kind: CassandraCluster 11 | metadata: 12 | name: cassandra-e2e 13 | status: 14 | lastClusterAction: ActionDeleteDC 15 | lastClusterActionStatus: Done 16 | phase: Running 17 | -------------------------------------------------------------------------------- /test/kuttl/multi-dcs/05-removeDC.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-e2e 5 | spec: 6 | topology: 7 | dc: 8 | - name: dc1 9 | rack: 10 | - name: rack1 11 | -------------------------------------------------------------------------------- /test/kuttl/operations/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: cassandra-e2e-dc1-rack1 5 | status: 6 | currentReplicas: 2 7 | replicas: 2 8 | --- 9 | apiVersion: db.orange.com/v2 10 | kind: CassandraCluster 11 | metadata: 12 | name: cassandra-e2e 13 | status: 14 | cassandraRackStatus: 15 | dc1-rack1: 16 | cassandraLastAction: 17 | name: Initializing 18 | status: Done 19 | phase: Running 20 | lastClusterAction: Initializing 21 | lastClusterActionStatus: Done 22 | phase: Running -------------------------------------------------------------------------------- /test/kuttl/operations/00-createCluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: configmap-v1 5 | data: 6 | pre_run.sh: |- 7 | echo example1 8 | --- 9 | apiVersion: db.orange.com/v2 10 | kind: CassandraCluster 11 | metadata: 12 | name: cassandra-e2e 13 | spec: 14 | nodesPerRacks: 2 15 | cassandraImage: cassandra:3.11.9 16 | configMapName: configmap-v1 17 | autoPilot: true 18 | resources: 19 | limits: 20 | cpu: 300m 21 | memory: 512Mi 22 | topology: 23 | dc: 24 | - name: dc1 25 | rack: 26 | - name: rack1 27 | -------------------------------------------------------------------------------- /test/kuttl/operations/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-e2e 5 | spec: 6 | nodesPerRacks: 2 7 | status: 8 | cassandraRackStatus: 9 | dc1-rack1: 10 | cassandraLastAction: 11 | name: RollingRestart 12 | status: Done -------------------------------------------------------------------------------- /test/kuttl/operations/01-rollingRestart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-e2e 5 | spec: 6 | nodesPerRacks: 2 7 | topology: 8 | dc: 9 | - name: dc1 10 | rack: 11 | - name: rack1 12 | rollingRestart: true -------------------------------------------------------------------------------- /test/kuttl/operations/02-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-e2e 5 | status: 6 | cassandraRackStatus: 7 | dc1-rack1: 8 | cassandraLastAction: 9 | name: UpdateConfigMap 10 | status: Done -------------------------------------------------------------------------------- /test/kuttl/operations/02-updateConfigmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: configmap-v2 5 | data: 6 | pre_run.sh: |- 7 | echo example2 8 | --- 9 | apiVersion: db.orange.com/v2 10 | kind: CassandraCluster 11 | metadata: 12 | name: cassandra-e2e 13 | spec: 14 | configMapName: configmap-v2 -------------------------------------------------------------------------------- /test/kuttl/operations/03-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: cassandra-e2e-dc1-rack1-0 5 | labels: 6 | operation-name: cleanup 7 | operation-status: Done 8 | --- 9 | apiVersion: v1 10 | kind: Pod 11 | metadata: 12 | name: cassandra-e2e-dc1-rack1-1 13 | labels: 14 | operation-name: cleanup 15 | operation-status: Done 16 | -------------------------------------------------------------------------------- /test/kuttl/operations/03-cleanup.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: cassandra-e2e-dc1-rack1-0 5 | labels: 6 | operation-name: cleanup 7 | operation-status: ToDo 8 | --- 9 | apiVersion: v1 10 | kind: Pod 11 | metadata: 12 | name: cassandra-e2e-dc1-rack1-1 13 | labels: 14 | operation-name: cleanup 15 | operation-status: ToDo 16 | -------------------------------------------------------------------------------- /test/kuttl/scaling/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: cassandra-e2e-dc1-rack1 5 | status: 6 | currentReplicas: 1 7 | replicas: 1 8 | --- 9 | apiVersion: db.orange.com/v2 10 | kind: CassandraCluster 11 | metadata: 12 | name: cassandra-e2e 13 | status: 14 | cassandraRackStatus: 15 | dc1-rack1: 16 | cassandraLastAction: 17 | name: Initializing 18 | status: Done 19 | phase: Running 20 | lastClusterAction: Initializing 21 | lastClusterActionStatus: Done 22 | phase: Running -------------------------------------------------------------------------------- /test/kuttl/scaling/00-createCluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-e2e 5 | spec: 6 | nodesPerRacks: 1 7 | cassandraImage: cassandra:4.0-rc1 8 | serverVersion: 4.0.0 9 | config: 10 | jvm-options: 11 | initial_heap_size: 32M 12 | max_heap_size: 256M 13 | deletePVC: true 14 | autoPilot: true 15 | backRestSidecar: 16 | resources: 17 | limits: 18 | memory: 128Mi 19 | cpu: 100m 20 | resources: 21 | limits: 22 | cpu: 200m 23 | memory: 512Mi 24 | topology: 25 | dc: 26 | - name: dc1 27 | rack: 28 | - name: rack1 -------------------------------------------------------------------------------- /test/kuttl/scaling/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: cassandra-e2e-dc1-rack1 5 | status: 6 | currentReplicas: 2 7 | replicas: 2 8 | --- 9 | apiVersion: db.orange.com/v2 10 | kind: CassandraCluster 11 | metadata: 12 | name: cassandra-e2e 13 | spec: 14 | nodesPerRacks: 2 15 | status: 16 | cassandraRackStatus: 17 | dc1-rack1: 18 | cassandraLastAction: 19 | name: ScaleUp 20 | status: Done -------------------------------------------------------------------------------- /test/kuttl/scaling/01-scaleUp.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-e2e 5 | spec: 6 | nodesPerRacks: 2 7 | topology: 8 | dc: 9 | - name: dc1 10 | rack: 11 | - name: rack1 -------------------------------------------------------------------------------- /test/kuttl/scaling/02-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kuttl.dev/v1beta1 2 | kind: TestAssert 3 | timeout: 500 4 | --- 5 | apiVersion: apps/v1 6 | kind: StatefulSet 7 | metadata: 8 | name: cassandra-e2e-dc1-rack1 9 | status: 10 | currentReplicas: 1 11 | replicas: 1 12 | --- 13 | apiVersion: db.orange.com/v2 14 | kind: CassandraCluster 15 | metadata: 16 | name: cassandra-e2e 17 | spec: 18 | nodesPerRacks: 1 19 | status: 20 | cassandraRackStatus: 21 | dc1-rack1: 22 | cassandraLastAction: 23 | name: ScaleDown 24 | status: Done -------------------------------------------------------------------------------- /test/kuttl/scaling/02-scaleDown.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-e2e 5 | spec: 6 | nodesPerRacks: 1 7 | topology: 8 | dc: 9 | - name: dc1 10 | rack: 11 | - name: rack1 -------------------------------------------------------------------------------- /test/kuttl/sidecars/00-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: gc-logs-cassandra-e2e-dc1-rack1-0 5 | spec: 6 | accessModes: 7 | - ReadWriteOnce 8 | resources: 9 | requests: 10 | storage: 200Mi 11 | storageClassName: local-path 12 | volumeMode: Filesystem 13 | status: 14 | accessModes: 15 | - ReadWriteOnce 16 | phase: Bound 17 | --- 18 | apiVersion: v1 19 | kind: PersistentVolumeClaim 20 | metadata: 21 | name: data-cassandra-e2e-dc1-rack1-0 22 | spec: 23 | accessModes: 24 | - ReadWriteOnce 25 | resources: 26 | requests: 27 | storage: 256Mi 28 | storageClassName: local-path 29 | volumeMode: Filesystem 30 | status: 31 | accessModes: 32 | - ReadWriteOnce 33 | phase: Bound 34 | --- 35 | apiVersion: apps/v1 36 | kind: StatefulSet 37 | metadata: 38 | name: cassandra-e2e-dc1-rack1 39 | spec: 40 | replicas: 1 41 | serviceName: cassandra-e2e 42 | template: 43 | spec: 44 | initContainers: 45 | - name: base-config-builder 46 | image: cassandra:3.11.9 47 | - name: config-builder 48 | image: datastax/cass-config-builder:1.0.3 49 | - name: bootstrap 50 | image: orangeopensource/cassandra-bootstrap:0.1.9 51 | containers: 52 | - args: 53 | - tail 54 | - -F 55 | - /var/log/cassandra/gc.log.0.current 56 | image: ez123/alpine-tini 57 | name: cassandra-log 58 | resources: 59 | limits: 60 | cpu: 50m 61 | memory: 50Mi 62 | requests: 63 | cpu: 10m 64 | memory: 10Mi 65 | volumeMounts: 66 | - mountPath: /var/log/cassandra 67 | name: gc-logs 68 | - name: cassandra 69 | - name: backrest-sidecar 70 | status: 71 | readyReplicas: 1 72 | replicas: 1 73 | --- 74 | apiVersion: db.orange.com/v2 75 | kind: CassandraCluster 76 | metadata: 77 | name: cassandra-e2e 78 | status: 79 | lastClusterAction: Initializing 80 | lastClusterActionStatus: Done 81 | phase: Running 82 | 83 | -------------------------------------------------------------------------------- /test/kuttl/sidecars/00-clusterWithTwoSidecars.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: db.orange.com/v2 2 | kind: CassandraCluster 3 | metadata: 4 | name: cassandra-e2e 5 | spec: 6 | nodesPerRacks: 1 7 | cassandraImage: cassandra:3.11.9 8 | configBuilderImage: datastax/cass-config-builder:1.0.3 9 | dataCapacity: "256Mi" 10 | hardAntiAffinity: false 11 | deletePVC: true 12 | autoPilot: true 13 | autoUpdateSeedList: false 14 | dataStorageClass: local-path 15 | resources: 16 | limits: 17 | memory: 512Mi 18 | cpu: 200m 19 | topology: 20 | dc: 21 | - name: dc1 22 | rack: 23 | - name: rack1 24 | storageConfigs: 25 | - mountPath: /var/lib/cassandra/log 26 | name: gc-logs 27 | pvcSpec: 28 | accessModes: 29 | - ReadWriteOnce 30 | storageClassName: local-path 31 | resources: 32 | requests: 33 | storage: 200Mi 34 | sidecarConfigs: 35 | - args: ["tail", "-F", "/var/log/cassandra/gc.log.0.current"] 36 | image: ez123/alpine-tini 37 | name: cassandra-log 38 | resources: 39 | limits: 40 | cpu: 50m 41 | memory: 50Mi 42 | requests: 43 | cpu: 10m 44 | memory: 10Mi 45 | volumeMounts: 46 | - mountPath: /var/log/cassandra 47 | name: gc-logs 48 | -------------------------------------------------------------------------------- /tools/circleci-get-logs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while true; do 4 | NAME=$(kubectl -n cassandra-e2e get pods -l app=casskop -o jsonpath='{range .items[*]}{.metadata.name}'); 5 | READY=$(kubectl -n cassandra-e2e get pods -l app=casskop -o jsonpath='{range .items[*]}{.status.containerStatuses[0].ready}'); 6 | 7 | if [[ "$NAME" != "" ]] && [[ "$READY" == "true" ]]; then 8 | break; 9 | fi 10 | echo "wait for logs: $NAME=$READY"; 11 | sleep 10; 12 | done ; 13 | 14 | echo "Get Operator logs: $NAME"; 15 | 16 | kubectl -n cassandra-e2e logs $NAME -f > operator.log 17 | -------------------------------------------------------------------------------- /tools/configure-dind-local-storage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | KUBE_NODES=$(kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{" "}') 4 | NB_PV=5 5 | 6 | if [ "$1" == "create" ]; then 7 | 8 | kubectl apply -f tools/storageclass-local-storage.yaml 9 | 10 | for n in $KUBE_NODES; do 11 | echo $n 12 | for i in `seq -w 1 $NB_PV`; do 13 | echo docker exec -ti $n bash -c "mkdir -p /dind/local-storage/pv$i" 14 | docker exec -ti $n bash -c "mkdir -p /dind/local-storage/pv$i" 15 | 16 | docker exec -ti $n bash -c "mount -t tmpfs pv$i /dind/local-storage/pv$i" 17 | done 18 | done 19 | 20 | kubectl apply -f tools/provisioner_generated.yaml 21 | 22 | fi 23 | 24 | if [ "$1" == "delete" ]; then 25 | for n in $KUBE_NODES; do 26 | echo $n 27 | for i in `seq -w 1 $NB_PV`; do 28 | kubectl delete pv local-pv-$n-$i 29 | done 30 | done 31 | fi 32 | -------------------------------------------------------------------------------- /tools/create_dind_cluster.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo $https_proxy 3 | #export DIND_PROPAGATE_HTTP_PROXY=true 4 | export DIND_HTTP_PROXY=$http_proxy 5 | export DIND_HTTPS_PROXY=$https_proxy 6 | export DIND_NO_PROXY=$no_proxy 7 | 8 | echo "Create K8s cluster" 9 | NUM_NODES=3 dind-cluster up 10 | 11 | echo "Configure local-storage" 12 | kubectl create namespace local-provisioner 13 | kubectl config set-context $(kubectl config current-context) --namespace=local-provisioner 14 | tools/configure-dind-local-storage.sh create 15 | 16 | 17 | echo "label nodes" 18 | kubectl label node kube-node-1 failure-domain.beta.kubernetes.io/region="europe-west2" 19 | kubectl label node kube-node-1 location.physical/rack="1" 20 | kubectl label node kube-node-1 failure-domain.beta.kubernetes.io/region="europe-west2" 21 | kubectl label node kube-node-1 location.physical/rack="2" 22 | 23 | echo "create cassandra namespace" 24 | kubectl create namespace cassandra-demo 25 | kubectl config set-context $(kubectl config current-context) --namespace=cassandra-demo 26 | 27 | echo "Create CRD" 28 | kubectl apply -f config/crd/bases/db.orange.com_cassandraclusters.yaml 29 | 30 | echo "configure helm" 31 | helm init 32 | -------------------------------------------------------------------------------- /tools/e2e_test_cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Deleting test namespaces" 4 | for x in $(kns | egrep "group|main-"); do echo $x ; k delete namespace --grace-period=0 --force $x ; done 5 | 6 | echo "Deleting CRD" 7 | kubectl delete -f config/crd/bases/db.orange.com_cassandraclusters.yaml 8 | -------------------------------------------------------------------------------- /tools/health/go.mod: -------------------------------------------------------------------------------- 1 | module main.go 2 | 3 | go 1.12 4 | 5 | require github.com/sirupsen/logrus v1.4.2 6 | -------------------------------------------------------------------------------- /tools/health/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= 3 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= 6 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 7 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 8 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 9 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= 10 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 11 | -------------------------------------------------------------------------------- /tools/health/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Orange 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 | 15 | //In scratch docker container, there is no binary and we cannot stat the file 16 | // this binary goal is to be used by the k8s healthcheck for CassKop 17 | 18 | package main 19 | 20 | import ( 21 | "os" 22 | 23 | "github.com/sirupsen/logrus" 24 | ) 25 | 26 | func main() { 27 | if _, err := os.Stat("/tmp/operator-sdk-ready"); err == nil { 28 | os.Exit(0) 29 | 30 | } else if os.IsNotExist(err) { 31 | logrus.Infof("error file don't exists : %v", err) 32 | os.Exit(1) 33 | } else { 34 | logrus.Infof("error %v", err) 35 | os.Exit(1) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tools/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # The following line is needed by the CircleCI Local Build Tool (due to Docker interactivity) 4 | exec < /dev/tty 5 | 6 | # If validation fails, tell Git to stop and provide error message. Otherwise, continue. 7 | if ! eMSG=$(circleci config validate -c .circleci/config.yml); then 8 | echo "CircleCI Configuration Failed Validation." 9 | echo $eMSG 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /tools/storageclass-local-storage.yaml: -------------------------------------------------------------------------------- 1 | kind: StorageClass 2 | apiVersion: storage.k8s.io/v1 3 | metadata: 4 | name: local-storage 5 | provisioner: kubernetes.io/no-provisioner 6 | volumeBindingMode: WaitForFirstConsumer 7 | -------------------------------------------------------------------------------- /version/version.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Orange 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 | 15 | package version 16 | 17 | var ( 18 | Version = "2.1.0" 19 | ) 20 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | ``` 8 | $ yarn 9 | ``` 10 | 11 | ### Local Development 12 | 13 | ``` 14 | $ yarn start 15 | ``` 16 | 17 | This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### Build 20 | 21 | ``` 22 | $ yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ### Deployment 28 | 29 | ``` 30 | $ GIT_USER= USE_SSH=true yarn deploy 31 | ``` 32 | 33 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 34 | -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /website/docs/2_setup/2_install_plugin.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 2_install_plugin 3 | title: Install Plugin 4 | sidebar_label: Install Plugin 5 | --- 6 | You can install the plugin by copying the [file](https://github.com/Orange-OpenSource/casskop/tree/master/plugins/kubectl-casskop) into your PATH. 7 | 8 | For example on a linux/ mac machine: 9 | 10 | ```console 11 | cp plugins/kubectl-casskop /usr/local/bin 12 | ``` 13 | 14 | Then you can test the plugin: 15 | 16 | ```console 17 | kubectl casskop 18 | 19 | usage: kubectl-casskop [] 20 | 21 | The available commands are: 22 | cleanup 23 | upgradesstables 24 | rebuild 25 | remove 26 | restart 27 | pause 28 | unpause 29 | 30 | For more information you can run kubectl-casskop --help 31 | kubectl-casskop: error: the following arguments are required: command 32 | ``` 33 | 34 | Your CassKop plugin is now installed! 35 | -------------------------------------------------------------------------------- /website/docs/2_setup/4_platform_setup/1_gke.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 1_gke 3 | title: Google Kubernetes Engine 4 | sidebar_label: Google Kubernetes Engine 5 | --- 6 | 7 | Follow these instructions to prepare a GKE cluster for Casskop 8 | 9 | 1. Setup environment variables. 10 | 11 | ```sh 12 | export GCP_PROJECT= 13 | export GCP_ZONE= 14 | export CLUSTER_NAME= 15 | ``` 16 | 17 | 2. Create a new cluster. 18 | 19 | ```sh 20 | gcloud container clusters create $CLUSTER_NAME \ 21 | --cluster-version latest \ 22 | --machine-type=n1-standard-1 \ 23 | --num-nodes 4 \ 24 | --zone $GCP_ZONE \ 25 | --project $GCP_PROJECT 26 | ``` 27 | 28 | 3. Retrieve your credentials for `kubectl`. 29 | 30 | ```sh 31 | cloud container clusters get-credentials $CLUSTER_NAME \ 32 | --zone $GCP_ZONE \ 33 | --project $GCP_PROJECT 34 | ``` 35 | 36 | 4. Grant cluster administrator (admin) permissions to the current user. To create the necessary RBAC rules for Casskop, the current user requires admin permissions. 37 | 38 | ```sh 39 | kubectl create clusterrolebinding cluster-admin-binding \ 40 | --clusterrole=cluster-admin \ 41 | --user=$(gcloud config get-value core/account) 42 | ``` 43 | -------------------------------------------------------------------------------- /website/docs/2_setup/4_platform_setup/2_minikube.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 2_minikube 3 | title: MiniKube 4 | sidebar_label: MiniKube 5 | --- 6 | 7 | Follow these instructions to prepare minikube for Casskop installation with sufficient resources to run Casskop and some basic applications. 8 | 9 | ## Prerequisites 10 | 11 | - Administrative privileges are required to run minikube. 12 | 13 | ## Installation steps 14 | 15 | 1. Install the latest version of [minikube](https://kubernetes.io/docs/setup/learning-environment/minikube/), version 1.1.1 or later, and a [minikube hypervisor driver](https://kubernetes.io/docs/tasks/tools/install-minikube/#install-a-hypervisor). 16 | 2. If you’re not using the default driver, set your minikube hypervisor driver. 17 | For example, if you installed the KVM hypervisor, set the vm-driver within the minikube configuration using the following command: 18 | 19 | ```sh 20 | minikube config set vm-driver kvm2 21 | ``` 22 | 3. Start minikube with 16384 MB of memory and 4 CPUs. This example uses Kubernetes version 1.14.2. You can change the version to any Kubernetes version supported by Casskop by altering the --kubernetes-version value: 23 | 24 | ```sh 25 | $ minikube start --memory=16384 --cpus=4 --kubernetes-version=v1.14.2 26 | ``` 27 | 28 | Depending on the hypervisor you use and the platform on which the hypervisor is run, minimum memory requirements vary. 16384 MB is sufficent to run Casskop. 29 | 30 | :::tip 31 | If you don’t have enough RAM allocated to the minikube virtual machine, the following errors could occur: 32 | - Image pull failures 33 | - Healthcheck timeout failures 34 | - Kubectl failures on the host 35 | - General network instability of the virtual machine and the host 36 | - Complete lock-up of the virtual machine 37 | - Host NMI watchdog reboots 38 | - One effective way to monitor memory usage in minikube: 39 | 40 | ```sh 41 | minikube ssh 42 | top 43 | ``` 44 | ::: 45 | -------------------------------------------------------------------------------- /website/docs/5_operations/4_upgrade_operator.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 4_upgrade_operator 3 | title: Upgrade Operator 4 | sidebar_label: Upgrade Operator 5 | --- 6 | 7 | ## Case : No changes of the CRD's structure 8 | 9 | Upgrading the operator consists in uninstalling the current version and installing the new version : 10 | 11 | ``` 12 | helm uninstall casskop 13 | helm repo update 14 | helm install --name casskop casskop/cassandra-operator 15 | ``` 16 | 17 | ## Upgrading from v1 to v2 18 | 19 | Please refer to [the specific v1 to v2 section](/casskop/docs/2_setup/5_upgrade_v1_to_v2) for the step by step protocol. 20 | -------------------------------------------------------------------------------- /website/docs/5_operations/6_uninstall_casskop.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 5_uninstall_casskop 3 | title: Uninstall Casskop 4 | sidebar_label: Uninstall Casskop 5 | --- 6 | 7 | ## Uninstaling the Charts 8 | 9 | If you want to delete the operator from your Kubernetes cluster, the operator deployment 10 | should be deleted. 11 | 12 | ``` 13 | $ helm uninstall casskop 14 | ``` 15 | The command removes all the Kubernetes components associated with the chart and deletes the helm release. 16 | 17 | > The CRDs created by the chart are not removed by Helm and should be manually cleaned up (if required) 18 | 19 | Manually delete the CRDs: 20 | ``` 21 | kubectl delete crd cassandraclusters.db.orange.com 22 | kubectl delete crd cassandrabackups.db.orange.com 23 | kubectl delete crd cassandrarestores.db.orange.com 24 | ``` 25 | 26 | > :triangular_flag_on_post: If you delete the CRDs then : It will delete **ALL** Clusters that has been created using these CRDs!!! 27 | > Please never delete CRDs without very very good care 28 | -------------------------------------------------------------------------------- /website/docs/6_references/2_topology.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 2_topology 3 | title: Topology 4 | sidebar_label: Topology 5 | --- 6 | 7 | ## Topology 8 | 9 | |Field|Type|Description|Required|Default| 10 | |-----|----|-----------|--------|--------| 11 | |dc|\[ \][DC](#dc)|List of DC defined in the CassandraCluster.|Yes| - | 12 | 13 | ## DC 14 | 15 | |Field|Type|Description|Required|Default| 16 | |-----|----|-----------|--------|--------| 17 | |name|string|Name of the DC|Yes|dc1| 18 | |labels|map\[string\]string|Labels used to target Kubernetes nodes|No|| 19 | |rack|\[ \][Rack](#rack)|List of Racks defined in the Cassandra DC|Yes|-| 20 | |config|map|Configuration used by the config builder to generated cassandra.yaml and other configuration files|No|| 21 | |nodesPerRacks|int32|Number of nodes to deploy for a Cassandra deployment in each Racks.|Optional, if not filled, used value define in [CassandraClusterSpec](/casskop/docs/6_references/1_cassandra_cluster#cassandraclusterspec)|1| 22 | |dataCapacity|string|Define the Capacity for Persistent Volume Claims in the local storage. [Check documentation for more informations](/casskop/docs/3_configuration_deployment/3_storage#configuration)|Optional, if not filled, used value define in [CassandraClusterSpec](/casskop/docs/6_references/1_cassandra_cluster#cassandraclusterspec)|| 23 | |dataStorageClass|string|Define StorageClass for Persistent Volume Claims in the local storage. [Check documentation for more informations](/casskop/docs/3_configuration_deployment/3_storage#configuration)|Optional, if not filled, used value define in [CassandraClusterSpec](/casskop/docs/6_references/1_cassandra_cluster#cassandraclusterspec)|| 24 | 25 | ## Rack 26 | 27 | |Field|Type|Description|Required|Default| 28 | |-----|----|-----------|--------|--------| 29 | |name|string|Name of the Rack|Yes|rack1| 30 | |labels|map\[string\]string|Labels used to target Kubernetes nodes|No|-| 31 | |config|map|Configuration used by the config builder to generated cassandra.yaml and other configuration files|No|| 32 | |rollingRestart|bool|Flag to tell the operator to trigger a rolling restart of the Rack|Yes|false| 33 | |rollingPartition|int32|The Partition to control the Statefulset Upgrade|Yes|0| -------------------------------------------------------------------------------- /website/docs/7_troubleshooting/2_gke_issues.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 2_gke_issues 3 | title: GKE Issues 4 | sidebar_label: GKE Issues 5 | --- 6 | ### RBAC on Google Container Engine (GKE) 7 | 8 | When you try to create `ClusterRole` (`cassandra-operator`, etc.) on GKE Kubernetes cluster, you will probably run into permission errors: 9 | 10 | ``` 11 | <....> 12 | failed to initialize cluster resources: roles.rbac.authorization.k8s.io 13 | "cassandra-operator" is forbidden: attempt to grant extra privileges: 14 | <....> 15 | ```` 16 | 17 | This is due to the way Container Engine checks permissions. From [Google Container Engine docs](https://cloud.google.com/container-engine/docs/role-based-access-control): 18 | 19 | :::note 20 | Because of the way Container Engine checks permissions when you create a Role or ClusterRole, you must first create a RoleBinding that grants you all of the permissions included in the role you want to create. 21 | An example workaround is to create a RoleBinding that gives your Google identity a cluster-admin role before attempting to create additional Role or ClusterRole permissions. 22 | This is a known issue in the Beta release of Role-Based Access Control in Kubernetes and Container Engine version 1.6. 23 | ::: 24 | 25 | To overcome this, you must grant your current Google identity `cluster-admin` Role: 26 | 27 | ```console 28 | # get current google identity 29 | $ gcloud info | grep Account 30 | Account: [myname@example.org] 31 | 32 | # grant cluster-admin to your current identity 33 | $ kubectl create clusterrolebinding myname-cluster-admin-binding --clusterrole=cluster-admin --user=myname@example.org 34 | Clusterrolebinding "myname-cluster-admin-binding" created 35 | ``` 36 | 37 | ### Pod and volumes can be scheduled in different zones using default provisioned 38 | 39 | The default provisioner in GKE does not have the `volumeBindingMode: "WaitForFirstConsumer"` option that can result in 40 | a bad 41 | scheduling behaviour. 42 | We use one of the following files to create a storage class: 43 | - config/samples/gke-storage-standard-wait.yaml 44 | - config/samples/gke-storage-ssd-wait.yaml (if you have ssd disks) -------------------------------------------------------------------------------- /website/docs/8_contributing/2_release_guide.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 2_release_guide 3 | title: Release guide 4 | sidebar_label: Release guide 5 | --- 6 | 7 | There are several things to do when you want to make a release of the project: 8 | Todo: things should be automatize ;) 9 | 10 | For ease, we have same version for casskop and multi-casskop 11 | - [ ] Update Changelog.md with informations for the new release 12 | - [ ] update version/version.go with the new release version 13 | - [ ] update multi-casskop/version/version.go with the new release version 14 | - [ ] update helm/cassandra-operator/Chart.yaml and values.yaml 15 | - [ ] update multi-casskop/helm/multi-casskop/Chart.yaml and values.yaml 16 | - [ ] generate casskop helm with `make helm-package` 17 | - [ ] add to git docs/helm, commit & push 18 | - [ ] once the PR is merged to master, create the release with content of changelog for this version 19 | - https://github.com/Orange-OpenSource/casskop/releases 20 | 21 | ## With Helm 22 | 23 | The CassKop operator is released in the helm/charts/incubator see : https://github.com/helm/charts/pull/14414 24 | 25 | We also have a helm repository hosted on GitHub pages. 26 | 27 | ### Release helm charts on GitHub 28 | 29 | In order to release the Helm charts on GitHub, we need to generate the package locally 30 | ``` 31 | make helm-package 32 | ``` 33 | 34 | then add to git the package and make a PR on the repo. 35 | 36 | 37 | ## With OLM (Operator Lifecycle Manager) 38 | 39 | OLM is used to manage lifecycle of the Operator, and is also used to puclish on https://operatorhub.io 40 | 41 | ### Create new OLM release 42 | 43 | You can create new version of CassKop OLM bundle using: 44 | 45 | Exemple for generating version 0.0.4 46 | ``` 47 | operator-sdk olm-catalog gen-csv --csv-version 0.4.0 --update-crds 48 | ``` 49 | 50 | > You may need to manually update some fileds (such as description..), you can refere to previous versions for that 51 | 52 | ### Instruction to tests locally with OLM 53 | 54 | Before submitting the operator to operatorhub.io you need to install and test OLM on a local Kubernetes. 55 | 56 | These tests and all pre-requisite can also be executed automatically in a single step using a 57 | [Makefile](https://github.com/operator-framework/community-operators/blob/master/docs/using-scripts.md). 58 | 59 | Go to github/operator-framework/community-operators to interract with the OLM makefile 60 | 61 | Install OLM 62 | ``` 63 | make operator.olm.install 64 | ``` 65 | 66 | Launch lint 67 | ``` 68 | make operator.verify OP_PATH=community-operators/casskop VERBOSE=true 69 | ``` 70 | 71 | Launch tests 72 | ``` 73 | make operator.test OP_PATH=community-operators/casskop VERBOSE=true 74 | ``` -------------------------------------------------------------------------------- /website/docs/8_contributing/3_reporting_bugs.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 3_reporting_bugs 3 | title: Reporting bugs 4 | sidebar_label: Reporting bugs 5 | --- 6 | 7 | If any part of the CassKop project has bugs or documentation mistakes, please let us know by 8 | [opening an issue](https://github.com/Orange-OpenSource/casskop/issues/new). We treat 9 | bugs and mistakes very seriously and believe no issue is too small. Before creating a bug report, please check that an 10 | issue reporting the same problem does not already exist. 11 | 12 | 13 | To make the bug report accurate and easy to understand, please try to create bug reports that are: 14 | 15 | - Specific. Include as much details as possible: which version, what environment, what configuration, etc. 16 | 17 | - Reproducible. Include the steps to reproduce the problem. We understand some issues might be hard to reproduce, please 18 | include the steps that might lead to the problem. 19 | - Isolated. Please try to isolate and reproduce the bug with minimum dependencies. It would significantly slow down the 20 | speed to fix a bug if too many dependencies are involved in a bug report. Debugging external systems that rely on 21 | CassKop is out of scope, but we are happy to provide guidance in the right direction or help with using 22 | CassKop itself. 23 | - Unique. Do not duplicate existing bug report. 24 | - Scoped. One bug per report. Do not follow up with another bug inside one report. 25 | 26 | We might ask for further information to locate a bug. A duplicated bug report will be closed. -------------------------------------------------------------------------------- /website/docs/8_contributing/4_credits.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 4_credits 3 | title: Credits 4 | sidebar_label: Credits 5 | --- 6 | 7 | This implementation is based on other Open-Source project, and lot of the community ideas. Particular thanks to : 8 | 9 | - Implementation is based on [Operator SDK](https://github.com/operator-framework/operator-sdk) -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "serve": "docusaurus serve" 12 | }, 13 | "dependencies": { 14 | "@docusaurus/core": "2.0.0-alpha.70dece09e", 15 | "@docusaurus/preset-classic": "2.0.0-alpha.70dece09e", 16 | "@mdx-js/react": "^1.6.22", 17 | "clsx": "^1.1.1", 18 | "core-js": "^3.8.1", 19 | "dns-packet": "^1.3.1", 20 | "node-fetch": "^2.6.7", 21 | "node-forge": "^1.0.0", 22 | "react": "^17.0.1", 23 | "react-dom": "^17.0.1", 24 | "serialize-javascript": "^5.0.1" 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /website/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #f09549; 10 | --ifm-color-primary-dark: #d9853f; 11 | --ifm-color-primary-darker: #c47739; 12 | --ifm-color-primary-darkest: #b36d34; 13 | --ifm-color-primary-light: #ff9c4b; 14 | --ifm-color-primary-lighter: #fca966; 15 | --ifm-color-primary-lightest: #fcb57c; 16 | --ifm-color-feedback-background: #fff; 17 | --ifm-code-background: #d9b295; 18 | } 19 | 20 | html[data-theme='dark'] { 21 | --ifm-color-feedback-background: #f0f8ff; 22 | } 23 | 24 | @media screen and (max-width: 996px) { 25 | :root { 26 | --ifm-font-size-base: 15px; 27 | } 28 | } 29 | 30 | @media screen and (min-width: 997px) { 31 | :root { 32 | --ifm-font-size-base: 17px; 33 | } 34 | } 35 | 36 | .docusaurus-highlight-code-line { 37 | background-color: rgb(0, 0, 0, 0.1); 38 | display: block; 39 | margin: 0 calc(-1 * var(--ifm-pre-padding)); 40 | padding: 0 var(--ifm-pre-padding); 41 | } 42 | 43 | html[data-theme='dark'] .docusaurus-highlight-code-line { 44 | background-color: rgb(0, 0, 0, 0.3); 45 | } -------------------------------------------------------------------------------- /website/src/pages/styles.module.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable docusaurus/copyright-header */ 2 | 3 | /** 4 | * CSS files with the .module.css suffix will be treated as CSS modules 5 | * and scoped locally. 6 | */ 7 | 8 | .heroBanner { 9 | padding: 4rem 0; 10 | text-align: center; 11 | position: relative; 12 | overflow: hidden; 13 | } 14 | 15 | @media screen and (max-width: 966px) { 16 | .heroBanner { 17 | padding: 2rem; 18 | } 19 | } 20 | 21 | .buttons { 22 | display: flex; 23 | align-items: center; 24 | justify-content: center; 25 | } 26 | 27 | .features { 28 | display: flex; 29 | align-items: center; 30 | padding: 2rem 0; 31 | width: 100%; 32 | } 33 | 34 | .featureImage { 35 | height: 200px; 36 | width: 200px; 37 | } 38 | -------------------------------------------------------------------------------- /website/static/.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | machine: true 5 | branches: 6 | ignore: gh-pages 7 | steps: 8 | - run: echo "Skipping tests on gh-pages branch" 9 | -------------------------------------------------------------------------------- /website/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/.nojekyll -------------------------------------------------------------------------------- /website/static/img/1_concepts/multi-casskop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/1_concepts/multi-casskop.png -------------------------------------------------------------------------------- /website/static/img/3_configuration_deployment/topology-custom-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/3_configuration_deployment/topology-custom-example.png -------------------------------------------------------------------------------- /website/static/img/3_configuration_deployment/topology-gke-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/3_configuration_deployment/topology-gke-example.png -------------------------------------------------------------------------------- /website/static/img/8_contributing/ide_debug_action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/8_contributing/ide_debug_action.png -------------------------------------------------------------------------------- /website/static/img/8_contributing/ide_debug_configutation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/8_contributing/ide_debug_configutation.png -------------------------------------------------------------------------------- /website/static/img/blog/2020-01-15-multicasskop_gke/multicasskop_architecture.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/blog/2020-01-15-multicasskop_gke/multicasskop_architecture.jpeg -------------------------------------------------------------------------------- /website/static/img/cassandra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/cassandra.png -------------------------------------------------------------------------------- /website/static/img/casskop_alone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/casskop_alone.png -------------------------------------------------------------------------------- /website/static/img/dc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/dc.png -------------------------------------------------------------------------------- /website/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/favicon.ico -------------------------------------------------------------------------------- /website/static/img/kubernetes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/kubernetes.png -------------------------------------------------------------------------------- /website/static/img/namespace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/namespace.png -------------------------------------------------------------------------------- /website/static/img/open_source.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /website/static/img/operator-sdk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/operator-sdk.png -------------------------------------------------------------------------------- /website/static/img/orange.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/img/orange.jpg -------------------------------------------------------------------------------- /website/static/slides/Makefile: -------------------------------------------------------------------------------- 1 | 2 | #You must install slides-server first 3 | serve: 4 | python -m SimpleHTTPServer 3000 5 | -------------------------------------------------------------------------------- /website/static/slides/assets/dfy-50x53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/slides/assets/dfy-50x53.png -------------------------------------------------------------------------------- /website/static/slides/assets/dfy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/slides/assets/dfy.png -------------------------------------------------------------------------------- /website/static/slides/assets/edit-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/slides/assets/edit-50.png -------------------------------------------------------------------------------- /website/static/slides/assets/k8s.puml: -------------------------------------------------------------------------------- 1 | 2 | @startuml 3 | 4 | scale 800 width 5 | 6 | :Developpeur: 7 | [KUBECTL] 8 | [HELM] 9 | 10 | Developpeur --> [KUBECTL] 11 | Developpeur --> [HELM] 12 | () HTTPS 13 | cloud "Kubenetes" { 14 | 15 | node "master" { 16 | HTTPS - [API] 17 | } 18 | 19 | node "workers" { 20 | 21 | } 22 | [KUBECTL] --> HTTPS 23 | [HELM] --> HTTPS 24 | workers - master 25 | } 26 | 27 | 28 | cloud "Gitlab" { 29 | 30 | package "gitlab-ci" { 31 | 32 | node "runner" { 33 | [helm] - HTTPS 34 | [kubectl] - HTTPS 35 | } 36 | 37 | } 38 | 39 | @enduml 40 | -------------------------------------------------------------------------------- /website/static/slides/assets/kubernetes-operators/CassandraOperator2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/slides/assets/kubernetes-operators/CassandraOperator2.png -------------------------------------------------------------------------------- /website/static/slides/assets/kubernetes-operators/cassandra-sts-uml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/slides/assets/kubernetes-operators/cassandra-sts-uml.png -------------------------------------------------------------------------------- /website/static/slides/assets/kubernetes-operators/minions.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/slides/assets/kubernetes-operators/minions.jpeg -------------------------------------------------------------------------------- /website/static/slides/assets/kubernetes-operators/topology-custom-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/slides/assets/kubernetes-operators/topology-custom-example.png -------------------------------------------------------------------------------- /website/static/slides/assets/kubernetes-operators/topology-gke-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/slides/assets/kubernetes-operators/topology-gke-example.png -------------------------------------------------------------------------------- /website/static/slides/assets/orange-50x50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Orange-OpenSource/casskop/8fb1b71ec9d98f41261b76f0313a74d3c03b65db/website/static/slides/assets/orange-50x50.png -------------------------------------------------------------------------------- /website/static/slides/home.md: -------------------------------------------------------------------------------- 1 | # CassKop Slides Presentations 2 | 3 | - [Slides-CassKop-demo.md](?slides=Slides-CassKop-demo.md) 4 | -------------------------------------------------------------------------------- /website/static/slides/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Slides 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /website/static/slides/js/plantUml.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by cfwr6466 on 06/09/2016. 3 | */ 4 | 5 | var PLANTUML_SERVER="http://plantuml.com/plantuml/"; 6 | 7 | 8 | function encode64(data) { 9 | r = ""; 10 | for (i=0; i> 2; 24 | c2 = ((b1 & 0x3) << 4) | (b2 >> 4); 25 | c3 = ((b2 & 0xF) << 2) | (b3 >> 6); 26 | c4 = b3 & 0x3F; 27 | r = ""; 28 | r += encode6bit(c1 & 0x3F); 29 | r += encode6bit(c2 & 0x3F); 30 | r += encode6bit(c3 & 0x3F); 31 | r += encode6bit(c4 & 0x3F); 32 | return r; 33 | } 34 | function encode6bit(b) { 35 | if (b < 10) { 36 | return String.fromCharCode(48 + b); 37 | } 38 | b -= 10; 39 | if (b < 26) { 40 | return String.fromCharCode(65 + b); 41 | } 42 | b -= 26; 43 | if (b < 26) { 44 | return String.fromCharCode(97 + b); 45 | } 46 | b -= 26; 47 | if (b == 0) { 48 | return '-'; 49 | } 50 | if (b == 1) { 51 | return '_'; 52 | } 53 | return '?'; 54 | } 55 | 56 | 57 | function parsePlantUml(txt) { 58 | console.log("looking for plantuml diagram"); 59 | diagrams=[]; 60 | var i=0; 61 | newLastContent=txt.replace(/\@startuml([\s\S]*?)(?!\@startuml)\@enduml/mg, function(plantuml) { 62 | console.log(plantuml); 63 | plantuml = unescape(encodeURIComponent(plantuml)); 64 | return "![plantuml]("+PLANTUML_SERVER+"svg/"+encode64(RawDeflate.deflate(plantuml))+")"; 65 | }); 66 | return newLastContent; 67 | } -------------------------------------------------------------------------------- /website/static/slides/js/remark-macros.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by cfwr6466 on 15/09/2016. 3 | */ 4 | 5 | remark.macros.scale = function (percentage) { 6 | var url = this; 7 | return ''; 8 | // Usage: 9 | // ![:scale 50%](image.jpg) 10 | // Outputs: 11 | // 12 | }; --------------------------------------------------------------------------------