├── .dmtlint.yaml ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── PULL_REQUEST_TEMPLATE.md ├── check_previous_channel_release.sh └── workflows │ ├── build_dev.yml │ ├── build_prod.yml │ ├── checks.yaml │ ├── deploy_dev.yml │ ├── deploy_prod.yml │ ├── dev_registry-cleanup.yml │ ├── go_checks.yaml │ └── trivy_image_check.yaml ├── .gitignore ├── .golangci.yaml ├── .helmignore ├── .werf ├── base-images.yaml ├── bundle.yaml ├── choose-edition.yaml ├── consts.yaml ├── images-digests.yaml ├── images.yaml ├── python-deps.yaml ├── release.yaml └── utils.yaml ├── Chart.yaml ├── LICENSE ├── Makefile ├── api ├── LICENSE ├── README.md ├── go.mod ├── go.sum ├── linstor │ ├── layer_drbd_resource_definitions.go │ ├── layer_drbd_volume_definitions.go │ ├── layer_storage_volumes.go │ ├── props_containers.go │ ├── register.go │ ├── resource.go │ ├── resource_definitions.go │ ├── resource_groups.go │ ├── volume_definitions.go │ └── zz_generated.deepcopy.go └── v1alpha1 │ ├── register.go │ ├── replicated_storage_class.go │ ├── replicated_storage_pool.go │ └── zz_generated.deepcopy.go ├── charts └── deckhouse_lib_helm-1.57.0.tgz ├── crds ├── doc-ru-replicatedstoragebackup.yaml ├── doc-ru-replicatedstorageclass.yaml ├── doc-ru-replicatedstoragepool.yaml ├── replicatedstoragebackup.yaml ├── replicatedstorageclass.yaml └── replicatedstoragepool.yaml ├── docs ├── CONFIGURATION.md ├── CONFIGURATION_RU.md ├── CR.md ├── CR_RU.md ├── FAQ.md ├── FAQ_RU.md ├── LAYOUTS.md ├── LAYOUTS_RU.md ├── README.md ├── README_RU.md ├── USAGE.md ├── USAGE_RU.md └── images │ ├── linstor-debug-cheatsheet.ru.svg │ ├── linstor-debug-cheatsheet.svg │ ├── trans-zonal.png │ ├── trans-zonal.ru.png │ ├── zonal.png │ └── zonal.ru.png ├── hooks ├── common.py ├── discovery_data_nodes_checksum.py ├── ensure_crds.py ├── go │ ├── 050-label-expiring-certs │ │ └── label_expiring_certs.go │ ├── 060-manual-cert-renewal │ │ ├── manual_cert_renewal.go │ │ ├── manual_cert_renewal_test.go │ │ ├── state_machine.go │ │ ├── state_machine_cache.go │ │ └── state_machine_certs.go │ ├── 070-generate-certs │ │ ├── linstor_certs.go │ │ ├── scheduler_extender_cert.go │ │ ├── spaas_cert.go │ │ └── webhook_certs.go │ ├── certs │ │ ├── linstor_certs.go │ │ ├── scheduler_extender_cert.go │ │ ├── spaas_cert.go │ │ └── webhook_certs.go │ ├── consts │ │ └── consts.go │ ├── go.mod │ ├── go.sum │ ├── main.go │ ├── tls-certificate │ │ ├── cert_helpers.go │ │ ├── internal_tls.go │ │ └── manual_tls.go │ └── utils │ │ ├── certs.go │ │ ├── iter.go │ │ ├── maps.go │ │ └── slices.go ├── initial_backup.py ├── lib │ ├── __init__.py │ ├── hooks │ │ ├── __init__.py │ │ ├── copy_custom_certificate.py │ │ ├── hook.py │ │ └── manage_tenant_secrets.py │ ├── module │ │ ├── __init__.py │ │ ├── module.py │ │ └── values.py │ ├── password_generator │ │ ├── __init__.py │ │ └── password_generator.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_copy_custom_certificate.py │ │ ├── test_manage_tenant_secrets.py │ │ └── testing.py │ └── utils.py ├── migrate_csi_endpoint.sh ├── migrate_csi_endpoint_check.sh ├── migrate_sdsdrbd_crds.py └── on_start_checks.py ├── images ├── drbd-reactor │ ├── patches │ │ ├── 001-fix-drbd-reactor-spec.patch │ │ └── Readme.md │ └── werf.inc.yaml ├── drbd │ ├── scripts │ │ ├── install │ │ └── uninstall │ └── werf.inc.yaml ├── go-hooks │ └── werf.inc.yaml ├── linstor-affinity-controller │ └── werf.inc.yaml ├── linstor-csi │ ├── patches │ │ ├── 001-requisites.patch │ │ ├── 002-rename-linbit-labels.patch │ │ ├── 003-new-csi-path.patch │ │ ├── 004-csi-add-new-topology-logic.patch │ │ └── README.md │ └── werf.inc.yaml ├── linstor-drbd-wait │ ├── LICENSE │ ├── cmd │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── pkg │ │ └── logger │ │ │ └── logger.go │ └── werf.inc.yaml ├── linstor-scheduler-admission │ └── werf.inc.yaml ├── linstor-scheduler-extender │ ├── patches │ │ ├── 001-linstor-scheduler-extender.patch │ │ ├── README.md │ │ └── stork │ │ │ ├── new-files │ │ │ └── pkg │ │ │ │ └── cache │ │ │ │ └── cache.go │ │ │ └── stork.patch │ └── werf.inc.yaml ├── linstor-server │ ├── cleaner.py │ ├── client-wrapper.sh │ ├── liveness-satellite.sh │ ├── liveness.sh │ ├── patches │ │ ├── 001-fix-linstor-spec.patch │ │ ├── 002-fix-symlinks.patch │ │ └── README.md │ └── werf.inc.yaml ├── linstor-wait-until │ ├── patches │ │ ├── 001-log.patch │ │ └── README.md │ └── werf.inc.yaml ├── metadata-backup │ ├── backup.py │ └── werf.inc.yaml ├── sds-replicated-volume-controller │ ├── LICENSE │ ├── cmd │ │ └── main.go │ ├── config │ │ └── config.go │ ├── go.mod │ ├── go.sum │ ├── pkg │ │ ├── controller │ │ │ ├── controller_suite_test.go │ │ │ ├── linstor_leader.go │ │ │ ├── linstor_leader_test.go │ │ │ ├── linstor_node.go │ │ │ ├── linstor_node_t_test.go │ │ │ ├── linstor_node_test.go │ │ │ ├── linstor_port_range_cm_watcher.go │ │ │ ├── linstor_port_range_cm_watcher_test.go │ │ │ ├── linstor_resources_watcher.go │ │ │ ├── linstor_resources_watcher_test.go │ │ │ ├── replicated_storage_class.go │ │ │ ├── replicated_storage_class_test.go │ │ │ ├── replicated_storage_class_watcher.go │ │ │ ├── replicated_storage_class_watcher_test.go │ │ │ ├── replicated_storage_pool.go │ │ │ ├── replicated_storage_pool_test.go │ │ │ ├── storage_class_annotations.go │ │ │ ├── storage_class_annotations_func.go │ │ │ └── storage_class_annotations_test.go │ │ ├── kubeutils │ │ │ └── kubernetes.go │ │ ├── logger │ │ │ └── logger.go │ │ └── sdk │ │ │ └── framework │ │ │ └── reconcile_helper │ │ │ └── reconciler_core.go │ └── werf.inc.yaml ├── semver │ ├── scripts │ │ ├── install │ │ └── uninstall │ └── werf.inc.yaml ├── service-scripts │ ├── scripts │ │ ├── install │ │ └── uninstall │ ├── tools │ │ ├── evict.sh │ │ └── replicas_manager.sh │ └── werf.inc.yaml ├── spaas │ └── werf.inc.yaml └── webhooks │ ├── LICENSE │ ├── api │ ├── module_config.go │ ├── register.go │ ├── zz_generated.deepcopy.go │ └── zz_generated.defaults.go │ ├── cmd │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── handlers │ ├── func.go │ ├── rscValidator.go │ ├── rspValidator.go │ └── scValidator.go │ └── werf.inc.yaml ├── lib └── python │ └── requirements.txt ├── module.yaml ├── monitoring ├── grafana-dashboards │ └── storage │ │ └── linstor_drbd.json └── prometheus-rules │ ├── drbd-devices.yaml │ ├── expiring-certs.yaml │ ├── linstor-affinity-controller.yaml │ ├── linstor-backup.yaml │ ├── linstor-controller.yaml │ ├── linstor-csi-controller.yaml │ ├── linstor-csi-node.yaml │ ├── linstor-node.yaml │ ├── linstor-scheduler-admission.tpl │ ├── linstor-scheduler.yaml │ ├── linstor-storage-pools.yaml │ ├── memory-leak.yaml │ ├── replicated-pv-with-incorrect-settings.yaml │ ├── spaas.yaml │ └── storage-class.yaml ├── openapi ├── config-values.yaml ├── doc-ru-config-values.yaml ├── openapi-case-tests.yaml ├── values_ce.yaml └── values_ee.yaml ├── oss.yaml ├── templates ├── certs.yaml ├── csi │ ├── controller.yaml │ ├── csidriver.yaml │ ├── rbac-for-us.yaml │ └── volume-snapshot-class.yaml ├── linstor-affinity-controller │ ├── deployment.yaml │ └── rbac-for-us.yaml ├── linstor-controller │ ├── configmap-linstor-controller-config.yaml │ ├── configmap-linstor-port-range.yaml │ ├── deployment.yaml │ ├── rbac-for-us.yaml │ ├── service.yaml │ └── servicemonitor.yaml ├── linstor-node │ ├── configmap-linstor-node-config.yaml │ ├── configmap-linstor-node-monitoring.yaml │ ├── daemonset.yaml │ ├── podmonitor.yaml │ └── rbac-for-us.yaml ├── linstor-scheduler-admission │ ├── deployment.yaml │ ├── rbac-for-us.yaml │ ├── secret.yaml │ ├── service.yaml │ └── webhook.yaml ├── linstor-scheduler-extender │ ├── configmap.yaml │ ├── deployment.yaml │ ├── kube-scheduler-webhook-configuration.yaml │ ├── rbac-for-us.yaml │ ├── secret.yaml │ └── service.yaml ├── metadata-backup │ ├── job.yaml │ ├── job_weekly.yaml │ └── rbac-for-us.yaml ├── monitoring.yaml ├── namespace.yaml ├── nodegroupconfiguration-blacklist-drbd.yaml ├── nodegroupconfiguration-disable-lvmetad.yaml ├── nodegroupconfiguration-drbd-install-altlinux-like.yaml ├── nodegroupconfiguration-drbd-install-centos-like.yaml ├── nodegroupconfiguration-drbd-install-debian-like.yaml ├── nodegroupconfiguration-restart-kubelet.yaml ├── passphrase.yaml ├── rbac-to-us.yaml ├── registry-secret.yaml ├── sds-replicated-volume-controller │ ├── configmap.yaml │ ├── deployment.yaml │ ├── rbac-for-us.yaml │ └── secret.yaml ├── spaas │ ├── deployment.yaml │ ├── secret.yaml │ └── service.yaml └── webhooks │ ├── deployment.yaml │ ├── rbac-for-us.yaml │ ├── secret.yaml │ ├── service.yaml │ └── webhook.yaml ├── tools └── dev_images │ └── additional_tools │ └── alt │ └── binary_replace.sh ├── werf-giterminism.yaml ├── werf.yaml └── werf_cleanup.yaml /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🎯 Bug report 2 | description: Report a bug to help us improve Deckhouse 3 | labels: 4 | - 'type/bug' 5 | - 'status/needs-triage' 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thank you for submitting a bug report! 11 | 12 | Please fill out the template below to make it easier to debug your problem. 13 | - type: checkboxes 14 | attributes: 15 | label: Preflight Checklist 16 | description: Please ensure you've completed all of the following. 17 | options: 18 | - label: I agree to follow the [Code of Conduct](https://github.com/deckhouse/deckhouse/blob/main/CODE_OF_CONDUCT.md) that this project adheres to. 19 | required: true 20 | - label: I have searched the [issue tracker](https://github.com/deckhouse/deckhouse/issues) for an issue that matches the one I want to file, without success. 21 | required: true 22 | - type: input 23 | attributes: 24 | label: Version 25 | description: | 26 | What version of Deckhouse are you running? 27 | placeholder: v1.0.0 28 | validations: 29 | required: true 30 | - type: textarea 31 | attributes: 32 | label: Expected Behavior 33 | description: A clear and concise description of what you expected to happen. 34 | validations: 35 | required: true 36 | - type: textarea 37 | attributes: 38 | label: Actual Behavior 39 | description: A clear description of what actually happens. 40 | validations: 41 | required: true 42 | - type: textarea 43 | attributes: 44 | label: Steps To Reproduce 45 | description: Steps to reproduce the behavior if it is not self-explanatory. 46 | placeholder: | 47 | 1. In this environment... 48 | 2. With this config... 49 | 3. Run '...' 50 | 4. See error... 51 | - type: textarea 52 | attributes: 53 | label: Additional Information 54 | description: Links? References? Anything that will give us more context about the issue that you are encountering! 55 | - type: textarea 56 | attributes: 57 | label: Logs 58 | description: Deckhouse application logs (if relevant). 59 | render: shell 60 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 📚 Documentation 4 | url: https://deckhouse.io/documentation/ 5 | about: Check the documentation for help 6 | 7 | - name: 💬 Telegram channel [EN] 8 | url: https://t.me/deckhouse 9 | about: Please ask and answer questions here 10 | 11 | - name: 🇷🇺 Telegram channel [RU] 12 | url: https://t.me/deckhouse_ru 13 | about: Please ask and answer questions here 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: 💡 Feature request 2 | description: Suggest an idea for Deckhouse 3 | labels: 4 | - 'type/enhancement' 5 | - 'status/needs-triage' 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thank you for submitting a feature request! 11 | 12 | Please describe what you would like to change/add and why in detail by filling out the template below. 13 | - type: checkboxes 14 | attributes: 15 | label: Preflight Checklist 16 | description: Please ensure you've completed all of the following. 17 | options: 18 | - label: I agree to follow the [Code of Conduct](https://github.com/deckhouse/deckhouse/blob/main/CODE_OF_CONDUCT.md) that this project adheres to. 19 | required: true 20 | - label: I have searched the [issue tracker](https://github.com/deckhouse/deckhouse/issues) for an issue that matches the one I want to file, without success. 21 | required: true 22 | - type: textarea 23 | attributes: 24 | label: Use case. Why is this important? 25 | description: A clear and concise description of the problem you are seeking to solve with this feature request. 26 | validations: 27 | required: true 28 | - type: textarea 29 | attributes: 30 | label: Proposed Solution 31 | description: A clear and concise description of what would you like to happen. 32 | validations: 33 | required: true 34 | - type: textarea 35 | attributes: 36 | label: Additional Information 37 | description: Add any other context about the problem here. 38 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 8 | 9 | ## Why do we need it, and what problem does it solve? 10 | 18 | 19 | ## What is the expected result? 20 | 25 | 26 | ## Checklist 27 | - [ ] The code is covered by unit tests. 28 | - [ ] e2e tests passed. 29 | - [ ] Documentation updated according to the changes. 30 | - [ ] Changes were tested in the Kubernetes cluster manually. 31 | -------------------------------------------------------------------------------- /.github/check_previous_channel_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | crane="/usr/local/bin/crane" 4 | repositoryName=$1 5 | edition=$2 6 | channel=$3 7 | version=$4 8 | user=$5 9 | password=$6 10 | 11 | echo "Module $repositoryName, edition $edition, channel $channel, version $version" 12 | 13 | if [[ "$channel" == "alpha" ]]; then 14 | echo "Deploying $version to alpha channel" 15 | exit 0 16 | elif [[ "$channel" == "beta" ]]; then 17 | previousChannel="alpha" 18 | elif [[ "$channel" == "early-access" ]]; then 19 | previousChannel="beta" 20 | elif [[ "$channel" == "stable" ]]; then 21 | previousChannel="early-access" 22 | elif [[ "$channel" == "rock-solid" ]]; then 23 | previousChannel="stable" 24 | else 25 | echo "Unknown channel" 26 | exit 1 27 | fi 28 | 29 | echo "Checking previous channel $previousChannel" 30 | $crane auth login -u $user -p $password registry.deckhouse.io 31 | previousChannelVersion=$($crane export registry.deckhouse.io/deckhouse/$edition/modules/$repositoryName/release:$previousChannel | grep -aoE '\{"version":".*"\}' | jq -r .version) 32 | if [[ "$version" == "$previousChannelVersion" ]]; then 33 | echo "Previous channel $previousChannel version $previousChannelVersion is equal desired version $version, processing" 34 | exit 0 35 | else 36 | echo "Previous channel $previousChannel version $previousChannelVersion is not equal desired version $version, rejecting" 37 | exit 1 38 | fi 39 | -------------------------------------------------------------------------------- /.github/workflows/checks.yaml: -------------------------------------------------------------------------------- 1 | name: PR Checks 2 | 3 | on: 4 | pull_request: 5 | types: [opened, labeled, unlabeled, synchronize] 6 | 7 | jobs: 8 | release-label: 9 | name: Release note label 10 | runs-on: [self-hosted, regular] 11 | 12 | steps: 13 | - name: Check minimum labels 14 | uses: mheap/github-action-required-labels@v5 15 | with: 16 | mode: minimum 17 | count: 1 18 | labels: "release-note/dependencies, dependencies, release-note/deprecation, release-note/breaking-change, release-note/bug, bug, release-note/enhancement, enhancement, release-note/documentation, documentation, release-note/new-feature, release-note/ignore" 19 | -------------------------------------------------------------------------------- /.github/workflows/deploy_dev.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Dev 2 | 3 | env: 4 | MODULES_REGISTRY: ${{ vars.DEV_REGISTRY }} 5 | CI_COMMIT_REF_NAME: ${{ github.event.inputs.tag }} 6 | MODULES_MODULE_NAME: ${{ vars.MODULE_NAME }} 7 | MODULES_MODULE_SOURCE: ${{ vars.DEV_MODULE_SOURCE }} 8 | MODULES_REGISTRY_LOGIN: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} 9 | MODULES_REGISTRY_PASSWORD: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} 10 | RELEASE_CHANNEL: ${{ github.event.inputs.channel }} 11 | MODULES_MODULE_TAG: ${{ github.event.inputs.tag }} 12 | GOLANG_VERSION: ${{ vars.GOLANG_VERSION }} 13 | GOPROXY: ${{ secrets.GOPROXY }} 14 | SOURCE_REPO: ${{ secrets.SOURCE_REPO }} 15 | 16 | on: 17 | workflow_dispatch: 18 | inputs: 19 | channel: 20 | description: "Select release channel" 21 | type: choice 22 | default: alpha 23 | options: 24 | - "alpha" 25 | - "beta" 26 | - "early-access" 27 | - "stable" 28 | - "rock-solid" 29 | 30 | tag: 31 | description: "The module's tag, which must include the -dev1 postfix. For example: v1.21.1-dev1" 32 | type: string 33 | required: true 34 | 35 | enableBuild: 36 | type: boolean 37 | default: true 38 | description: "Set to true if build is required" 39 | 40 | jobs: 41 | deploy-dev: 42 | runs-on: [self-hosted, large] 43 | name: Deploy dev 44 | steps: 45 | - name: PRINT VARS 46 | run: | 47 | echo MODULES_REGISTRY=$MODULES_REGISTRY 48 | echo MODULES_MODULE_SOURCE=$MODULES_MODULE_SOURCE 49 | echo CI_COMMIT_REF_NAME=$CI_COMMIT_REF_NAME 50 | echo MODULES_MODULE_NAME=$MODULES_MODULE_NAME 51 | echo RELEASE_CHANNEL=$RELEASE_CHANNEL 52 | echo MODULES_MODULE_TAG=$MODULES_MODULE_TAG 53 | shell: bash 54 | - name: Validation for tag 55 | run: | 56 | echo ${{ github.event.inputs.tag }} | grep -P '^v\d+\.\d+\.\d+-dev1$' 57 | shell: bash 58 | 59 | - uses: actions/checkout@v4 60 | - uses: deckhouse/modules-actions/setup@v2 61 | with: 62 | registry: ${{ vars.DEV_REGISTRY }} 63 | registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} 64 | registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} 65 | - if: ${{ github.event.inputs.enableBuild == 'true' }} 66 | uses: deckhouse/modules-actions/build@v2 67 | with: 68 | module_source: "${{ vars.DEV_MODULE_SOURCE }}" 69 | module_name: ${{ vars.MODULE_NAME }} 70 | module_tag: ${{ github.event.inputs.tag }} 71 | - uses: deckhouse/modules-actions/deploy@v2 -------------------------------------------------------------------------------- /.github/workflows/dev_registry-cleanup.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Flant JSC 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 | name: Cleanup dev registries 16 | 17 | env: 18 | MODULES_REGISTRY: ${{ vars.DEV_REGISTRY }} 19 | CI_COMMIT_REF_NAME: ${{ github.ref_name }} 20 | MODULES_MODULE_NAME: ${{ vars.MODULE_NAME }} 21 | MODULES_MODULE_SOURCE: ${{ vars.DEV_MODULE_SOURCE }} 22 | MODULES_REGISTRY_LOGIN: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} 23 | MODULES_REGISTRY_PASSWORD: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} 24 | WERF_DRY_RUN: "false" 25 | 26 | on: 27 | workflow_dispatch: 28 | schedule: 29 | - cron: "12 0 * * 6" 30 | 31 | defaults: 32 | run: 33 | shell: bash 34 | 35 | jobs: 36 | lint: 37 | runs-on: [self-hosted, large] 38 | name: Run cleanup 39 | steps: 40 | - uses: actions/checkout@v4 41 | - uses: deckhouse/modules-actions/setup@v2 42 | with: 43 | registry: ${{ vars.DEV_REGISTRY }} 44 | registry_login: ${{ vars.DEV_MODULES_REGISTRY_LOGIN }} 45 | registry_password: ${{ secrets.DEV_MODULES_REGISTRY_PASSWORD }} 46 | - name: Cleanup 47 | run: | 48 | werf cleanup \ 49 | --repo ${MODULES_MODULE_SOURCE}/${MODULES_MODULE_NAME} \ 50 | --without-kube=true --config werf_cleanup.yaml 51 | -------------------------------------------------------------------------------- /.github/workflows/go_checks.yaml: -------------------------------------------------------------------------------- 1 | name: Go checks for images 2 | 3 | env: 4 | GO_BUILD_TAGS: "ce ee se seplus csepro" 5 | 6 | on: 7 | pull_request: 8 | push: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | go_linter: 14 | name: Go linter for images 15 | runs-on: [self-hosted, regular] 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v2 20 | 21 | - name: Run Go lint 22 | uses: deckhouse/modules-actions/go_linter@v2 23 | 24 | go_tests: 25 | name: Go tests for images 26 | runs-on: [self-hosted, regular] 27 | 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@v2 31 | 32 | - name: Run Go tests 33 | uses: deckhouse/modules-actions/go_tests@v2 34 | 35 | go_test_coverage: 36 | name: Go test coverage for images 37 | runs-on: [self-hosted, regular] 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v2 42 | 43 | - name: Run Go test coverage count 44 | uses: deckhouse/modules-actions/go_test_coverage@v2 45 | 46 | go_modules_check: 47 | name: Go modules version 48 | runs-on: [self-hosted, regular] 49 | 50 | steps: 51 | - name: Checkout repository 52 | uses: actions/checkout@v2 53 | 54 | - name: Run Go modules version check 55 | uses: deckhouse/modules-actions/go_modules_check@v2 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | 16 | # vim 17 | *.swp 18 | 19 | # IDE 20 | .project 21 | .settings 22 | .idea/ 23 | .vscode 24 | venv/ 25 | 26 | # macOS Finder files 27 | *.DS_Store 28 | ._* 29 | 30 | # Python 31 | __pycache__/ 32 | *.py[cod] 33 | *$py.class 34 | .pytest_cache/ 35 | 36 | # dev 37 | images/sds-replicated-volume-controller/dev/Dockerfile-dev 38 | images/sds-replicated-volume-controller/src/Makefile 39 | hack.sh 40 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | run: 2 | timeout: 10m 3 | 4 | issues: 5 | exclude: 6 | - ST1005.* 7 | - "should not use dot imports" 8 | - "don't use an underscore in package name" 9 | - "exported: .*" 10 | 11 | linters-settings: 12 | gci: 13 | sections: 14 | - standard 15 | - default 16 | - prefix(github.com/deckhouse) 17 | 18 | errcheck: 19 | exclude-functions: 20 | - fmt:.*,[rR]ead|[wW]rite|[cC]lose 21 | - io:Copy 22 | 23 | linters: 24 | disable-all: true 25 | enable: 26 | - dogsled 27 | - errcheck 28 | - gci 29 | - gocritic 30 | - gofmt 31 | - gosimple 32 | - govet 33 | - ineffassign 34 | - misspell 35 | - revive 36 | - staticcheck 37 | - typecheck 38 | - unconvert 39 | - unparam 40 | - whitespace 41 | - copyloopvar 42 | -------------------------------------------------------------------------------- /.helmignore: -------------------------------------------------------------------------------- 1 | crds 2 | docs 3 | enabled 4 | hooks 5 | images 6 | lib 7 | Makefile 8 | openapi 9 | *.md 10 | release.yaml 11 | werf*.yaml 12 | NOTES.txt 13 | -------------------------------------------------------------------------------- /.werf/base-images.yaml: -------------------------------------------------------------------------------- 1 | # Base Images 2 | {{- $baseImages := .Files.Get "base_images.yml" | fromYaml }} 3 | {{- range $k, $v := $baseImages }} 4 | {{ $baseImagePath := (printf "%s@%s" $baseImages.REGISTRY_PATH (trimSuffix "/" $v)) }} 5 | {{- if ne $k "REGISTRY_PATH" }} 6 | {{- $_ := set $baseImages $k $baseImagePath }} 7 | {{- end }} 8 | {{- end }} 9 | {{- $_ := unset $baseImages "REGISTRY_PATH" }} 10 | 11 | {{- $_ := set . "Images" $baseImages }} 12 | # base images artifacts 13 | {{- range $k, $v := .Images }} 14 | --- 15 | image: {{ $k }} 16 | from: {{ $v }} 17 | final: false 18 | {{- end }} 19 | 20 | -------------------------------------------------------------------------------- /.werf/bundle.yaml: -------------------------------------------------------------------------------- 1 | # Bundle image, stored in your.registry.io/modules/: 2 | --- 3 | image: bundle 4 | fromImage: builder/scratch 5 | 6 | import: 7 | # Rendering .werf/images-digests.yaml is required! 8 | - image: images-digests 9 | add: /images_digests.json 10 | to: /images_digests.json 11 | after: setup 12 | # Rendering .werf/python-deps.yaml is required! 13 | - image: python-dependencies 14 | add: /lib/python/dist 15 | to: /lib/python/dist 16 | after: setup 17 | # Rendering .werf/go-hooks.yaml is required! 18 | - image: go-hooks-artifact 19 | add: /usr/local/bin/go-hooks 20 | to: /hooks/go-hooks 21 | after: setup 22 | # Rendering .werf/choose-edition.yaml is required! 23 | - image: choose-edition 24 | add: /openapi 25 | to: /openapi 26 | after: setup 27 | git: 28 | - add: / 29 | to: / 30 | excludePaths: 31 | - hooks/go 32 | includePaths: 33 | - .helmignore 34 | - charts 35 | - crds 36 | - docs 37 | - hooks 38 | - monitoring 39 | - templates 40 | - Chart.yaml 41 | - module.yaml 42 | -------------------------------------------------------------------------------- /.werf/choose-edition.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: choose-edition 3 | fromImage: builder/alt 4 | fromCacheVersion: {{ div .Commit.Date.Unix (mul 60 60 24 30) }} 5 | 6 | git: 7 | - add: / 8 | to: / 9 | includePaths: 10 | - openapi 11 | stageDependencies: 12 | setup: 13 | - openapi/values_*.yaml 14 | shell: 15 | setup: 16 | - cd /openapi 17 | - if [[ {{ .MODULE_EDITION }} == "ce" ]]; then cp -v values_ce.yaml values.yaml; else cp -v values_ee.yaml values.yaml; fi 18 | - rm -rf values_*.yaml 19 | -------------------------------------------------------------------------------- /.werf/images-digests.yaml: -------------------------------------------------------------------------------- 1 | {{- /* Find all images digests and save use them to compose a structure for the module values. */ -}} 2 | {{- $ImagesIDList := list }} 3 | {{- $Images := tpl (.Files.Get ".werf/images.yaml") . }} 4 | 5 | 6 | {{- range $ImageManifest := regexSplit "\n?---[ \t]*\n" $Images -1 }} 7 | {{- $ImageManifest := $ImageManifest | fromYaml }} 8 | {{- if and $ImageManifest.image (ne ($ImageManifest.final | toJson) "false") }} 9 | {{- $ImagesIDList = append $ImagesIDList $ImageManifest.image }} 10 | {{- end }} 11 | {{- end }} 12 | 13 | # Images Digest: a files with all image digests to be able to use them in helm templates of a module 14 | --- 15 | image: images-digests 16 | fromImage: builder/alpine 17 | dependencies: 18 | {{- range $ImageID := $ImagesIDList }} 19 | {{- $ImageNameCamel := $ImageID | splitList "/" | last | camelcase | untitle }} 20 | - image: {{ $ImageID }} 21 | before: setup 22 | imports: 23 | - type: ImageDigest 24 | targetEnv: MODULE_IMAGE_DIGEST_{{ $ImageNameCamel }} 25 | {{- end }} 26 | shell: 27 | beforeInstall: 28 | - apk add --no-cache jq 29 | setup: 30 | - | 31 | env | grep MODULE_IMAGE_DIGEST | jq -Rn ' 32 | reduce inputs as $i ( 33 | {}; 34 | . * ( 35 | $i | ltrimstr("MODULE_IMAGE_DIGEST_") | sub("=";"_") | 36 | split("_") as [$imageName, $digest] | 37 | {($imageName): $digest} 38 | ) 39 | ) 40 | ' > /images_digests.json 41 | -------------------------------------------------------------------------------- /.werf/images.yaml: -------------------------------------------------------------------------------- 1 | {{- $ImagesBuildFiles := .Files.Glob "images/*/{Dockerfile,werf.inc.yaml}" }} 2 | 3 | {{- range $path, $content := $ImagesBuildFiles }} 4 | {{ $ctx := (dict "ImageName" ($path | split "/")._1 "Root" $ "Versions" $.VERSIONS) }} 5 | --- 6 | {{- /* For Dockerfile just render it from the folder. */ -}} 7 | {{- if not (regexMatch "/werf.inc.yaml$" $path) }} 8 | image: images/{{ $ctx.ImageName }} 9 | context: images/{{ $ctx.ImageName }} 10 | dockerfile: Dockerfile 11 | 12 | {{- /* For werf.inc.yaml render content by providing the ImageName param. */ -}} 13 | {{- else }} 14 | {{ tpl $content $ctx }} 15 | 16 | {{- end }} 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /.werf/python-deps.yaml: -------------------------------------------------------------------------------- 1 | # Python deps image, required to download dependencies and put it to the final module image (bundle) 2 | --- 3 | image: python-dependencies 4 | fromImage: builder/alpine 5 | 6 | git: 7 | - add: / 8 | to: / 9 | includePaths: 10 | - lib/python 11 | stageDependencies: 12 | setup: 13 | - lib/python/requirements.txt 14 | shell: 15 | beforeInstall: 16 | - apk add --no-cache python3 py3-pip 17 | setup: 18 | - pip3 install -r /lib/python/requirements.txt -t /lib/python/dist 19 | -------------------------------------------------------------------------------- /.werf/release.yaml: -------------------------------------------------------------------------------- 1 | # Release image, stored in your.registry.io/modules//release: 2 | --- 3 | image: release-channel-version-artifact 4 | fromImage: builder/alpine 5 | final: false 6 | shell: 7 | beforeInstall: 8 | - apk add --no-cache curl 9 | - curl -sfL https://github.com/mikefarah/yq/releases/download/2.4.1/yq_linux_amd64 --output /usr/local/bin/yq 10 | - chmod +x /usr/local/bin/yq 11 | install: 12 | - | 13 | yq n version "{{ env "CI_COMMIT_REF_NAME" }}" | yq r - -j > version.json 14 | --- 15 | image: release-channel-version 16 | fromImage: builder/scratch 17 | import: 18 | - image: release-channel-version-artifact 19 | add: / 20 | to: / 21 | after: install 22 | includePaths: 23 | - version.json 24 | -------------------------------------------------------------------------------- /Chart.yaml: -------------------------------------------------------------------------------- 1 | name: sds-replicated-volume 2 | version: 0.0.1 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /bin/bash 2 | 3 | .PHONY: update-dev 4 | update-dev: check-yq 5 | make bump-dev version=$$(./hack/increase_semver.sh -d $$(yq .version Chart.yaml)) 6 | 7 | .PHONY: update-patch 8 | update-patch: check-yq 9 | make bump version=$$(./hack/increase_semver.sh -p $$(yq .version Chart.yaml)) 10 | 11 | .PHONY: update-minor 12 | update-minor: check-yq 13 | make bump version=$$(./hack/increase_semver.sh -m $$(yq .version Chart.yaml)) 14 | 15 | .PHONY: update-major 16 | update-major: check-yq 17 | make bump version=$$(./hack/increase_semver.sh -M $$(yq .version Chart.yaml)) 18 | 19 | .PHONY: bump-dev 20 | bump-dev: current-version 21 | yq -i '.version="$(version)"' Chart.yaml 22 | yq -i '.version="v$(version)"' release.yaml 23 | 24 | git commit -a -s -m "bump version $(version)" 25 | 26 | .PHONY: bump 27 | bump: current-version 28 | yq -i '.version="$(version)"' Chart.yaml 29 | yq -i '.version="v$(version)"' release.yaml 30 | 31 | git commit -a -s -m "bump version $(version)" 32 | git tag "v$(version)" 33 | 34 | .PHONY: push 35 | push: 36 | git push -u origin HEAD && git push --tags 37 | 38 | .PHONY: current-version 39 | current-version: check-yq 40 | @echo "Current version: $$(yq .version Chart.yaml)" 41 | 42 | .PHONY: check-yq 43 | check-yq: 44 | @which yq >/dev/null || (echo "yq not found. Install it to change Chart.yaml"; exit 1) 45 | 46 | .PHONY: check-jq 47 | check-jq: 48 | @which jq >/dev/null || (echo "jq not found. Install it to change package.json"; exit 1) 49 | 50 | ##@ Helm lib 51 | 52 | .PHONY: helm-update-subcharts 53 | helm-update-subcharts: ## Download subcharts into charts directory. Please, set desired versions in Chart.yaml before download. 54 | @which helm || (echo "Helm not found. Please, install helm to update helm_lib."; exit 1) 55 | helm repo add deckhouse https://deckhouse.github.io/lib-helm && \ 56 | helm repo update && \ 57 | helm dep update 58 | 59 | .PHONY: helm-bump-helm-lib 60 | helm-bump-helm-lib: ## Update helm lib in charts directory to specified version. 61 | ##~ Options: version= 62 | @which yq || (echo "yq not found. Install it to change Chart.yaml"; exit 1) 63 | yq -i '.dependencies[] |= select(.name == "deckhouse_lib_helm").version = "$(version)"' Chart.yaml 64 | git rm charts/*.tgz || true 65 | mkdir -p charts 66 | $(MAKE) helm-update-subcharts 67 | @echo "Helm lib updated to $(version)" 68 | ls -la charts 69 | -------------------------------------------------------------------------------- /api/README.md: -------------------------------------------------------------------------------- 1 | To use this module, execute 2 | ``` 3 | go get github.com/deckhouse/MODULE/api@main. 4 | ``` 5 | 6 | The pseudo-tag will be generated automatically. 7 | 8 | Please note that model changes will NOT BE APPLIED in dependent modules until you rerun go get (the pseudo-tag points to a specific commit). 9 | Therefore, it is important to remember to apply go get in all external modules that use this models. 10 | 11 | !Also, DO NOT FORGET to update the models when the CRD are changed! -------------------------------------------------------------------------------- /api/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/deckhouse/sds-replicated-volume/api 2 | 3 | go 1.23.6 4 | 5 | require k8s.io/apimachinery v0.30.2 6 | 7 | require ( 8 | github.com/go-logr/logr v1.4.1 // indirect 9 | github.com/gogo/protobuf v1.3.2 // indirect 10 | github.com/google/gofuzz v1.2.0 // indirect 11 | github.com/json-iterator/go v1.1.12 // indirect 12 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 13 | github.com/modern-go/reflect2 v1.0.2 // indirect 14 | golang.org/x/net v0.40.0 // indirect 15 | golang.org/x/text v0.25.0 // indirect 16 | gopkg.in/inf.v0 v0.9.1 // indirect 17 | gopkg.in/yaml.v2 v2.4.0 // indirect 18 | k8s.io/klog/v2 v2.120.1 // indirect 19 | k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect 20 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect 21 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect 22 | ) 23 | -------------------------------------------------------------------------------- /api/linstor/layer_drbd_resource_definitions.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 linstor 18 | 19 | import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 | 21 | type LayerDrbdResourceDefinitions struct { 22 | metav1.TypeMeta `json:",inline"` 23 | metav1.ObjectMeta `json:"metadata,omitempty"` 24 | Spec struct { 25 | AlStripeSize int `json:"al_stripe_size"` 26 | AlStripes int `json:"al_stripes"` 27 | PeerSlots int `json:"peer_slots"` 28 | ResourceName string `json:"resource_name"` 29 | ResourceNameSuffix string `json:"resource_name_suffix"` 30 | Secret string `json:"secret"` 31 | SnapshotName string `json:"snapshot_name"` 32 | TCPPort int `json:"tcp_port"` 33 | TransportType string `json:"transport_type"` 34 | } `json:"spec"` 35 | } 36 | 37 | type LayerDrbdResourceDefinitionsList struct { 38 | metav1.TypeMeta `json:",inline"` 39 | metav1.ListMeta `json:"metadata"` 40 | Items []LayerDrbdResourceDefinitions `json:"items"` 41 | } 42 | -------------------------------------------------------------------------------- /api/linstor/layer_drbd_volume_definitions.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 linstor 18 | 19 | import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 | 21 | type LayerDrbdVolumeDefinitions struct { 22 | metav1.TypeMeta `json:",inline"` 23 | metav1.ObjectMeta `json:"metadata,omitempty"` 24 | Spec struct { 25 | ResourceName string `json:"resource_name"` 26 | ResourceNameSuffix string `json:"resource_name_suffix"` 27 | SnapshotName string `json:"snapshot_name"` 28 | VlmMinorNr int `json:"vlm_minor_nr"` 29 | VlmNr int `json:"vlm_nr"` 30 | } `json:"spec"` 31 | } 32 | 33 | type LayerDrbdVolumeDefinitionsList struct { 34 | metav1.TypeMeta `json:",inline"` 35 | metav1.ListMeta `json:"metadata"` 36 | Items []LayerDrbdVolumeDefinitions `json:"items"` 37 | } 38 | -------------------------------------------------------------------------------- /api/linstor/layer_storage_volumes.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 linstor 18 | 19 | import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 | 21 | type LayerStorageVolumes struct { 22 | metav1.TypeMeta `json:",inline"` 23 | metav1.ObjectMeta `json:"metadata,omitempty"` 24 | Spec struct { 25 | LayerResourceID int `json:"layer_resource_id"` 26 | NodeName string `json:"node_name"` 27 | ProviderKind string `json:"provider_kind"` 28 | StorPoolName string `json:"stor_pool_name"` 29 | VlmNr int `json:"vlm_nr"` 30 | } `json:"spec"` 31 | } 32 | 33 | type LayerStorageVolumesList struct { 34 | metav1.TypeMeta `json:",inline"` 35 | metav1.ListMeta `json:"metadata"` 36 | Items []LayerStorageVolumes `json:"items"` 37 | } 38 | -------------------------------------------------------------------------------- /api/linstor/props_containers.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 linstor 18 | 19 | import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 | 21 | type PropsContainersSpec struct { 22 | PropKey string `json:"prop_key"` 23 | PropValue string `json:"prop_value"` 24 | PropsInstance string `json:"props_instance"` 25 | } 26 | 27 | type PropsContainers struct { 28 | metav1.TypeMeta `json:",inline"` 29 | metav1.ObjectMeta `json:"metadata,omitempty"` 30 | Spec PropsContainersSpec `json:"spec"` 31 | } 32 | 33 | type PropsContainersList struct { 34 | metav1.TypeMeta `json:",inline"` 35 | metav1.ListMeta `json:"metadata"` 36 | Items []PropsContainers `json:"items"` 37 | } 38 | -------------------------------------------------------------------------------- /api/linstor/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 linstor 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/apimachinery/pkg/runtime" 22 | "k8s.io/apimachinery/pkg/runtime/schema" 23 | ) 24 | 25 | const ( 26 | APIGroup = "internal.linstor.linbit.com" 27 | APIVersion = "v1-15-0" 28 | ) 29 | 30 | // SchemeGroupVersion is group version used to register these objects 31 | var ( 32 | SchemeGroupVersion = schema.GroupVersion{ 33 | Group: APIGroup, 34 | Version: APIVersion, 35 | } 36 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 37 | AddToScheme = SchemeBuilder.AddToScheme 38 | ) 39 | 40 | // Adds the list of known types to Scheme. 41 | func addKnownTypes(scheme *runtime.Scheme) error { 42 | scheme.AddKnownTypes(SchemeGroupVersion, 43 | &ResourceGroups{}, 44 | &ResourceGroupsList{}, 45 | &LayerDrbdResourceDefinitions{}, 46 | &LayerDrbdResourceDefinitionsList{}, 47 | &VolumeDefinitions{}, 48 | &VolumeDefinitionsList{}, 49 | &LayerDrbdVolumeDefinitions{}, 50 | &LayerDrbdVolumeDefinitionsList{}, 51 | &PropsContainers{}, 52 | &PropsContainersList{}, 53 | &Resources{}, 54 | &ResourcesList{}, 55 | &LayerStorageVolumes{}, 56 | &LayerStorageVolumesList{}, 57 | &ResourceDefinitions{}, 58 | &ResourceDefinitionsList{}, 59 | ) 60 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /api/linstor/resource.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 linstor 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | type Resources struct { 24 | metav1.TypeMeta `json:",inline"` 25 | metav1.ObjectMeta `json:"metadata,omitempty"` 26 | Spec struct { 27 | CreateTimestamp int64 `json:"create_timestamp"` 28 | NodeName string `json:"node_name"` 29 | ResourceFlags int `json:"resource_flags"` 30 | ResourceName string `json:"resource_name"` 31 | SnapshotName string `json:"snapshot_name"` 32 | UUID string `json:"uuid"` 33 | } `json:"spec"` 34 | } 35 | 36 | type ResourcesList struct { 37 | metav1.TypeMeta `json:",inline"` 38 | metav1.ListMeta `json:"metadata"` 39 | Items []Resources `json:"items"` 40 | } 41 | -------------------------------------------------------------------------------- /api/linstor/resource_definitions.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 linstor 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | type ResourceDefinitions struct { 24 | metav1.TypeMeta `json:",inline"` 25 | metav1.ObjectMeta `json:"metadata,omitempty"` 26 | Spec struct { 27 | LayerStack string `json:"layer_stack"` 28 | ResourceDspName string `json:"resource_dsp_name"` 29 | ResourceFlags int `json:"resource_flags"` 30 | ResourceGroupName string `json:"resource_group_name"` 31 | ResourceName string `json:"resource_name"` 32 | SnapshotDspName string `json:"snapshot_dsp_name"` 33 | SnapshotName string `json:"snapshot_name"` 34 | UUID string `json:"uuid"` 35 | } `json:"spec"` 36 | } 37 | 38 | type ResourceDefinitionsList struct { 39 | metav1.TypeMeta `json:",inline"` 40 | metav1.ListMeta `json:"metadata"` 41 | Items []ResourceDefinitions `json:"items"` 42 | } 43 | -------------------------------------------------------------------------------- /api/linstor/resource_groups.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 linstor 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | type ResourceGroups struct { 24 | metav1.TypeMeta `json:",inline"` 25 | metav1.ObjectMeta `json:"metadata,omitempty"` 26 | Spec struct { 27 | AllowedProviderList string `json:"allowed_provider_list"` 28 | Description string `json:"description"` 29 | DoNotPlaceWithRscList string `json:"do_not_place_with_rsc_list"` 30 | LayerStack string `json:"layer_stack"` 31 | NodeNameList string `json:"node_name_list"` 32 | PoolName string `json:"pool_name"` 33 | PoolNameDiskless string `json:"pool_name_diskless"` 34 | ReplicaCount int `json:"replica_count"` 35 | ReplicasOnDifferent string `json:"replicas_on_different"` 36 | ReplicasOnSame string `json:"replicas_on_same"` 37 | ResourceGroupDspName string `json:"resource_group_dsp_name"` 38 | ResourceGroupName string `json:"resource_group_name"` 39 | UUID string `json:"uuid"` 40 | } `json:"spec"` 41 | } 42 | 43 | type ResourceGroupsList struct { 44 | metav1.TypeMeta `json:",inline"` 45 | metav1.ListMeta `json:"metadata"` 46 | Items []ResourceGroups `json:"items"` 47 | } 48 | -------------------------------------------------------------------------------- /api/linstor/volume_definitions.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 linstor 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | type VolumeDefinitions struct { 24 | metav1.TypeMeta `json:",inline"` 25 | metav1.ObjectMeta `json:"metadata,omitempty"` 26 | Spec struct { 27 | ResourceName string `json:"resource_name"` 28 | SnapshotName string `json:"snapshot_name"` 29 | UUID string `json:"uuid"` 30 | VlmFlags int `json:"vlm_flags"` 31 | VlmNr int `json:"vlm_nr"` 32 | VlmSize int `json:"vlm_size"` 33 | } `json:"spec"` 34 | } 35 | 36 | type VolumeDefinitionsList struct { 37 | metav1.TypeMeta `json:",inline"` 38 | metav1.ListMeta `json:"metadata"` 39 | Items []VolumeDefinitions `json:"items"` 40 | } 41 | -------------------------------------------------------------------------------- /api/v1alpha1/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/apimachinery/pkg/runtime" 22 | "k8s.io/apimachinery/pkg/runtime/schema" 23 | ) 24 | 25 | const ( 26 | APIGroup = "storage.deckhouse.io" 27 | APIVersion = "v1alpha1" // v1alpha1 28 | ) 29 | 30 | // SchemeGroupVersion is group version used to register these objects 31 | var ( 32 | SchemeGroupVersion = schema.GroupVersion{ 33 | Group: APIGroup, 34 | Version: APIVersion, 35 | } 36 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) 37 | AddToScheme = SchemeBuilder.AddToScheme 38 | ) 39 | 40 | // Adds the list of known types to Scheme. 41 | func addKnownTypes(scheme *runtime.Scheme) error { 42 | scheme.AddKnownTypes(SchemeGroupVersion, 43 | &ReplicatedStorageClass{}, 44 | &ReplicatedStorageClassList{}, 45 | &ReplicatedStoragePool{}, 46 | &ReplicatedStoragePoolList{}, 47 | ) 48 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 49 | return nil 50 | } 51 | -------------------------------------------------------------------------------- /api/v1alpha1/replicated_storage_class.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 | 21 | type ReplicatedStorageClass struct { 22 | metav1.TypeMeta `json:",inline"` 23 | metav1.ObjectMeta `json:"metadata,omitempty"` 24 | Spec ReplicatedStorageClassSpec `json:"spec"` 25 | Status ReplicatedStorageClassStatus `json:"status,omitempty"` 26 | } 27 | 28 | // ReplicatedStorageClassList contains a list of empty block device 29 | type ReplicatedStorageClassList struct { 30 | metav1.TypeMeta `json:",inline"` 31 | metav1.ListMeta `json:"metadata"` 32 | Items []ReplicatedStorageClass `json:"items"` 33 | } 34 | 35 | type ReplicatedStorageClassSpec struct { 36 | StoragePool string `json:"storagePool"` 37 | ReclaimPolicy string `json:"reclaimPolicy"` 38 | Replication string `json:"replication"` 39 | VolumeAccess string `json:"volumeAccess"` 40 | Topology string `json:"topology"` 41 | Zones []string `json:"zones"` 42 | } 43 | 44 | type ReplicatedStorageClassStatus struct { 45 | Phase string `json:"phase,omitempty"` 46 | Reason string `json:"reason,omitempty"` 47 | } 48 | -------------------------------------------------------------------------------- /api/v1alpha1/replicated_storage_pool.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 | 21 | type ReplicatedStoragePool struct { 22 | metav1.TypeMeta `json:",inline"` 23 | metav1.ObjectMeta `json:"metadata,omitempty"` 24 | Spec ReplicatedStoragePoolSpec `json:"spec"` 25 | Status ReplicatedStoragePoolStatus `json:"status,omitempty"` 26 | } 27 | 28 | type ReplicatedStoragePoolSpec struct { 29 | Type string `json:"type"` 30 | LVMVolumeGroups []ReplicatedStoragePoolLVMVolumeGroups `json:"lvmVolumeGroups"` 31 | } 32 | 33 | type ReplicatedStoragePoolLVMVolumeGroups struct { 34 | Name string `json:"name"` 35 | ThinPoolName string `json:"thinPoolName"` 36 | } 37 | 38 | type ReplicatedStoragePoolStatus struct { 39 | Phase string `json:"phase"` 40 | Reason string `json:"reason"` 41 | } 42 | 43 | // ReplicatedStoragePoolList contains a list of ReplicatedStoragePool 44 | type ReplicatedStoragePoolList struct { 45 | metav1.TypeMeta `json:",inline"` 46 | metav1.ListMeta `json:"metadata"` 47 | Items []ReplicatedStoragePool `json:"items"` 48 | } 49 | -------------------------------------------------------------------------------- /charts/deckhouse_lib_helm-1.57.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deckhouse/sds-replicated-volume/f2e65d667eadeea727930092e3fe21d20a492ef7/charts/deckhouse_lib_helm-1.57.0.tgz -------------------------------------------------------------------------------- /crds/doc-ru-replicatedstoragebackup.yaml: -------------------------------------------------------------------------------- 1 | spec: 2 | versions: 3 | - name: v1alpha1 4 | schema: 5 | openAPIV3Schema: 6 | description: | 7 | Объекты для хранения резервных копий базы данных control-plane 8 | properties: 9 | spec: 10 | properties: 11 | spec: 12 | type: object 13 | description: | 14 | Хранит резервные копии базы данных control-plane 15 | properties: 16 | data: 17 | type: string 18 | description: | 19 | Часть резервной копии базы данных control-plane в base64 20 | -------------------------------------------------------------------------------- /crds/doc-ru-replicatedstoragepool.yaml: -------------------------------------------------------------------------------- 1 | spec: 2 | versions: 3 | - name: v1alpha1 4 | schema: 5 | openAPIV3Schema: 6 | description: | 7 | Интерфейс для управления Storage Pool в бэкенде LINSTOR. 8 | properties: 9 | spec: 10 | properties: 11 | type: 12 | description: | 13 | Определяет тип Volume'ов. Может быть: 14 | - LVM (для классических LVM-томов) 15 | - LVMThin (для Thin-томов) 16 | lvmVolumeGroups: 17 | description: | 18 | Список LVMVolumeGroup-ресурсов, Volume Group'ы/Thin-pool'ы которых будут использованы для создания Storage-pool'ов в бэкенде LINSTOR. 19 | 20 | > Обратите внимание, что каждый LVMVolumeGroup-ресурс обязан иметь тот же тип (Thin/Thick), что указан в поле 'Spec.Type' текущего ресурса. 21 | items: 22 | properties: 23 | name: 24 | description: | 25 | Имя ресурса LVMVolumeGroup. 26 | thinPoolName: 27 | description: | 28 | Имя выбранного Thin-pool в рамках указанного LVMVolumeGroup. Обязательное поле если вы создаёте ReplicatedStoragePool с типом LVMThin. 29 | status: 30 | properties: 31 | phase: 32 | description: | 33 | Текущее состояние ReplicatedStoragePool-ресурса. Может быть: 34 | - Completed (если контроллер получил корректную конфигурацию ресурса и конфигурация Storage-pool'ов в LINSTOR обновлена) 35 | - Updating (если контроллер получил корректную конфигурацию ресурса и конфигурация Storage-pool'ов в LINSTOR обновляется) 36 | - Failed (если контроллер получил некорректную конфигурацию ресурса или во время операции возникла ошибка) 37 | reason: 38 | description: | 39 | Дополнительная информация о текущем состоянии ресурса. 40 | -------------------------------------------------------------------------------- /crds/replicatedstoragebackup.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: replicatedstoragemetadatabackups.storage.deckhouse.io 5 | labels: 6 | heritage: deckhouse 7 | module: sds-replicated-volume 8 | backup.deckhouse.io/cluster-config: "true" 9 | spec: 10 | group: storage.deckhouse.io 11 | scope: Cluster 12 | names: 13 | plural: replicatedstoragemetadatabackups 14 | singular: replicatedstoragemetadatabackup 15 | kind: ReplicatedStorageMetadataBackup 16 | shortNames: 17 | - rsmb 18 | versions: 19 | - name: v1alpha1 20 | served: true 21 | storage: true 22 | schema: 23 | openAPIV3Schema: 24 | type: object 25 | description: | 26 | ReplicatedStorageMetadataBackup is a Kubernetes Custom Resource that stores Linstor control-plane database backup. 27 | required: 28 | - spec 29 | properties: 30 | spec: 31 | type: object 32 | description: | 33 | Stores Linstor's control-plane database backup. 34 | properties: 35 | data: 36 | type: string 37 | description: | 38 | Part of the Linstor's control-plane database backup -------------------------------------------------------------------------------- /docs/CONFIGURATION.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The sds-replicated-volume module: configuration" 3 | force_searchable: true 4 | description: The sds-replicated-volume Deckhouse module's configuration. 5 | --- 6 | 7 | {{< alert level="warning" >}} 8 | The module is only guaranteed to work if the [system requirements](./readme.html#system-requirements-and-recommendations) are met. 9 | As for any other configurations, the module may work, but its smooth operation is not guaranteed. 10 | {{< /alert >}} 11 | -------------------------------------------------------------------------------- /docs/CONFIGURATION_RU.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Модуль sds-replicated-volume: настройки" 3 | force_searchable: true 4 | description: Параметры настройки модуля sds-replicated-volume Deckhouse. 5 | --- 6 | 7 | {{< alert level="warning" >}} 8 | Работоспособность модуля гарантируется только при соблюдении [системных требований](./readme.html#системные-требования-и-рекомендации). 9 | Использование в других условиях возможно, но стабильная работа в таких случаях не гарантируется. 10 | {{< /alert >}} 11 | -------------------------------------------------------------------------------- /docs/CR.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The sds-replicated-volume module: Custom Resources" 3 | description: "The sds-replicated-volume module Custom Resources: ReplicatedStoragePool and ReplicatedStorageClass." 4 | --- 5 | 6 | {{< alert level="warning" >}} 7 | The module is only guaranteed to work if the [system requirements](./readme.html#system-requirements-and-recommendations) are met. 8 | As for any other configurations, the module may work, but its smooth operation is not guaranteed. 9 | {{< /alert >}} 10 | -------------------------------------------------------------------------------- /docs/CR_RU.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Модуль sds-replicated-volume: Custom Resources" 3 | description: "Модуль sds-replicated-volume Custom Resources: ReplicatedStoragePool и ReplicatedStorageClass." 4 | --- 5 | 6 | {{< alert level="warning" >}} 7 | Работоспособность модуля гарантируется только при соблюдении [системных требований](./readme.html#системные-требования-и-рекомендации). 8 | Использование в других условиях возможно, но стабильная работа в таких случаях не гарантируется. 9 | {{< /alert >}} 10 | -------------------------------------------------------------------------------- /docs/images/trans-zonal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deckhouse/sds-replicated-volume/f2e65d667eadeea727930092e3fe21d20a492ef7/docs/images/trans-zonal.png -------------------------------------------------------------------------------- /docs/images/trans-zonal.ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deckhouse/sds-replicated-volume/f2e65d667eadeea727930092e3fe21d20a492ef7/docs/images/trans-zonal.ru.png -------------------------------------------------------------------------------- /docs/images/zonal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deckhouse/sds-replicated-volume/f2e65d667eadeea727930092e3fe21d20a492ef7/docs/images/zonal.png -------------------------------------------------------------------------------- /docs/images/zonal.ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deckhouse/sds-replicated-volume/f2e65d667eadeea727930092e3fe21d20a492ef7/docs/images/zonal.ru.png -------------------------------------------------------------------------------- /hooks/common.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright 2023 Flant JSC 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 | from deckhouse import hook 18 | from lib.module import module 19 | from typing import Callable 20 | import json 21 | import os 22 | import unittest 23 | 24 | 25 | NAMESPACE = "d8-sds-replicated-volume" 26 | MODULE_NAME = "sdsReplicatedVolume" 27 | 28 | def json_load(path: str): 29 | with open(path, "r", encoding="utf-8") as f: 30 | data = json.load(f) 31 | return data 32 | 33 | def get_dir_path() -> str: 34 | return os.path.dirname(os.path.abspath(__file__)) 35 | -------------------------------------------------------------------------------- /hooks/discovery_data_nodes_checksum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright 2023 Flant JSC 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 | from deckhouse import hook 18 | from typing import Callable 19 | 20 | import yaml 21 | import hashlib 22 | 23 | from lib.hooks.hook import Hook 24 | from lib.module import values as module_values 25 | import common 26 | 27 | 28 | NODE_SNAPSHOT_NAME = "nodes" 29 | MODULE_NAME = "sds-replicated-volume" 30 | NODE_LABELS_TO_FOLLOW = {"storage.deckhouse.io/sds-replicated-volume-node": ""} 31 | QUEUE = f"/modules/{MODULE_NAME}/node-label-change" 32 | 33 | config = { 34 | "configVersion": "v1", 35 | "kubernetes": [ 36 | { 37 | "name": NODE_SNAPSHOT_NAME, 38 | "apiVersion": "v1", 39 | "kind": "Node", 40 | "includeSnapshotsFrom": [ 41 | NODE_SNAPSHOT_NAME 42 | ], 43 | "jqFilter": '{"uid": .metadata.uid}', 44 | "labelSelector": { 45 | "matchLabels": NODE_LABELS_TO_FOLLOW 46 | }, 47 | "queue": QUEUE, 48 | "keepFullObjectsInMemory": False 49 | } 50 | ] 51 | } 52 | 53 | def main(ctx: hook.Context): 54 | uid_list = sorted(_['filterResult']['uid'] for _ in ctx.snapshots.get(NODE_SNAPSHOT_NAME, [])) 55 | hash = hashlib.sha256(bytes(str(uid_list), 'UTF-8')).hexdigest() 56 | module_values.set_value(f"{common.MODULE_NAME}.internal.dataNodesChecksum", ctx.values, hash) 57 | 58 | if __name__ == "__main__": 59 | if isinstance(config, dict): 60 | conf = yaml.dump(config) 61 | hook.run(main, config=conf) 62 | -------------------------------------------------------------------------------- /hooks/ensure_crds.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright 2023 Flant JSC 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 | import os 18 | 19 | import yaml 20 | from deckhouse import hook 21 | 22 | # We expect structure with possible subdirectories like this: 23 | # 24 | # my-module/ 25 | # crds/ 26 | # crd1.yaml 27 | # crd2.yaml 28 | # subdir/ 29 | # crd3.yaml 30 | # hooks/ 31 | # ensure_crds.py # this file 32 | 33 | 34 | config = """ 35 | configVersion: v1 36 | onStartup: 5 37 | """ 38 | 39 | 40 | def main(ctx: hook.Context): 41 | for crd in iter_manifests(find_crds_root(__file__)): 42 | ctx.kubernetes.create_or_update(crd) 43 | 44 | 45 | def iter_manifests(root_path: str): 46 | if not os.path.exists(root_path): 47 | return 48 | 49 | for dirpath, dirnames, filenames in os.walk(top=root_path): 50 | for filename in filenames: 51 | if not filename.endswith(".yaml"): 52 | # Wee only seek manifests 53 | continue 54 | if filename.startswith("doc-"): 55 | # Skip dedicated doc yamls, common for Deckhouse internal modules 56 | continue 57 | 58 | crd_path = os.path.join(dirpath, filename) 59 | with open(crd_path, "r", encoding="utf-8") as f: 60 | for manifest in yaml.safe_load_all(f): 61 | if manifest is None: 62 | continue 63 | yield manifest 64 | 65 | for dirname in dirnames: 66 | subroot = os.path.join(dirpath, dirname) 67 | for manifest in iter_manifests(subroot): 68 | yield manifest 69 | 70 | 71 | def find_crds_root(hookpath): 72 | hooks_root = os.path.dirname(hookpath) 73 | module_root = os.path.dirname(hooks_root) 74 | crds_root = os.path.join(module_root, "crds") 75 | return crds_root 76 | 77 | 78 | if __name__ == "__main__": 79 | hook.run(main, config=config) 80 | -------------------------------------------------------------------------------- /hooks/go/060-manual-cert-renewal/manual_cert_renewal_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Flant JSC 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 manualcertrenewal 18 | 19 | import ( 20 | "context" 21 | "os" 22 | "testing" 23 | 24 | "github.com/deckhouse/deckhouse/pkg/log" 25 | "github.com/deckhouse/module-sdk/pkg" 26 | ) 27 | 28 | func TestManualCertRenewal(t *testing.T) { 29 | devMode = true 30 | os.Setenv("LOG_LEVEL", "INFO") 31 | 32 | err := manualCertRenewal(context.Background(), &pkg.HookInput{ 33 | Logger: log.Default(), 34 | }) 35 | 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /hooks/go/060-manual-cert-renewal/state_machine_cache.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Flant JSC 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 manualcertrenewal 18 | 19 | import ( 20 | "fmt" 21 | 22 | appsv1 "k8s.io/api/apps/v1" 23 | v1 "k8s.io/api/core/v1" 24 | "k8s.io/apimachinery/pkg/types" 25 | 26 | "github.com/deckhouse/sds-replicated-volume/hooks/go/consts" 27 | "github.com/deckhouse/sds-replicated-volume/hooks/go/utils" 28 | ) 29 | 30 | func (s *stateMachine) getDeployment(name string, forceReload bool) (*appsv1.Deployment, error) { 31 | if depl, ok := s.cachedDeployments[name]; !forceReload && ok { 32 | return depl, nil 33 | } 34 | 35 | depl := &appsv1.Deployment{} 36 | 37 | if err := s.cl.Get( 38 | s.ctx, 39 | types.NamespacedName{Namespace: consts.ModuleNamespace, Name: name}, 40 | depl, 41 | ); err != nil { 42 | return nil, fmt.Errorf("getting deployment %s: %w", name, err) 43 | } 44 | 45 | utils.MapEnsureAndSet(&s.cachedDeployments, name, depl) 46 | 47 | return depl, nil 48 | } 49 | 50 | func (s *stateMachine) getDaemonSet(name string, forceReload bool) (*appsv1.DaemonSet, error) { 51 | if ds, ok := s.cachedDaemonSets[name]; !forceReload && ok { 52 | return ds, nil 53 | } 54 | 55 | ds := &appsv1.DaemonSet{} 56 | 57 | if err := s.cl.Get( 58 | s.ctx, 59 | types.NamespacedName{Namespace: consts.ModuleNamespace, Name: name}, 60 | ds, 61 | ); err != nil { 62 | return nil, fmt.Errorf("getting daemonset %s: %w", name, err) 63 | } 64 | 65 | utils.MapEnsureAndSet(&s.cachedDaemonSets, name, ds) 66 | 67 | return ds, nil 68 | } 69 | 70 | func (s *stateMachine) getSecret(name string, forceReload bool) (*v1.Secret, error) { 71 | if secret, ok := s.cachedSecrets[name]; !forceReload && ok { 72 | return secret, nil 73 | } 74 | 75 | secret := &v1.Secret{} 76 | 77 | if err := s.cl.Get( 78 | s.ctx, 79 | types.NamespacedName{Namespace: consts.ModuleNamespace, Name: name}, 80 | secret, 81 | ); err != nil { 82 | return nil, fmt.Errorf("getting secret %s: %w", name, err) 83 | } 84 | 85 | utils.MapEnsureAndSet(&s.cachedSecrets, name, secret) 86 | 87 | return secret, nil 88 | } 89 | -------------------------------------------------------------------------------- /hooks/go/060-manual-cert-renewal/state_machine_certs.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Flant JSC 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 manualcertrenewal 18 | 19 | import ( 20 | "fmt" 21 | "iter" 22 | 23 | "github.com/deckhouse/sds-replicated-volume/hooks/go/certs" 24 | tlsc "github.com/deckhouse/sds-replicated-volume/hooks/go/tls-certificate" 25 | ) 26 | 27 | var allCertGroupsConfigs = makeAllCertGroupsConfigs() 28 | 29 | func makeAllCertGroupsConfigs() iter.Seq[tlsc.GenSelfSignedTLSGroupHookConf] { 30 | return func(yield func(tlsc.GenSelfSignedTLSGroupHookConf) bool) { 31 | if !yield(certs.LinstorCertConfigs()) { 32 | return 33 | } 34 | if !yield(certs.WebhookCertConfigs()) { 35 | return 36 | } 37 | if !yield(certs.SchedulerExtenderCertConfig) { 38 | return 39 | } 40 | if !yield(certs.SpaasCertConfig) { 41 | return 42 | } 43 | } 44 | } 45 | 46 | func allCertConfigs() iter.Seq[tlsc.GenSelfSignedTLSHookConf] { 47 | return func(yield func(tlsc.GenSelfSignedTLSHookConf) bool) { 48 | for confs := range allCertGroupsConfigs { 49 | for _, conf := range confs { 50 | if !yield(conf) { 51 | return 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | func (s *stateMachine) renewCerts() error { 59 | for groupConf := range allCertGroupsConfigs { 60 | if err := s.renewCertGroup(groupConf); err != nil { 61 | return err 62 | } 63 | } 64 | 65 | return nil 66 | } 67 | 68 | func (s *stateMachine) renewCertGroup(confs tlsc.GenSelfSignedTLSGroupHookConf) error { 69 | newCerts, err := tlsc.GenerateNewSelfSignedTLSGroup( // input.Values will be set there 70 | s.hookInput, 71 | confs, 72 | ) 73 | if err != nil { 74 | return fmt.Errorf("generating new cert group: %w", err) 75 | } 76 | 77 | for i, cert := range newCerts { 78 | secret, err := s.getSecret(confs[i].TLSSecretName, false) 79 | if err != nil { 80 | return err 81 | } 82 | secret.Data["tls.key"] = cert.Key 83 | secret.Data["tls.crt"] = cert.Cert 84 | secret.Data["ca.crt"] = cert.CA 85 | if err := s.cl.Update(s.ctx, secret); err != nil { 86 | return fmt.Errorf("updating secret %s: %w", secret.Name, err) 87 | } 88 | s.log.Info("generated and saved cert", "name", secret.Name) 89 | } 90 | 91 | return nil 92 | } 93 | -------------------------------------------------------------------------------- /hooks/go/070-generate-certs/linstor_certs.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Flant JSC 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 generatecerts 18 | 19 | import "github.com/deckhouse/sds-replicated-volume/hooks/go/certs" 20 | 21 | func init() { 22 | certs.RegisterLinstorCertsHook() 23 | } 24 | -------------------------------------------------------------------------------- /hooks/go/070-generate-certs/scheduler_extender_cert.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Flant JSC 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 generatecerts 18 | 19 | import "github.com/deckhouse/sds-replicated-volume/hooks/go/certs" 20 | 21 | func init() { 22 | certs.RegisterSchedulerExtenderCertHook() 23 | } 24 | -------------------------------------------------------------------------------- /hooks/go/070-generate-certs/spaas_cert.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Flant JSC 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 generatecerts 18 | 19 | import "github.com/deckhouse/sds-replicated-volume/hooks/go/certs" 20 | 21 | func init() { 22 | certs.RegisterSpaasCertHook() 23 | } 24 | -------------------------------------------------------------------------------- /hooks/go/070-generate-certs/webhook_certs.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Flant JSC 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 generatecerts 18 | 19 | import "github.com/deckhouse/sds-replicated-volume/hooks/go/certs" 20 | 21 | func init() { 22 | certs.RegisterWebhookCertsHook() 23 | } 24 | -------------------------------------------------------------------------------- /hooks/go/certs/scheduler_extender_cert.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Flant JSC 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 certs 18 | 19 | import ( 20 | "fmt" 21 | 22 | kcertificates "k8s.io/api/certificates/v1" 23 | 24 | chcrt "github.com/deckhouse/module-sdk/common-hooks/tls-certificate" 25 | . "github.com/deckhouse/sds-replicated-volume/hooks/go/consts" 26 | tlscertificate "github.com/deckhouse/sds-replicated-volume/hooks/go/tls-certificate" 27 | ) 28 | 29 | func RegisterSchedulerExtenderCertHook() { 30 | tlscertificate.RegisterManualTLSHookEM(SchedulerExtenderCertConfig) 31 | } 32 | 33 | var SchedulerExtenderCertConfig = tlscertificate.MustNewGenSelfSignedTLSGroupHookConf( 34 | tlscertificate.GenSelfSignedTLSHookConf{ 35 | CN: "linstor-scheduler-extender", 36 | Namespace: ModuleNamespace, 37 | TLSSecretName: "linstor-scheduler-extender-https-certs", 38 | SANs: chcrt.DefaultSANs([]string{ 39 | "linstor-scheduler-extender", 40 | fmt.Sprintf("linstor-scheduler-extender.%s", ModuleNamespace), 41 | fmt.Sprintf("linstor-scheduler-extender.%s.svc", ModuleNamespace), 42 | fmt.Sprintf("%%CLUSTER_DOMAIN%%://linstor-scheduler-extender.%s.svc", ModuleNamespace), 43 | }), 44 | FullValuesPathPrefix: fmt.Sprintf("%s.internal.customSchedulerExtenderCert", ModuleName), 45 | Usages: []kcertificates.KeyUsage{ 46 | kcertificates.UsageKeyEncipherment, 47 | kcertificates.UsageCertSign, 48 | // ExtKeyUsage 49 | kcertificates.UsageServerAuth, 50 | }, 51 | CAExpiryDuration: DefaultCertExpiredDuration, 52 | CertExpiryDuration: DefaultCertExpiredDuration, 53 | CertOutdatedDuration: DefaultCertOutdatedDuration, 54 | }, 55 | ) 56 | -------------------------------------------------------------------------------- /hooks/go/certs/spaas_cert.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Flant JSC 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 certs 18 | 19 | import ( 20 | "fmt" 21 | 22 | kcertificates "k8s.io/api/certificates/v1" 23 | 24 | chcrt "github.com/deckhouse/module-sdk/common-hooks/tls-certificate" 25 | . "github.com/deckhouse/sds-replicated-volume/hooks/go/consts" 26 | tlscertificate "github.com/deckhouse/sds-replicated-volume/hooks/go/tls-certificate" 27 | ) 28 | 29 | func RegisterSpaasCertHook() { 30 | tlscertificate.RegisterManualTLSHookEM(SpaasCertConfig) 31 | } 32 | 33 | var SpaasCertConfig = tlscertificate.MustNewGenSelfSignedTLSGroupHookConf( 34 | tlscertificate.GenSelfSignedTLSHookConf{ 35 | CN: "spaas", 36 | Namespace: ModuleNamespace, 37 | TLSSecretName: "spaas-certs", 38 | SANs: chcrt.DefaultSANs([]string{ 39 | "spaas", 40 | fmt.Sprintf("spaas.%s", ModuleNamespace), 41 | fmt.Sprintf("spaas.%s.svc", ModuleNamespace), 42 | }), 43 | FullValuesPathPrefix: fmt.Sprintf("%s.internal.spaasCert", ModuleName), 44 | CommonCACanonicalName: "spaas-ca", 45 | Usages: []kcertificates.KeyUsage{ 46 | kcertificates.UsageKeyEncipherment, 47 | kcertificates.UsageCertSign, 48 | // ExtKeyUsage 49 | kcertificates.UsageServerAuth, 50 | }, 51 | CAExpiryDuration: DefaultCertExpiredDuration, 52 | CertExpiryDuration: DefaultCertExpiredDuration, 53 | CertOutdatedDuration: DefaultCertOutdatedDuration, 54 | }, 55 | ) 56 | -------------------------------------------------------------------------------- /hooks/go/consts/consts.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Flant JSC 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 consts 18 | 19 | import "time" 20 | 21 | const ( 22 | ModuleURI = "storage.deckhouse.io/sds-replicated-volume" 23 | ModuleName = "sdsReplicatedVolume" 24 | ModuleLabelValue = "sds-replicated-volume" 25 | ModuleNamespace = "d8-sds-replicated-volume" 26 | SecretCertExpire30dLabel = ModuleURI + "-cert-expire-in-30d" 27 | // this is used to avoid trigger certificate hooks 28 | SecretCertHookSuppressedByLabel = ModuleURI + "-cert-hook-suppressed-by" 29 | ) 30 | 31 | const ( 32 | DefaultCertExpiredDuration = time.Hour * 24 * 365 33 | DefaultCertOutdatedDuration = time.Hour * 24 * 30 34 | ) 35 | -------------------------------------------------------------------------------- /hooks/go/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" 21 | 22 | "github.com/deckhouse/module-sdk/pkg/app" 23 | _ "github.com/deckhouse/sds-replicated-volume/hooks/go/050-label-expiring-certs" 24 | _ "github.com/deckhouse/sds-replicated-volume/hooks/go/060-manual-cert-renewal" 25 | _ "github.com/deckhouse/sds-replicated-volume/hooks/go/070-generate-certs" 26 | ) 27 | 28 | func main() { 29 | app.Run() 30 | } 31 | -------------------------------------------------------------------------------- /hooks/go/tls-certificate/cert_helpers.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Flant JSC 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 tlscertificate 18 | 19 | import ( 20 | "fmt" 21 | "strings" 22 | ) 23 | 24 | const ( 25 | publicDomainPrefix = "%PUBLIC_DOMAIN%://" 26 | clusterDomainPrefix = "%CLUSTER_DOMAIN%://" 27 | ) 28 | 29 | // PublicDomainSAN create template to enrich specified san with a public domain 30 | func PublicDomainSAN(s string) string { 31 | return publicDomainPrefix + strings.TrimSuffix(s, ".") 32 | } 33 | 34 | // ClusterDomainSAN create template to enrich specified san with a cluster domain 35 | func ClusterDomainSAN(san string) string { 36 | return clusterDomainPrefix + strings.TrimSuffix(san, ".") 37 | } 38 | 39 | func getClusterDomainSAN(domain, sanValue string) string { 40 | sanValue = strings.TrimPrefix(sanValue, clusterDomainPrefix) 41 | 42 | return strings.Join([]string{sanValue, domain}, ".") 43 | } 44 | 45 | func getPublicDomainSAN(domainTemplate, sanValue string) string { 46 | sanValue = strings.TrimPrefix(sanValue, publicDomainPrefix) 47 | 48 | return fmt.Sprintf(domainTemplate, sanValue) 49 | } 50 | -------------------------------------------------------------------------------- /hooks/go/utils/certs.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 utils 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "strings" 23 | "time" 24 | 25 | v1 "k8s.io/api/core/v1" 26 | 27 | "github.com/deckhouse/module-sdk/pkg" 28 | "github.com/deckhouse/module-sdk/pkg/certificate" 29 | ) 30 | 31 | func AnyCertIsExpiringSoon( 32 | log pkg.Logger, 33 | secret *v1.Secret, 34 | durationLeft time.Duration, 35 | ) (bool, error) { 36 | var resultErr error 37 | 38 | log = log.With("name", secret.Name) 39 | 40 | for key, val := range secret.Data { 41 | keyLog := log.With("key", key) 42 | 43 | if !strings.HasSuffix(strings.ToLower(key), ".crt") { 44 | keyLog.Debug("not a certificate, skip") 45 | continue 46 | } 47 | 48 | if len(val) == 0 { 49 | keyLog.Debug("empty certificate, skip") 50 | continue 51 | } 52 | 53 | if expiring, err := certificate.IsCertificateExpiringSoon(val, durationLeft); err != nil { 54 | keyLog.Warn("error parsing certificate", "err", err) 55 | resultErr = errors.Join(resultErr, fmt.Errorf("error parsing certificate: %w", err)) 56 | } else if expiring { 57 | // drop errors as not relevant anymore 58 | return true, nil 59 | } 60 | } 61 | 62 | return false, resultErr 63 | } 64 | -------------------------------------------------------------------------------- /hooks/go/utils/iter.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 utils 18 | 19 | import ( 20 | "iter" 21 | ) 22 | 23 | func IterToKeys[K comparable](s iter.Seq[K]) iter.Seq2[K, struct{}] { 24 | return func(yield func(K, struct{}) bool) { 25 | for k := range s { 26 | if !yield(k, struct{}{}) { 27 | return 28 | } 29 | } 30 | } 31 | } 32 | 33 | func IterMap[T any, U any](src iter.Seq[T], f func(T) U) iter.Seq[U] { 34 | return func(yield func(U) bool) { 35 | for v := range src { 36 | if !yield(f(v)) { 37 | return 38 | } 39 | } 40 | } 41 | } 42 | 43 | func IterFilter[T any](s []T, p func(v T) bool) iter.Seq[T] { 44 | return func(yield func(T) bool) { 45 | for _, v := range s { 46 | if !p(v) { 47 | continue 48 | } 49 | if !yield(v) { 50 | return 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /hooks/go/utils/maps.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 utils 18 | 19 | func MapEnsureAndSet[K comparable, V any](m *map[K]V, key K, value V) { 20 | if m == nil { 21 | panic("can not add to nil") 22 | } 23 | if *m == nil { 24 | *m = make(map[K]V, 1) 25 | } 26 | (*m)[key] = value 27 | } 28 | -------------------------------------------------------------------------------- /hooks/go/utils/slices.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 utils 18 | 19 | import "iter" 20 | 21 | func SliceFind[T any](s []T, f func(v *T) bool) *T { 22 | for i := range s { 23 | if f(&s[i]) { 24 | return &s[i] 25 | } 26 | } 27 | return nil 28 | } 29 | 30 | func SliceFilter[T any](s []T, p func(v *T) bool) iter.Seq[*T] { 31 | return func(yield func(*T) bool) { 32 | for i := range s { 33 | if !p(&s[i]) { 34 | continue 35 | } 36 | if !yield(&s[i]) { 37 | return 38 | } 39 | } 40 | } 41 | } 42 | 43 | func SliceMap[T any, U any](s []T, f func(v *T) U) iter.Seq[U] { 44 | return func(yield func(U) bool) { 45 | for i := range s { 46 | if !yield(f(&s[i])) { 47 | return 48 | } 49 | } 50 | } 51 | } 52 | 53 | func SliceIndex[K comparable, V any](s []V, indexFn func(v *V) K) iter.Seq2[K, *V] { 54 | return func(yield func(K, *V) bool) { 55 | for i := range s { 56 | k := indexFn(&s[i]) 57 | if !yield(k, &s[i]) { 58 | return 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /hooks/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deckhouse/sds-replicated-volume/f2e65d667eadeea727930092e3fe21d20a492ef7/hooks/lib/__init__.py -------------------------------------------------------------------------------- /hooks/lib/hooks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deckhouse/sds-replicated-volume/f2e65d667eadeea727930092e3fe21d20a492ef7/hooks/lib/hooks/__init__.py -------------------------------------------------------------------------------- /hooks/lib/hooks/hook.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2023 Flant JSC 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 | from deckhouse import hook 17 | from typing import Callable 18 | from lib.module import module 19 | from lib.module import values as module_values 20 | import yaml 21 | 22 | class Hook: 23 | def __init__(self, module_name: str = None) -> None: 24 | self.module_name = self.get_module_name(module_name) 25 | 26 | def generate_config(self): 27 | pass 28 | 29 | @staticmethod 30 | def get_value(path: str, values: dict, default=None): 31 | return module_values.get_value(path, values, default) 32 | 33 | @staticmethod 34 | def set_value(path: str, values: dict, value: str) -> None: 35 | return module_values.set_value(path, values, value) 36 | 37 | @staticmethod 38 | def delete_value(path: str, values: dict) -> None: 39 | return module_values.delete_value(path, values) 40 | 41 | @staticmethod 42 | def get_module_name(module_name: str) -> str: 43 | if module_name is not None: 44 | return module_name 45 | return module.get_module_name() 46 | 47 | def reconcile(self) -> Callable[[hook.Context], None]: 48 | def r(ctx: hook.Context) -> None: 49 | pass 50 | return r 51 | 52 | def run(self) -> None: 53 | conf = self.generate_config() 54 | if isinstance(conf, dict): 55 | conf = yaml.dump(conf) 56 | hook.run(func=self.reconcile(), config=conf) 57 | -------------------------------------------------------------------------------- /hooks/lib/module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deckhouse/sds-replicated-volume/f2e65d667eadeea727930092e3fe21d20a492ef7/hooks/lib/module/__init__.py -------------------------------------------------------------------------------- /hooks/lib/module/module.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2023 Flant JSC 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 | from lib.module import values as module_values 17 | import re 18 | import os 19 | 20 | def get_values_first_defined(values: dict, *keys): 21 | return _get_first_defined(values, keys) 22 | 23 | def _get_first_defined(values: dict, keys: tuple): 24 | for i in range(len(keys)): 25 | if (val := module_values.get_value(path=keys[i], values=values)) is not None: 26 | return val 27 | return 28 | 29 | def get_https_mode(module_name: str, values: dict) -> str: 30 | module_path = f"{module_name}.https.mode" 31 | global_path = "global.modules.https.mode" 32 | https_mode = get_values_first_defined(values, module_path, global_path) 33 | if https_mode is not None: 34 | return str(https_mode) 35 | raise Exception("https mode is not defined") 36 | 37 | def get_module_name() -> str: 38 | return "sds-replicated-volume" 39 | -------------------------------------------------------------------------------- /hooks/lib/module/values.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2023 Flant JSC 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 | def get_value(path: str, values: dict, default=None): 17 | def get(keys: list, values: dict, default): 18 | if len(keys) == 1: 19 | if not isinstance(values, dict): 20 | return default 21 | return values.get(keys[0], default) 22 | if not isinstance(values, dict) or values.get(keys[0]) is None: 23 | return default 24 | if values.get(keys[0]) is None: 25 | return default 26 | return get(keys[1:], values[keys[0]], default) 27 | keys = path.lstrip(".").split(".") 28 | return get(keys, values, default) 29 | 30 | def set_value(path: str, values: dict, value) -> None: 31 | """ 32 | Functions for save value to dict. 33 | 34 | Example: 35 | path = "virtualization.internal.dvcr.cert" 36 | values = {"virtualization": {"internal": {}}} 37 | value = "{"ca": "ca", "crt"="tlscrt", "key"="tlskey"}" 38 | 39 | result values = {"virtualization": {"internal": {"dvcr": {"cert": {"ca": "ca", "crt":"tlscrt", "key":"tlskey"}}}}} 40 | """ 41 | def set(keys: list, values: dict, value): 42 | if len(keys) == 1: 43 | values[keys[0]] = value 44 | return 45 | if values.get(keys[0]) is None: 46 | values[keys[0]] = {} 47 | set(keys[1:], values[keys[0]], value) 48 | keys = path.lstrip(".").split(".") 49 | return set(keys, values, value) 50 | 51 | def delete_value(path: str, values: dict) -> None: 52 | if get_value(path, values) is None: 53 | return 54 | keys = path.lstrip(".").split(".") 55 | def delete(keys: list, values: dict) -> None: 56 | if len(keys) == 1: 57 | values.pop(keys[0]) 58 | return 59 | delete(keys[1:], values[keys[0]]) 60 | return delete(keys, values) -------------------------------------------------------------------------------- /hooks/lib/password_generator/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deckhouse/sds-replicated-volume/f2e65d667eadeea727930092e3fe21d20a492ef7/hooks/lib/password_generator/__init__.py -------------------------------------------------------------------------------- /hooks/lib/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deckhouse/sds-replicated-volume/f2e65d667eadeea727930092e3fe21d20a492ef7/hooks/lib/tests/__init__.py -------------------------------------------------------------------------------- /hooks/lib/tests/testing.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2023 Flant JSC 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 | from deckhouse import hook 17 | import unittest 18 | import jsonpatch 19 | import kubernetes_validate 20 | import jsonschema 21 | 22 | class TestHook(unittest.TestCase): 23 | kube_resources = [] 24 | kube_version = "1.28" 25 | def setUp(self): 26 | self.bindind_context = [] 27 | self.values = {} 28 | self.func = None 29 | 30 | def tearDown(self): 31 | pass 32 | 33 | def hook_run(self, validate_kube_resources: bool = True) -> None: 34 | out = hook.testrun(func=self.func, 35 | binding_context=self.bindind_context, 36 | initial_values=self.values) 37 | for patch in out.values_patches.data: 38 | self.values = jsonpatch.apply_patch(self.values, [patch]) 39 | 40 | deletes = ("Delete", "DeleteInBackground", "DeleteNonCascading") 41 | for kube_operation in out.kube_operations.data: 42 | if kube_operation["operation"] in deletes: 43 | continue 44 | obj = kube_operation["object"] 45 | if validate_kube_resources: 46 | try: 47 | ## TODO Validate CRD 48 | kubernetes_validate.validate(obj, self.kube_version, strict=True) 49 | self.kube_resources.append(obj) 50 | except (kubernetes_validate.SchemaNotFoundError, 51 | kubernetes_validate.InvalidSchemaError, 52 | kubernetes_validate.ValidationError, 53 | jsonschema.RefResolutionError) as e: 54 | self.fail(f"Object is not valid. Raised an exception: {e} ") 55 | else: 56 | self.kube_resources.append(obj) 57 | 58 | -------------------------------------------------------------------------------- /hooks/lib/utils.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2023 Flant JSC 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 | import base64 17 | import os 18 | import json 19 | 20 | def base64_encode(b: bytes) -> str: 21 | return str(base64.b64encode(b), encoding='utf-8') 22 | 23 | def base64_decode(s: str) -> str: 24 | return str(base64.b64decode(s), encoding="utf-8") 25 | 26 | def base64_encode_from_str(s: str) -> str: 27 | return base64_encode(bytes(s, 'utf-8')) 28 | 29 | def json_load(path: str): 30 | with open(path, "r", encoding="utf-8") as f: 31 | data = json.load(f) 32 | return data 33 | 34 | def get_dir_path() -> str: 35 | return os.path.dirname(os.path.abspath(__file__)) 36 | 37 | def is_base64(s): 38 | try: 39 | base64_decode(s) 40 | return True 41 | except base64.binascii.Error: 42 | return False 43 | 44 | def check_elem_in_list(l: list, elem) -> bool: 45 | for i in l: 46 | if i == elem: 47 | return True 48 | return False 49 | 50 | def find_index_in_list(l: list, elem) -> int: 51 | for i in range(len(l)): 52 | if l[i] == elem: 53 | return i 54 | return -------------------------------------------------------------------------------- /images/drbd-reactor/patches/001-fix-drbd-reactor-spec.patch: -------------------------------------------------------------------------------- 1 | diff --git a/drbd-reactor.spec b/drbd-reactor.spec 2 | index d3bd88c..fc2e1c4 100644 3 | --- a/drbd-reactor.spec 4 | +++ b/drbd-reactor.spec 5 | @@ -11,7 +11,6 @@ License: ASL 2.0 6 | URL: https://www.github.com/LINBIT/drbd-reactor 7 | Source0: https://pkg.linbit.com/downloads/drbd/utils/%{name}-%{tarball_version}.tar.gz 8 | 9 | -BuildRequires: systemd 10 | # While most pkgs I looked at have bash-completion as BuildRequires, I don't think we need it 11 | # looks like it would only help for cmake or pkgconfig projects. 12 | # BuildRequires: bash-completion 13 | -------------------------------------------------------------------------------- /images/drbd-reactor/patches/Readme.md: -------------------------------------------------------------------------------- 1 | # Patches 2 | 3 | ## fix-drbd-reactor-spec.patch 4 | 5 | Remove systemd build-requirement because ALTLinux is based on SysV, not Systemd. 6 | -------------------------------------------------------------------------------- /images/drbd/scripts/install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2023 Flant JSC 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 | rm -rf /opt/deckhouse/drbd 17 | cp -r drbd /opt/deckhouse/ 18 | -------------------------------------------------------------------------------- /images/drbd/scripts/uninstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2023 Flant JSC 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 | rm -rf /opt/deckhouse/drbd 17 | -------------------------------------------------------------------------------- /images/drbd/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: {{ $.ImageName }}-artifact 3 | fromImage: builder/alt 4 | final: false 5 | git: 6 | - add: /images/{{ $.ImageName }}/scripts 7 | to: /scripts 8 | stageDependencies: 9 | beforeSetup: 10 | - "**/*" 11 | shell: 12 | beforeInstall: 13 | - export DEBIAN_FRONTEND=noninteractive 14 | - | 15 | apt-get update \ 16 | && apt-get -y install {{ $.Root.BUILD_PACKAGES }} \ 17 | && apt-get -y install ca-certificates \ 18 | && update-ca-trust 19 | - {{ $.Root.ALT_CLEANUP_CMD }} 20 | - git config --global user.email "builder@deckhouse.io" 21 | - git config --global user.name "deckhouse" 22 | install: 23 | {{- $ctx := dict }} 24 | {{- include "utils:prepare-rpm-build" $ctx | nindent 2 }} 25 | beforeSetup: 26 | - mv /scripts/* / 27 | - chmod +x /install 28 | - chmod +x /uninstall 29 | setup: 30 | - git clone --depth 1 --branch drbd-{{ $.Versions.DRBD }} {{ $.Root.SOURCE_REPO }}/LINBIT/drbd.git /drbd 31 | - cd /drbd 32 | - git submodule update --init --recursive 33 | - sed -e "s/\/d8-curl -k/g" -i /drbd/drbd/drbd-kernel-compat/gen_compat_patch.sh 34 | - git commit -am 'd8-curl' 35 | # tarball required by spaas image 36 | - make tarball 37 | # disable use of local spatch (see /drbd/drbd/drbd-kernel-compat/gen_compat_patch.sh) 38 | - rm -rf .git 39 | --- 40 | image: {{ $.ImageName }} 41 | fromImage: base/distroless 42 | 43 | import: 44 | - image: {{ $.ImageName }}-artifact 45 | add: / 46 | to: / 47 | includePaths: 48 | - drbd 49 | - install 50 | - uninstall 51 | before: setup 52 | docker: 53 | LABEL: 54 | distro: all 55 | version: all 56 | drbd: {{ $.Versions.DRBD }} 57 | -------------------------------------------------------------------------------- /images/go-hooks/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: {{ $.ImageName }}-artifact 3 | fromImage: builder/golang-alpine 4 | final: false 5 | 6 | git: 7 | - add: /hooks/go 8 | to: /usr/src/app/hooks/go 9 | stageDependencies: 10 | install: 11 | - '**/go.mod' 12 | - '**/go.sum' 13 | beforeSetup: 14 | - '**/*.go' 15 | - add: /api 16 | to: /usr/src/app/api 17 | stageDependencies: 18 | install: 19 | - '**/go.mod' 20 | - '**/go.sum' 21 | beforeSetup: 22 | - '**/*.go' 23 | 24 | mount: 25 | - fromPath: ~/go-pkg-cache 26 | to: /go/pkg 27 | 28 | shell: 29 | install: 30 | - cd /usr/src/app/hooks/go 31 | - go mod download 32 | beforeSetup: 33 | - | 34 | cd /usr/src/app/hooks/go; 35 | CGO_ENABLED=0 go build -a -gcflags=all="-l -B" -ldflags="-w -s" -o /usr/local/bin/go-hooks *.go; -------------------------------------------------------------------------------- /images/linstor-affinity-controller/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: {{ $.ImageName }}-golang-artifact 3 | from: {{ $.Root.BASE_GOLANG_1_22 }} 4 | final: false 5 | 6 | git: 7 | - url: https://github.com/piraeusdatastore/linstor-affinity-controller 8 | add: / 9 | to: /usr/local/go/{{ $.ImageName }} 10 | tag: v{{ $.Versions.LINSTOR_AFFINITY_CONTROLLER }} 11 | stageDependencies: 12 | setup: 13 | - "**/*" 14 | mount: 15 | - fromPath: ~/go-pkg-cache 16 | to: /go/pkg 17 | shell: 18 | setup: 19 | - cd /usr/local/go/{{ $.ImageName }}/cmd/linstor-affinity-controller 20 | - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w -X github.com/piraeusdatastore/linstor-affinity-controller/pkg/consts.Version=v{{ $.Versions.LINSTOR_AFFINITY_CONTROLLER }}" 21 | - mv {{ $.ImageName }} / 22 | - chmod +x /{{ $.ImageName }} 23 | --- 24 | image: {{ $.ImageName }} 25 | from: {{ $.Root.BASE_SCRATCH }} 26 | 27 | import: 28 | - image: {{ $.ImageName }}-golang-artifact 29 | add: /{{ $.ImageName }} 30 | to: /{{ $.ImageName }} 31 | before: setup 32 | 33 | docker: 34 | ENTRYPOINT: ["/{{ $.ImageName }}"] 35 | LABEL: 36 | distro: all 37 | version: all 38 | linstor-affinity-controller: {{ $.Versions.LINSTOR_AFFINITY_CONTROLLER }} 39 | -------------------------------------------------------------------------------- /images/linstor-csi/patches/001-requisites.patch: -------------------------------------------------------------------------------- 1 | diff --git a/pkg/linstor/highlevelclient/high_level_client.go b/pkg/linstor/highlevelclient/high_level_client.go 2 | index 645599c..2f7c3f9 100644 3 | --- a/pkg/linstor/highlevelclient/high_level_client.go 4 | +++ b/pkg/linstor/highlevelclient/high_level_client.go 5 | @@ -27,7 +27,6 @@ import ( 6 | "github.com/container-storage-interface/spec/lib/go/csi" 7 | 8 | "github.com/piraeusdatastore/linstor-csi/pkg/linstor/util" 9 | - "github.com/piraeusdatastore/linstor-csi/pkg/slice" 10 | "github.com/piraeusdatastore/linstor-csi/pkg/topology" 11 | "github.com/piraeusdatastore/linstor-csi/pkg/volume" 12 | ) 13 | @@ -104,18 +103,8 @@ func (c *HighLevelClient) GetAllTopologyNodes(ctx context.Context, remoteAccessP 14 | accessibleSegments = []map[string]string{{}} 15 | } 16 | 17 | - var allNodes []string 18 | - 19 | - for _, segment := range accessibleSegments { 20 | - nodes, err := c.NodesForTopology(ctx, segment) 21 | - if err != nil { 22 | - return nil, err 23 | - } 24 | - 25 | - allNodes = slice.AppendUnique(allNodes, nodes...) 26 | - } 27 | - 28 | - return allNodes, nil 29 | + // schedulded node of the pod is the first entry in the accessible segment 30 | + return c.NodesForTopology(ctx, accessibleSegments[0]) 31 | } 32 | 33 | // NodesForTopology finds all matching nodes for the given topology segment. 34 | -------------------------------------------------------------------------------- /images/linstor-csi/patches/002-rename-linbit-labels.patch: -------------------------------------------------------------------------------- 1 | From 110038fac54abe8f9d097d540c185a2a25eebb01 Mon Sep 17 00:00:00 2001 2 | From: Viktor Kramarenko 3 | Date: Tue, 16 Apr 2024 14:33:47 +0300 4 | Subject: [PATCH] Changed LinstorNodeKey and LinstorStoragePoolKeyPrefix 5 | consts. Signed-off-by: Viktor Kramarenko 6 | 7 | --- 8 | pkg/topology/topology.go | 4 ++-- 9 | 1 file changed, 2 insertions(+), 2 deletions(-) 10 | 11 | diff --git a/pkg/topology/topology.go b/pkg/topology/topology.go 12 | index c50d012..6dd92c5 100644 13 | --- a/pkg/topology/topology.go 14 | +++ b/pkg/topology/topology.go 15 | @@ -47,11 +47,11 @@ const ( 16 | const ( 17 | // LinstorNodeKey refers to a node running the LINSTOR csi node service 18 | // and the linstor Satellite and is therefore capable of hosting LINSTOR volumes. 19 | - LinstorNodeKey = "linbit.com/hostname" 20 | + LinstorNodeKey = "storage.deckhouse.io/sds-replicated-volume-hostname" 21 | 22 | // LinstorStoragePoolKeyPrefix is the prefix used when specifying the available storage 23 | // pools on a node via CSI topology keys. 24 | - LinstorStoragePoolKeyPrefix = "linbit.com/sp-" 25 | + LinstorStoragePoolKeyPrefix = "storage.deckhouse.io/sds-replicated-volume-sp-" 26 | 27 | // LinstorStoragePoolValue is the value assigned to the storage pool label, given that the node has access to the 28 | // storage pool. 29 | -- 30 | 2.39.3 (Apple Git-145) 31 | 32 | -------------------------------------------------------------------------------- /images/linstor-csi/patches/003-new-csi-path.patch: -------------------------------------------------------------------------------- 1 | diff --git a/cmd/linstor-csi/linstor-csi.go b/cmd/linstor-csi/linstor-csi.go 2 | index 20b09f5..8dac370 100644 3 | --- a/cmd/linstor-csi/linstor-csi.go 4 | +++ b/cmd/linstor-csi/linstor-csi.go 5 | @@ -40,7 +40,7 @@ func main() { 6 | var ( 7 | lsEndpoint = flag.String("linstor-endpoint", "", "Controller API endpoint for LINSTOR") 8 | lsSkipTLSVerification = flag.Bool("linstor-skip-tls-verification", false, "If true, do not verify tls") 9 | - csiEndpoint = flag.String("csi-endpoint", "unix:///var/lib/kubelet/plugins/linstor.csi.linbit.com/csi.sock", "CSI endpoint") 10 | + csiEndpoint = flag.String("csi-endpoint", "unix:///var/lib/kubelet/plugins/replicated.csi.storage.deckhouse.io/csi.sock", "CSI endpoint") 11 | node = flag.String("node", "", "Node ID to pass to node service") 12 | logLevel = flag.String("log-level", "info", "Enable debug log output. Choose from: panic, fatal, error, warn, info, debug") 13 | rps = flag.Float64("linstor-api-requests-per-second", 0, "Maximum allowed number of LINSTOR API requests per second. Default: Unlimited") 14 | diff --git a/pkg/linstor/const.go b/pkg/linstor/const.go 15 | index 8b732ec..d18e968 100644 16 | --- a/pkg/linstor/const.go 17 | +++ b/pkg/linstor/const.go 18 | @@ -24,7 +24,7 @@ import ( 19 | 20 | const ( 21 | // DriverName is the name used in CSI calls for this driver. 22 | - DriverName = "linstor.csi.linbit.com" 23 | + DriverName = "replicated.csi.storage.deckhouse.io" 24 | 25 | // LegacyParameterPassKey is the Aux props key in linstor where serialized CSI parameters 26 | // are stored. 27 | -------------------------------------------------------------------------------- /images/linstor-csi/patches/README.md: -------------------------------------------------------------------------------- 1 | ## Patches 2 | 3 | ### 001-requisites.patch 4 | 5 | Fix multiple requisites 6 | 7 | Sometimes Kubernetes may request multiple requisites in topology in CreateVolume request. 8 | This patch considers just the first one as the requested node. 9 | 10 | - https://github.com/piraeusdatastore/linstor-csi/pull/196 11 | 12 | ### 002-rename-linbit-labels.patch 13 | 14 | Rename linbit labels 15 | 16 | This patch renames following Linstor-csi-node labels: - linbit.com/hostname -> storage.deckhouse.io/sds-replicated-volume-hostname - linbit.com/sp-> storage.deckhouse.io/sds-replicated-volume-sp- 17 | 18 | ### 003-new-csi-path.patch 19 | 20 | Change csi endpoint 21 | 22 | Change csi endpoint from `linstor.csi.linbit.com` to `replicated.csi.storage.deckhouse.io`. 23 | 24 | ### 004-csi-add-new-topology-logic.patch 25 | 26 | Add new topology logic 27 | -------------------------------------------------------------------------------- /images/linstor-drbd-wait/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/sds-replicated-volume/images/linstor-drbd-wait 2 | 3 | go 1.23.6 4 | 5 | require ( 6 | github.com/go-logr/logr v1.4.2 7 | k8s.io/klog/v2 v2.130.1 8 | ) 9 | -------------------------------------------------------------------------------- /images/linstor-drbd-wait/go.sum: -------------------------------------------------------------------------------- 1 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= 2 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 3 | k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= 4 | k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= 5 | -------------------------------------------------------------------------------- /images/linstor-drbd-wait/pkg/logger/logger.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 logger 18 | 19 | import ( 20 | "fmt" 21 | "strconv" 22 | 23 | "github.com/go-logr/logr" 24 | "k8s.io/klog/v2/textlogger" 25 | ) 26 | 27 | const ( 28 | ErrorLevel Verbosity = "0" 29 | WarningLevel Verbosity = "1" 30 | InfoLevel Verbosity = "2" 31 | DebugLevel Verbosity = "3" 32 | TraceLevel Verbosity = "4" 33 | ) 34 | 35 | const ( 36 | warnLvl = iota + 1 37 | infoLvl 38 | debugLvl 39 | traceLvl 40 | ) 41 | 42 | type ( 43 | Verbosity string 44 | ) 45 | 46 | type Logger struct { 47 | log logr.Logger 48 | } 49 | 50 | func NewLogger(level Verbosity) (*Logger, error) { 51 | v, err := strconv.Atoi(string(level)) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | log := textlogger.NewLogger(textlogger.NewConfig(textlogger.Verbosity(v))).WithCallDepth(1) 57 | 58 | return &Logger{log: log}, nil 59 | } 60 | 61 | func (l Logger) GetLogger() logr.Logger { 62 | return l.log 63 | } 64 | 65 | func (l Logger) Error(err error, message string, keysAndValues ...interface{}) { 66 | l.log.Error(err, fmt.Sprintf("ERROR %s", message), keysAndValues...) 67 | } 68 | 69 | func (l Logger) Warning(message string, keysAndValues ...interface{}) { 70 | l.log.V(warnLvl).Info(fmt.Sprintf("WARNING %s", message), keysAndValues...) 71 | } 72 | 73 | func (l Logger) Info(message string, keysAndValues ...interface{}) { 74 | l.log.V(infoLvl).Info(fmt.Sprintf("INFO %s", message), keysAndValues...) 75 | } 76 | 77 | func (l Logger) Debug(message string, keysAndValues ...interface{}) { 78 | l.log.V(debugLvl).Info(fmt.Sprintf("DEBUG %s", message), keysAndValues...) 79 | } 80 | 81 | func (l Logger) Trace(message string, keysAndValues ...interface{}) { 82 | l.log.V(traceLvl).Info(fmt.Sprintf("TRACE %s", message), keysAndValues...) 83 | } 84 | 85 | func (l *Logger) Printf(format string, args ...interface{}) { 86 | l.log.V(traceLvl).Info("%s", fmt.Sprintf(format, args...)) 87 | } 88 | -------------------------------------------------------------------------------- /images/linstor-drbd-wait/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: {{ $.ImageName }}-src-artifact 3 | from: {{ $.Root.BASE_ALT_P11 }} 4 | final: false 5 | 6 | git: 7 | - add: / 8 | to: /src 9 | includePaths: 10 | - api 11 | - images/{{ $.ImageName }} 12 | stageDependencies: 13 | install: 14 | - '**/*' 15 | excludePaths: 16 | - images/{{ $.ImageName }}/werf.yaml 17 | 18 | shell: 19 | install: 20 | - echo "src artifact" 21 | 22 | --- 23 | image: {{ $.ImageName }}-golang-artifact 24 | from: {{ $.Root.BASE_GOLANG_1_23 }} 25 | final: false 26 | 27 | import: 28 | - image: {{ $.ImageName }}-src-artifact 29 | add: /src 30 | to: /src 31 | before: install 32 | 33 | mount: 34 | - fromPath: ~/go-pkg-cache 35 | to: /go/pkg 36 | 37 | shell: 38 | setup: 39 | - cd /src/images/{{ $.ImageName }}/cmd 40 | - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" -o /{{ $.ImageName }} 41 | - chmod +x /{{ $.ImageName }} 42 | 43 | --- 44 | image: {{ $.ImageName }}-distroless-artifact 45 | from: {{ $.Root.BASE_ALT }} 46 | final: false 47 | shell: 48 | beforeInstall: 49 | - apt-get update 50 | - apt-get install -y {{ $.Root.ALT_BASE_PACKAGES }} 51 | - rm -rf /var/lib/apt/lists/* /var/cache/apt/* && mkdir -p /var/lib/apt/lists/partial /var/cache/apt/archives/partial 52 | install: 53 | - mkdir -p /relocate/bin /relocate/sbin /relocate/etc /relocate/var/lib/ssl /relocate/usr/bin /relocate/usr/sbin /relocate/usr/share 54 | - cp -pr /tmp /relocate 55 | - cp -pr /etc/passwd /etc/group /etc/hostname /etc/hosts /etc/shadow /etc/protocols /etc/services /etc/nsswitch.conf /etc/netconfig /relocate/etc 56 | - cp -pr /usr/share/ca-certificates /relocate/usr/share 57 | - cp -pr /usr/share/zoneinfo /relocate/usr/share 58 | - cp -pr /var/lib/ssl/cert.pem /relocate/var/lib/ssl 59 | - cp -pr /var/lib/ssl/certs /relocate/var/lib/ssl 60 | - echo "deckhouse:x:64535:64535:deckhouse:/:/sbin/nologin" >> /relocate/etc/passwd 61 | - echo "deckhouse:x:64535:" >> /relocate/etc/group 62 | - echo "deckhouse:!::0:::::" >> /relocate/etc/shadow 63 | 64 | --- 65 | image: {{ $.ImageName }}-distroless 66 | from: {{ $.Root.BASE_SCRATCH }} 67 | final: false 68 | import: 69 | - image: {{ $.ImageName }}-distroless-artifact 70 | add: /relocate 71 | to: / 72 | before: setup 73 | 74 | --- 75 | image: {{ $.ImageName }} 76 | fromImage: {{ $.ImageName }}-distroless 77 | 78 | import: 79 | - image: {{ $.ImageName }}-golang-artifact 80 | add: /{{ $.ImageName }} 81 | to: /{{ $.ImageName }} 82 | before: setup 83 | 84 | docker: 85 | ENTRYPOINT: ["/{{ $.ImageName }}"] 86 | USER: deckhouse:deckhouse 87 | -------------------------------------------------------------------------------- /images/linstor-scheduler-admission/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | image: {{ $.ImageName }}-golang-artifact 4 | from: {{ $.Root.BASE_GOLANG_1_22 }} 5 | final: false 6 | 7 | git: 8 | - url: https://github.com/piraeusdatastore/linstor-scheduler-extender 9 | add: / 10 | to: /usr/local/go/{{ $.ImageName }} 11 | tag: v{{ $.Versions.LINSTOR_SCHEDULER_EXTENDER }} 12 | stageDependencies: 13 | setup: 14 | - "**/*" 15 | mount: 16 | - fromPath: ~/go-pkg-cache 17 | to: /go/pkg 18 | shell: 19 | setup: 20 | - cd /usr/local/go/{{ $.ImageName }}/cmd/linstor-scheduler-admission 21 | - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w -X github.com/piraeusdatastore/linstor-scheduler-extender/pkg/consts.Version=v{{ $.Versions.LINSTOR_SCHEDULER_EXTENDER }}" 22 | - mv {{ $.ImageName }} / 23 | - chmod +x /{{ $.ImageName }} 24 | --- 25 | image: {{ $.ImageName }} 26 | from: {{ $.Root.BASE_SCRATCH }} 27 | 28 | import: 29 | - image: {{ $.ImageName }}-golang-artifact 30 | add: /{{ $.ImageName }} 31 | to: /{{ $.ImageName }} 32 | before: setup 33 | 34 | docker: 35 | ENTRYPOINT: ["/{{ $.ImageName }}"] 36 | LABEL: 37 | distro: all 38 | version: all 39 | linstor-scheduler-admission: {{ $.Versions.LINSTOR_SCHEDULER_EXTENDER }} 40 | -------------------------------------------------------------------------------- /images/linstor-scheduler-extender/patches/001-linstor-scheduler-extender.patch: -------------------------------------------------------------------------------- 1 | diff --git a/cmd/linstor-scheduler-extender/linstor-scheduler-extender.go b/cmd/linstor-scheduler-extender/linstor-scheduler-extender.go 2 | index 9f61882..0f53cf1 100644 3 | --- a/cmd/linstor-scheduler-extender/linstor-scheduler-extender.go 4 | +++ b/cmd/linstor-scheduler-extender/linstor-scheduler-extender.go 5 | @@ -24,6 +24,11 @@ import ( 6 | _ "github.com/piraeusdatastore/linstor-scheduler-extender/pkg/driver" 7 | ) 8 | 9 | +const ( 10 | + defaultCertFile string = "/etc/sds-replicated-volume-scheduler-extender/certs/tls.crt" 11 | + defaultKeyFile string = "/etc/sds-replicated-volume-scheduler-extender/certs/tls.key" 12 | +) 13 | + 14 | var ext *extender.Extender 15 | 16 | func main() { 17 | @@ -88,19 +93,24 @@ func run(c *cli.Context) { 18 | log.Fatalf("Error initializing Scheduler Driver %v: %v", "linstor", err) 19 | } 20 | 21 | + // Create operator-sdk manager that will manage all controllers. 22 | + mgr, err := manager.New(config, manager.Options{}) 23 | + if err != nil { 24 | + log.Fatalf("Setup controller manager: %v", err) 25 | + } 26 | + 27 | ext = &extender.Extender{ 28 | Driver: d, 29 | Recorder: recorder, 30 | + CertFile: defaultCertFile, 31 | + KeyFile: defaultKeyFile, 32 | + LogLevel: log.GetLevel(), 33 | + Manager: &mgr, 34 | } 35 | 36 | if err = ext.Start(); err != nil { 37 | log.Fatalf("Error starting scheduler extender: %v", err) 38 | } 39 | - // Create operator-sdk manager that will manage all controllers. 40 | - mgr, err := manager.New(config, manager.Options{}) 41 | - if err != nil { 42 | - log.Fatalf("Setup controller manager: %v", err) 43 | - } 44 | 45 | signalChan := make(chan os.Signal, 1) 46 | signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) 47 | -------------------------------------------------------------------------------- /images/linstor-scheduler-extender/patches/README.md: -------------------------------------------------------------------------------- 1 | ## Patches 2 | 3 | ### 001-linstor-scheduler-extender.patch 4 | 5 | Scheduler extender 6 | 7 | Extend scheduler with HTTPS support and our own logic. 8 | -------------------------------------------------------------------------------- /images/linstor-scheduler-extender/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: {{ $.ImageName }}-golang-artifact 3 | from: {{ $.Root.BASE_GOLANG_1_22 }} 4 | final: false 5 | 6 | git: 7 | - url: https://github.com/piraeusdatastore/linstor-scheduler-extender 8 | add: / 9 | to: /usr/local/go/{{ $.ImageName }} 10 | tag: v{{ $.Versions.LINSTOR_SCHEDULER_EXTENDER }} 11 | stageDependencies: 12 | setup: 13 | - "**/*" 14 | 15 | - url: https://github.com/libopenstorage/stork 16 | add: / 17 | to: /usr/local/go/stork 18 | tag: v{{ $.Versions.LINSTOR_SCHEDULER_STORK }} 19 | stageDependencies: 20 | beforeSetup: 21 | - "**/*" 22 | setup: 23 | - "**/*" 24 | 25 | - add: /images/{{ $.ImageName }}/patches 26 | to: /patches 27 | stageDependencies: 28 | beforeSetup: 29 | - "**/*" 30 | setup: 31 | - "**/*" 32 | 33 | mount: 34 | - fromPath: ~/go-pkg-cache 35 | to: /go/pkg 36 | shell: 37 | beforeSetup: 38 | - cd /usr/local/go/stork 39 | - '[ -d "/patches/stork/new-files" ] && cp -frp /patches/stork/new-files/* /usr/local/go/stork/' 40 | - git apply /patches/stork/*.patch 41 | 42 | setup: 43 | - cd /usr/local/go/{{ $.ImageName }} 44 | - git apply /patches/*.patch 45 | - go mod edit -replace=github.com/libopenstorage/stork=/usr/local/go/stork 46 | - go mod tidy 47 | - cd cmd/linstor-scheduler-extender 48 | - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w -X github.com/piraeusdatastore/linstor-scheduler-extender/pkg/consts.Version=v{{ $.Versions.LINSTOR_SCHEDULER_EXTENDER }}" 49 | - mv {{ $.ImageName }} / 50 | - chmod +x /{{ $.ImageName }} 51 | --- 52 | image: {{ $.ImageName }} 53 | from: {{ $.Root.BASE_SCRATCH }} 54 | 55 | import: 56 | - image: {{ $.ImageName }}-golang-artifact 57 | add: /{{ $.ImageName }} 58 | to: /{{ $.ImageName }} 59 | before: setup 60 | 61 | docker: 62 | ENTRYPOINT: ["/{{ $.ImageName }}"] 63 | LABEL: 64 | distro: all 65 | version: all 66 | linstor-scheduler-extender: {{ $.Versions.LINSTOR_SCHEDULER_EXTENDER }} 67 | -------------------------------------------------------------------------------- /images/linstor-server/liveness-satellite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright 2024 Flant JSC 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 | # Sometimes nodes can be shown as Online without established connection to them. 18 | # This is a workaround for https://github.com/LINBIT/linstor-server/issues/331, https://github.com/LINBIT/linstor-server/issues/219 19 | 20 | # Check if there are symptoms of lost connection in linstor controller logs 21 | if test -f "/var/log/linstor-satellite/linstor-Satellite.log"; then 22 | if [ $(tail -n 1000 /var/log/linstor-satellite/linstor-Satellite.log | grep 'Target decrypted buffer is too small' | wc -l) -ne 0 ]; then 23 | exit 1 24 | fi 25 | fi 26 | 27 | # Because shell keeps last exit code, we must force exit with code 0. If not, we will have exit code 1 because of grep, that not founded anything 28 | exit 0 29 | -------------------------------------------------------------------------------- /images/linstor-server/liveness.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright 2023 Flant JSC 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 | # This is default linstor controller liveness probe 18 | if ! curl --connect-timeout 3 -sf http://localhost:9999/ > /dev/null; then 19 | exit 1; 20 | fi 21 | 22 | # Sometimes nodes can be shown as Online without established connection to them. 23 | # This is a workaround for https://github.com/LINBIT/linstor-server/issues/331, https://github.com/LINBIT/linstor-server/issues/219 24 | 25 | # Collect list of satellite nodes 26 | SATELLITES_ONLINE=$(linstor -m --output-version=v1 node list | jq -r '.[][] | select(.type == "SATELLITE" and .connection_status == "ONLINE").name') 27 | if [ -z "$SATELLITES_ONLINE" ]; then 28 | exit 0 29 | fi 30 | 31 | # Check online nodes with lost connection 32 | if [ $(linstor -m --output-version=v1 storage-pool list -s DfltDisklessStorPool -n $SATELLITES_ONLINE | jq '.[][].reports[]?.message' | grep 'No active connection to satellite' | wc -l) -ne 0 ]; then 33 | exit 1 34 | fi 35 | 36 | # Check if there are symptoms of lost connection in linstor controller logs 37 | if test -f "/var/log/linstor-controller/linstor-Controller.log"; then 38 | if [ $(tail -n 1000 /var/log/linstor-controller/linstor-Controller.log | grep 'Target decrypted buffer is too small' | wc -l) -ne 0 ]; then 39 | exit 1 40 | fi 41 | fi 42 | 43 | # Because shell keeps last exit code, we must force exit with code 0. If not, we will have exit code 1 because of grep, that not founded anything 44 | exit 0 45 | -------------------------------------------------------------------------------- /images/linstor-server/patches/001-fix-linstor-spec.patch: -------------------------------------------------------------------------------- 1 | diff --git a/linstor.spec b/linstor.spec 2 | index f94f0e523..cf465ae86 100644 3 | --- a/linstor.spec 4 | +++ b/linstor.spec 5 | @@ -23,11 +23,7 @@ BuildRequires: java-11-openjdk-headless java-11-openjdk-devel python 6 | %define GRADLE_J11_PATH -Pjava11=lib64 7 | %else 8 | %define GRADLE_J11_PATH -Pjava11=lib 9 | - %if 0%{?rhel} > 8 10 | BuildRequires: java-11-openjdk-headless java-11-openjdk-devel python3 11 | - %else 12 | -BuildRequires: java-11-openjdk-headless java-11-openjdk-devel python2 13 | - %endif 14 | %endif 15 | 16 | %description 17 | @@ -74,6 +70,7 @@ cp %{_builddir}/%{NAME_VERS}/docs/linstor.toml-example %{buildroot}/%{_sysconfdi 18 | ### common 19 | %package common 20 | Summary: Common files shared between controller and satellite 21 | +Group: System Environment/Daemons 22 | Requires: jre-11-headless 23 | ## This should really be included in the jre-headless dependencies, but it isn't. 24 | Requires: tzdata-java 25 | @@ -93,6 +90,7 @@ Linstor shared components between linstor-controller and linstor-satellite 26 | ### controller 27 | %package controller 28 | Summary: Linstor controller specific files 29 | +Group: System Environment/Daemons 30 | Requires: linstor-common = %{version} 31 | Requires(post): jre-11-headless 32 | 33 | @@ -113,7 +111,7 @@ Linstor controller manages linstor satellites and persistant data storage. 34 | %{FIREWALLD_SERVICES}/linstor-controller.xml 35 | %{_sysconfdir}/linstor/linstor.toml-example 36 | 37 | -%posttrans controller 38 | +%post controller 39 | %{LS_PREFIX}/bin/controller.postinst.sh 40 | %systemd_post linstor-controller.service 41 | test -f %{_bindir}/firewall-cmd && firewall-cmd --reload --quiet || : 42 | @@ -124,6 +122,7 @@ test -f %{_bindir}/firewall-cmd && firewall-cmd --reload --quiet || : 43 | ### satellite 44 | %package satellite 45 | Summary: Linstor satellite specific files 46 | +Group: System Environment/Daemons 47 | Requires: linstor-common = %{version} 48 | Requires: lvm2 49 | 50 | -------------------------------------------------------------------------------- /images/linstor-server/patches/README.md: -------------------------------------------------------------------------------- 1 | ## Patches 2 | 3 | ### 001-fix-linstor-spec.patch 4 | 5 | Fix linstor.spec 6 | 7 | Fixes error 'error: Group field must be present in package: linstor-common' when building RPM package (for ALT Linux) 8 | 9 | ### 002-fix-symlinks.patch 10 | 11 | Automatically fix symlinks for devices 12 | 13 | This change is workaround for specific set of issues, often related to udev, 14 | which lead to the disappearance of symlinks for LVM devices on a working system. 15 | These issues commonly manifest during device resizing and deactivation, 16 | causing LINSTOR exceptions when accessing DRBD super-block of volume. 17 | 18 | - Upstream: https://github.com/LINBIT/linstor-server/pull/370 19 | -------------------------------------------------------------------------------- /images/linstor-wait-until/patches/README.md: -------------------------------------------------------------------------------- 1 | ## Patches 2 | 3 | ### 001-log.patch 4 | 5 | Log 6 | 7 | This patches changes logrus library to klog, for redirect logs to containers output 8 | -------------------------------------------------------------------------------- /images/linstor-wait-until/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: {{ $.ImageName }}-golang-artifact 3 | from: {{ $.Root.BASE_GOLANG_1_22 }} 4 | final: false 5 | 6 | git: 7 | - url: https://github.com/LINBIT/linstor-wait-until 8 | add: / 9 | to: /usr/local/go/{{ $.ImageName }} 10 | tag: v{{ $.Versions.LINSTOR_WAIT_UNTIL }} 11 | stageDependencies: 12 | setup: 13 | - "**/*" 14 | 15 | - add: /images/{{ $.ImageName }}/patches 16 | to: /patches 17 | stageDependencies: 18 | beforeSetup: 19 | - "**/*" 20 | setup: 21 | - "**/*" 22 | 23 | mount: 24 | - fromPath: ~/go-pkg-cache 25 | to: /go/pkg 26 | shell: 27 | setup: 28 | - cd /usr/local/go/{{ $.ImageName }} 29 | - git apply /patches/*.patch 30 | - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" 31 | - mv {{ $.ImageName }} / 32 | - chmod +x /{{ $.ImageName }} 33 | --- 34 | image: {{ $.ImageName }} 35 | fromImage: base/distroless 36 | 37 | import: 38 | - image: {{ $.ImageName }}-golang-artifact 39 | add: /{{ $.ImageName }} 40 | to: /{{ $.ImageName }} 41 | before: setup 42 | 43 | docker: 44 | ENTRYPOINT: ["/{{ $.ImageName }}"] 45 | LABEL: 46 | distro: all 47 | version: all 48 | linstor-wait-until: {{ $.Versions.LINSTOR_WAIT_UNTIL }} 49 | -------------------------------------------------------------------------------- /images/metadata-backup/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: metadata-backup 3 | fromImage: builder/alt 4 | git: 5 | - add: /images/metadata-backup/backup.py 6 | to: /backup.py 7 | stageDependencies: 8 | setup: 9 | - "**/*" 10 | shell: 11 | beforeInstall: 12 | - apt-get update 13 | - DEBIAN_FRONTEND=noninteractive apt-get install -y wget unzip git python3 python3-module-pip jq curl gettext-base util-linux vim-console 14 | - pip3 install kubernetes==30.1.0 15 | setup: 16 | - chmod 755 /backup.py -------------------------------------------------------------------------------- /images/sds-replicated-volume-controller/pkg/kubeutils/kubernetes.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 kubutils 18 | 19 | import ( 20 | "fmt" 21 | 22 | "k8s.io/client-go/rest" 23 | "k8s.io/client-go/tools/clientcmd" 24 | ) 25 | 26 | func KubernetesDefaultConfigCreate() (*rest.Config, error) { 27 | clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( 28 | clientcmd.NewDefaultClientConfigLoadingRules(), 29 | &clientcmd.ConfigOverrides{}, 30 | ) 31 | // Get a config to talk to API server 32 | config, err := clientConfig.ClientConfig() 33 | if err != nil { 34 | return nil, fmt.Errorf("config kubernetes error %w", err) 35 | } 36 | return config, nil 37 | } 38 | -------------------------------------------------------------------------------- /images/sds-replicated-volume-controller/pkg/logger/logger.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 logger 18 | 19 | import ( 20 | "fmt" 21 | "strconv" 22 | 23 | "github.com/go-logr/logr" 24 | "k8s.io/klog/v2/textlogger" 25 | ) 26 | 27 | const ( 28 | ErrorLevel Verbosity = "0" 29 | WarningLevel Verbosity = "1" 30 | InfoLevel Verbosity = "2" 31 | DebugLevel Verbosity = "3" 32 | TraceLevel Verbosity = "4" 33 | ) 34 | 35 | const ( 36 | warnLvl = iota + 1 37 | infoLvl 38 | debugLvl 39 | traceLvl 40 | ) 41 | 42 | type ( 43 | Verbosity string 44 | ) 45 | 46 | type Logger struct { 47 | log logr.Logger 48 | } 49 | 50 | func NewLogger(level Verbosity) (*Logger, error) { 51 | v, err := strconv.Atoi(string(level)) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | log := textlogger.NewLogger(textlogger.NewConfig(textlogger.Verbosity(v))).WithCallDepth(1) 57 | 58 | return &Logger{log: log}, nil 59 | } 60 | 61 | func (l Logger) GetLogger() logr.Logger { 62 | return l.log 63 | } 64 | 65 | func (l Logger) Error(err error, message string, keysAndValues ...interface{}) { 66 | l.log.Error(err, fmt.Sprintf("ERROR %s", message), keysAndValues...) 67 | } 68 | 69 | func (l Logger) Warning(message string, keysAndValues ...interface{}) { 70 | l.log.V(warnLvl).Info(fmt.Sprintf("WARNING %s", message), keysAndValues...) 71 | } 72 | 73 | func (l Logger) Info(message string, keysAndValues ...interface{}) { 74 | l.log.V(infoLvl).Info(fmt.Sprintf("INFO %s", message), keysAndValues...) 75 | } 76 | 77 | func (l Logger) Debug(message string, keysAndValues ...interface{}) { 78 | l.log.V(debugLvl).Info(fmt.Sprintf("DEBUG %s", message), keysAndValues...) 79 | } 80 | 81 | func (l Logger) Trace(message string, keysAndValues ...interface{}) { 82 | l.log.V(traceLvl).Info(fmt.Sprintf("TRACE %s", message), keysAndValues...) 83 | } 84 | 85 | func (l *Logger) Printf(format string, args ...interface{}) { 86 | l.log.V(traceLvl).Info("%s", fmt.Sprintf(format, args...)) 87 | } 88 | -------------------------------------------------------------------------------- /images/sds-replicated-volume-controller/pkg/sdk/framework/reconcile_helper/reconciler_core.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 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 reconcile_helper 18 | 19 | import ( 20 | "k8s.io/apimachinery/pkg/runtime" 21 | "k8s.io/client-go/tools/record" 22 | "sigs.k8s.io/controller-runtime/pkg/cache" 23 | "sigs.k8s.io/controller-runtime/pkg/client" 24 | 25 | "github.com/deckhouse/sds-replicated-volume/images/sds-replicated-volume-controller/pkg/logger" 26 | ) 27 | 28 | type ReconcilerOptions struct { 29 | Client client.Client 30 | Cache cache.Cache 31 | Recorder record.EventRecorder 32 | Scheme *runtime.Scheme 33 | Log logger.Logger 34 | } 35 | -------------------------------------------------------------------------------- /images/sds-replicated-volume-controller/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: {{ $.ImageName }}-src-artifact 3 | from: {{ $.Root.BASE_ALT_P11 }} 4 | final: false 5 | 6 | git: 7 | - add: / 8 | to: /src 9 | includePaths: 10 | - api 11 | - images/{{ $.ImageName }} 12 | stageDependencies: 13 | install: 14 | - '**/*' 15 | excludePaths: 16 | - images/{{ $.ImageName }}/werf.yaml 17 | 18 | shell: 19 | install: 20 | - echo "src artifact" 21 | 22 | --- 23 | image: {{ $.ImageName }}-golang-artifact 24 | fromImage: builder/golang-alpine 25 | final: false 26 | 27 | import: 28 | - image: {{ $.ImageName }}-src-artifact 29 | add: /src 30 | to: /src 31 | before: install 32 | 33 | mount: 34 | - fromPath: ~/go-pkg-cache 35 | to: /go/pkg 36 | 37 | shell: 38 | setup: 39 | - cd /src/images/{{ $.ImageName }}/cmd 40 | - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" -o /{{ $.ImageName }} 41 | - chmod +x /{{ $.ImageName }} 42 | 43 | --- 44 | image: {{ $.ImageName }} 45 | fromImage: base/distroless 46 | 47 | import: 48 | - image: {{ $.ImageName }}-golang-artifact 49 | add: /{{ $.ImageName }} 50 | to: /{{ $.ImageName }} 51 | before: setup 52 | 53 | docker: 54 | ENTRYPOINT: ["/{{ $.ImageName }}"] 55 | USER: deckhouse:deckhouse 56 | -------------------------------------------------------------------------------- /images/semver/scripts/install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024 Flant JSC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -Eeo pipefail 17 | mkdir -p /opt/deckhouse/bin 18 | cp -f d8-semver /opt/deckhouse/bin 19 | -------------------------------------------------------------------------------- /images/semver/scripts/uninstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024 Flant JSC 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 | rm -rf /opt/deckhouse/bin/d8-semver 17 | -------------------------------------------------------------------------------- /images/semver/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: {{ $.ImageName }}-artifact 3 | fromImage: builder/alpine 4 | final: false 5 | 6 | git: 7 | - add: /images/{{ $.ImageName }}/scripts 8 | to: / 9 | 10 | shell: 11 | setup: 12 | - apk add wget tar 13 | - wget https://github.com/fsaintjacques/semver-tool/archive/refs/tags/{{ $.Versions.SEMVER_TOOL }}.tar.gz 14 | - tar -xvf {{ $.Versions.SEMVER_TOOL }}.tar.gz 15 | - mv semver-tool-{{ $.Versions.SEMVER_TOOL }}/src/semver /d8-semver 16 | --- 17 | image: {{ $.ImageName }} 18 | fromImage: base/distroless 19 | 20 | import: 21 | - image: {{ $.ImageName }}-artifact 22 | add: / 23 | to: / 24 | includePaths: 25 | - d8-semver 26 | - install 27 | - uninstall 28 | before: setup 29 | docker: 30 | LABEL: 31 | distro: all 32 | version: all 33 | semver: {{ $.Versions.SEMVER_TOOL }} 34 | -------------------------------------------------------------------------------- /images/service-scripts/scripts/install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024 Flant JSC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -Eeo pipefail 17 | mkdir -p /opt/deckhouse/sbin 18 | cp -f evict.sh /opt/deckhouse/sbin 19 | cp -f replicas_manager.sh /opt/deckhouse/sbin 20 | -------------------------------------------------------------------------------- /images/service-scripts/scripts/uninstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024 Flant JSC 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 | rm -rf /opt/deckhouse/sbin/evict.sh 17 | rm -rf /opt/deckhouse/sbin/replicas_manager.sh 18 | -------------------------------------------------------------------------------- /images/service-scripts/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: {{ $.ImageName }}-artifact 3 | fromImage: builder/alpine 4 | final: false 5 | 6 | git: 7 | - add: /images/{{ $.ImageName }} 8 | to: / 9 | excludePaths: 10 | - werf.inc.yaml 11 | stageDependencies: 12 | setup: 13 | - images/{{ $.ImageName }}/scripts 14 | - images/{{ $.ImageName }}/tools 15 | 16 | shell: 17 | setup: 18 | - chmod a+x scripts/* 19 | - mv scripts/* / 20 | - chmod a+x tools/* 21 | - mv tools/* / 22 | 23 | --- 24 | image: {{ $.ImageName }} 25 | fromImage: base/distroless 26 | 27 | import: 28 | - image: {{ $.ImageName }}-artifact 29 | add: / 30 | to: / 31 | includePaths: 32 | - evict.sh 33 | - replicas_manager.sh 34 | - install 35 | - uninstall 36 | before: setup 37 | docker: 38 | LABEL: 39 | distro: all 40 | version: all 41 | -------------------------------------------------------------------------------- /images/spaas/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: {{ $.ImageName }}-golang-artifact 3 | from: {{ $.Root.BASE_GOLANG_1_22 }} 4 | final: false 5 | git: 6 | - url: {{ $.Root.SOURCE_REPO }}/LINBIT/saas 7 | add: / 8 | to: /usr/local/go/{{ $.ImageName }} 9 | tag: {{ $.Versions.SPAAS }} 10 | stageDependencies: 11 | setup: 12 | - "**/*" 13 | mount: 14 | - fromPath: ~/go-pkg-cache 15 | to: /go/pkg 16 | shell: 17 | setup: 18 | - cd /usr/local/go/{{ $.ImageName }} 19 | - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" -o /{{ $.ImageName }} 20 | - chmod +x /{{ $.ImageName }} 21 | --- 22 | image: {{ $.ImageName }} 23 | # we must base on ALTLinux because SPAAS generates kernel patches for DRBD. So we need same kernel as in DRBD image and some build tools 24 | from: {{ $.Root.BASE_ALT_P11 }} 25 | 26 | import: 27 | - image: {{ $.ImageName }}-golang-artifact 28 | add: /{{ $.ImageName }} 29 | to: /{{ $.ImageName }} 30 | before: setup 31 | 32 | - image: drbd-artifact 33 | add: /drbd/drbd-{{ $.Versions.DRBD }}.tar.gz 34 | to: /var/cache/spaas/tarballs/drbd-{{ $.Versions.DRBD }}.tar.gz 35 | before: setup 36 | 37 | shell: 38 | beforeInstall: 39 | - export DEBIAN_FRONTEND=noninteractive 40 | - | 41 | apt-get update \ 42 | && apt-get -y install build-essential gcc glibc make coccinelle python3-dev vim-console \ 43 | && apt-get -y install ca-certificates \ 44 | && update-ca-trust \ 45 | && update-alternatives --install /usr/bin/python python /usr/bin/python3 100 \ 46 | && ln -sf /proc/mounts /etc/mtab 47 | - {{ $.Root.ALT_CLEANUP_CMD }} 48 | 49 | docker: 50 | ENTRYPOINT: ["/{{ $.ImageName }}"] 51 | LABEL: 52 | distro: all 53 | version: all 54 | spaas: {{ $.Versions.SPAAS }} 55 | -------------------------------------------------------------------------------- /images/webhooks/api/register.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Flant JSC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1alpha1 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | "k8s.io/apimachinery/pkg/runtime" 22 | "k8s.io/apimachinery/pkg/runtime/schema" 23 | ) 24 | 25 | // SchemeGroupVersion is group version used to register these objects 26 | var SchemeGroupVersion = schema.GroupVersion{Group: "deckhouse.io", Version: "v1alpha1"} 27 | 28 | // Resource takes an unqualified resource and returns a Group qualified GroupResource 29 | func Resource(resource string) schema.GroupResource { 30 | return SchemeGroupVersion.WithResource(resource).GroupResource() 31 | } 32 | 33 | var ( 34 | // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. 35 | SchemeBuilder runtime.SchemeBuilder 36 | localSchemeBuilder = &SchemeBuilder 37 | AddToScheme = localSchemeBuilder.AddToScheme 38 | ) 39 | 40 | func init() { 41 | // We only register manually written functions here. The registration of the 42 | // generated functions takes place in the generated files. The separation 43 | // makes the code compile even when the generated files are missing. 44 | localSchemeBuilder.Register(addKnownTypes) 45 | } 46 | 47 | // Adds the list of known types to api.Scheme. 48 | func addKnownTypes(scheme *runtime.Scheme) error { 49 | scheme.AddKnownTypes(SchemeGroupVersion, 50 | &ModuleConfig{}, 51 | &ModuleConfigList{}, 52 | ) 53 | 54 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion) 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /images/webhooks/api/zz_generated.defaults.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | /* 5 | Copyright The Kubernetes Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | // Code generated by defaulter-gen. DO NOT EDIT. 21 | 22 | package v1alpha1 23 | 24 | import ( 25 | runtime "k8s.io/apimachinery/pkg/runtime" 26 | ) 27 | 28 | // RegisterDefaults adds defaulters functions to the given scheme. 29 | // Public to allow building arbitrary schemes. 30 | // All generated defaulters are covering - they call all nested defaulters. 31 | func RegisterDefaults(scheme *runtime.Scheme) error { 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /images/webhooks/werf.inc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | image: {{ $.ImageName }}-src-artifact 3 | fromImage: builder/alt 4 | final: false 5 | 6 | git: 7 | - add: / 8 | to: /src 9 | includePaths: 10 | - api 11 | - images/{{ $.ImageName }} 12 | stageDependencies: 13 | install: 14 | - '**/*' 15 | excludePaths: 16 | - images/{{ $.ImageName }}/werf.yaml 17 | 18 | shell: 19 | install: 20 | - echo "src artifact" 21 | 22 | --- 23 | image: {{ $.ImageName }}-golang-artifact 24 | fromImage: builder/golang-alpine 25 | final: false 26 | 27 | import: 28 | - image: {{ $.ImageName }}-src-artifact 29 | add: /src 30 | to: /src 31 | before: install 32 | 33 | mount: 34 | - fromPath: ~/go-pkg-cache 35 | to: /go/pkg 36 | 37 | shell: 38 | setup: 39 | - cd /src/images/{{ $.ImageName }}/cmd 40 | - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" -o /{{ $.ImageName }} 41 | - chmod +x /{{ $.ImageName }} 42 | 43 | --- 44 | image: {{ $.ImageName }} 45 | fromImage: base/distroless 46 | 47 | import: 48 | - image: {{ $.ImageName }}-golang-artifact 49 | add: /{{ $.ImageName }} 50 | to: /{{ $.ImageName }} 51 | before: setup 52 | 53 | docker: 54 | ENTRYPOINT: ["/{{ $.ImageName }}"] 55 | USER: deckhouse:deckhouse 56 | -------------------------------------------------------------------------------- /lib/python/requirements.txt: -------------------------------------------------------------------------------- 1 | cffi==1.16.0 2 | pyopenssl==25.1.0 3 | pyOpenSSL==25.1.0 4 | cryptography==45.0.2 5 | DateTime==5.2 6 | deckhouse==0.4.9 7 | dictdiffer==0.9.0 8 | dotmap==1.3.30 9 | pycparser==2.21 10 | pytz==2023.3.post1 11 | PyYAML==6.0.1 12 | zope.interface==6.0 13 | jsonpatch==1.33 14 | jsonpointer==2.4 15 | attrs==23.1.0 16 | jsonschema==4.19.1 17 | jsonschema-specifications==2023.7.1 18 | kubernetes==28.1.0 19 | kubernetes-validate==1.28.0 20 | rpds-py==0.10.6 21 | -------------------------------------------------------------------------------- /module.yaml: -------------------------------------------------------------------------------- 1 | name: sds-replicated-volume 2 | weight: 915 3 | descriptions: 4 | en: "SDS Replicated Volume module" 5 | requirements: 6 | bootstrapped: true 7 | deckhouse: ">= 1.67" 8 | modules: 9 | sds-node-configurator: ">= 0.0.0" 10 | namespace: "d8-sds-replicated-volume" 11 | -------------------------------------------------------------------------------- /monitoring/prometheus-rules/expiring-certs.yaml: -------------------------------------------------------------------------------- 1 | - name: kubernetes.certs.expiring_soon_check 2 | rules: 3 | - alert: D8LinstorCertificateExpiringIn30d 4 | expr: count(kube_secret_labels{label_storage_deckhouse_io_sds_replicated_volume_cert_expire_in_30d="true"}) > 0 5 | for: 5m 6 | labels: 7 | severity_level: "4" 8 | tier: cluster 9 | annotations: 10 | plk_markup_format: "markdown" 11 | plk_protocol_version: "1" 12 | plk_create_group_if_not_exists__cluster_has_expiring_certificates: ClusterCertificatesExpiringIn30d,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes 13 | plk_grouped_by__cluster_has_expiring_certificates: ClusterCertificatesExpiringIn30d,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes 14 | summary: LINSTOR certificates expiring within 30 days detected 15 | description: | 16 | One or more Kubernetes Secrets contain certificates that are due to expire in under 30 days. 17 | Please check the certificate details and either renew or rotate them. 18 | 19 | Use the following to list them: 20 | `kubectl get secrets -n d8-sds-replicated-volume -l storage.deckhouse.io/sds-replicated-volume-cert-expire-in-30d=true` 21 | 22 | Check "FAQ: How to manually trigger the certificate renewal process?" in documentation for the manual certificate renewal guide. 23 | -------------------------------------------------------------------------------- /monitoring/prometheus-rules/linstor-affinity-controller.yaml: -------------------------------------------------------------------------------- 1 | - name: kubernetes.linstor.affinity-controller_state 2 | rules: 3 | - alert: D8LinstorAffinityControllerPodIsNotReady 4 | expr: min by (pod) (kube_pod_status_ready{condition="true", namespace="d8-sds-replicated-volume", pod=~"linstor-affinity-controller-.*"}) != 1 5 | labels: 6 | severity_level: "6" 7 | tier: cluster 8 | for: 10m 9 | annotations: 10 | plk_protocol_version: "1" 11 | plk_markup_format: "markdown" 12 | plk_labels_as_annotations: "pod" 13 | plk_create_group_if_not_exists__d8_linstor_affinity_controller_health: "D8LinstorAffinityControllerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 14 | plk_grouped_by__d8_linstor_affinity_controller_health: "D8LinstorAffinityControllerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 15 | summary: The linstor-affinity-controller Pod is NOT Ready. 16 | description: | 17 | The recommended course of action: 18 | 1. Retrieve details of the Deployment: `kubectl -n d8-sds-replicated-volume describe deploy linstor-affinity-controller` 19 | 2. View the status of the Pod and try to figure out why it is not running: `kubectl -n d8-sds-replicated-volume describe pod -l app=linstor-affinity-controller` 20 | 21 | - alert: D8LinstorAffinityControllerPodIsNotRunning 22 | expr: absent(kube_pod_status_phase{namespace="d8-sds-replicated-volume",phase="Running",pod=~"linstor-affinity-controller-.*"}) 23 | labels: 24 | severity_level: "6" 25 | tier: cluster 26 | for: 2m 27 | annotations: 28 | plk_protocol_version: "1" 29 | plk_markup_format: "markdown" 30 | plk_create_group_if_not_exists__d8_linstor_affinity_controller_health: "D8LinstorAffinityControllerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 31 | plk_grouped_by__d8_linstor_affinity_controller_health: "D8LinstorAffinityControllerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 32 | summary: The linstor-affinity-controller Pod is NOT Running. 33 | description: | 34 | The recommended course of action: 35 | 1. Retrieve details of the Deployment: `kubectl -n d8-sds-replicated-volume describe deploy linstor-affinity-controller` 36 | 2. View the status of the Pod and try to figure out why it is not running: `kubectl -n d8-sds-replicated-volume describe pod -l app=linstor-affinity-controller` 37 | -------------------------------------------------------------------------------- /monitoring/prometheus-rules/linstor-backup.yaml: -------------------------------------------------------------------------------- 1 | - name: kubernetes.linstor.obsolete_backups 2 | rules: 3 | - alert: D8ObsoleteLinstorBackupPresents 4 | expr: count(kube_secret_labels{label_sds_replicated_volume_deckhouse_io_linstor_db_backup!=""}) > 0 5 | for: 5m 6 | labels: 7 | severity_level: "4" 8 | tier: cluster 9 | annotations: 10 | plk_markup_format: "markdown" 11 | plk_protocol_version: "1" 12 | plk_create_group_if_not_exists__d8_linstor_obsolete_backups: "D8ObsoleteLinstorBackupPresents,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 13 | plk_grouped_by__d8_linstor_obsolete_backups: "D8ObsoleteLinstorBackupPresents,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 14 | summary: LINSTOR obsolete backups presents in cluster 15 | description: | 16 | There is obsolete LINSTOR metadata backups in cluster 17 | Please check it with command: 18 | `kubectl -n d8-sds-replicated-volume get secrets | grep -E "linstor-[0-9]+-backup"` 19 | 20 | You should remove it with command: 21 | `kubectl -n d8-sds-replicated-volume get secrets | grep -E "linstor-[0-9]+-backup" | awk '{ print "kubectl -n d8-sds-replicated-volume delete secret "$1 }' | bash` 22 | -------------------------------------------------------------------------------- /monitoring/prometheus-rules/linstor-csi-controller.yaml: -------------------------------------------------------------------------------- 1 | - name: kubernetes.linstor.csi_controller_state 2 | rules: 3 | - alert: D8LinstorCsiControllerPodIsNotReady 4 | expr: min by (pod) (kube_pod_status_ready{condition="true", namespace="d8-sds-replicated-volume", pod=~"linstor-csi-controller-.*"}) != 1 5 | for: 10m 6 | labels: 7 | severity_level: "6" 8 | tier: cluster 9 | annotations: 10 | plk_protocol_version: "1" 11 | plk_markup_format: "markdown" 12 | plk_labels_as_annotations: "pod" 13 | plk_create_group_if_not_exists__d8_linstor_csi_controller_health: "D8LinstorCsiControllerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 14 | plk_grouped_by__d8_linstor_csi_controller_health: "D8LinstorCsiControllerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 15 | summary: The linstor-csi-controller Pod is NOT Ready. 16 | description: | 17 | The recommended course of action: 18 | 1. Retrieve details of the Deployment: `kubectl -n d8-sds-replicated-volume describe deploy linstor-csi-controller` 19 | 2. View the status of the Pod and try to figure out why it is not running: `kubectl -n d8-sds-replicated-volume describe pod -l app.kubernetes.io/component=csi-controller` 20 | 21 | - alert: D8LinstorCsiControllerPodIsNotRunning 22 | expr: absent(kube_pod_status_phase{namespace="d8-sds-replicated-volume",phase="Running",pod=~"linstor-csi-controller-.*"}) 23 | labels: 24 | severity_level: "6" 25 | tier: cluster 26 | for: 2m 27 | annotations: 28 | plk_protocol_version: "1" 29 | plk_markup_format: "markdown" 30 | plk_create_group_if_not_exists__d8_linstor_csi_controller_health: "D8LinstorCsiControllerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 31 | plk_grouped_by__d8_linstor_csi_controller_health: "D8LinstorCsiControllerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 32 | summary: The linstor-csi-controller Pod is NOT Running. 33 | description: | 34 | The recommended course of action: 35 | 1. Retrieve details of the Deployment: `kubectl -n d8-sds-replicated-volume describe deploy linstor-csi-controller` 36 | 2. View the status of the Pod and try to figure out why it is not running: `kubectl -n d8-sds-replicated-volume describe pod -l app.kubernetes.io/component=csi-controller` 37 | -------------------------------------------------------------------------------- /monitoring/prometheus-rules/linstor-csi-node.yaml: -------------------------------------------------------------------------------- 1 | - name: kubernetes.linstor.csi_node_state 2 | rules: 3 | - alert: D8LinstorCsiNodePodIsNotReady 4 | expr: min by (pod) (avg by(node,pod,namespace)(kube_pod_info{}) * on(pod, namespace) group_right(node) kube_pod_status_ready{condition="true", namespace="d8-sds-replicated-volume", pod=~"linstor-csi-node-.*"}) != 1 5 | for: 10m 6 | labels: 7 | severity_level: "6" 8 | tier: cluster 9 | annotations: 10 | plk_protocol_version: "1" 11 | plk_markup_format: "markdown" 12 | plk_labels_as_annotations: "pod" 13 | plk_create_group_if_not_exists__d8_linstor_csi_node_health: "D8LinstorCsiNodeHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 14 | plk_grouped_by__d8_linstor_csi_node_health: "D8LinstorCsiNodeHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 15 | summary: The linstor-csi-node Pod is NOT Ready. 16 | description: | 17 | The recommended course of action: 18 | 1. Retrieve details of the DaemonSet: `kubectl -n d8-sds-replicated-volume describe daemonset linstor-csi-node` 19 | 2. View the status of the Pod and try to figure out why it is not running: `kubectl -n d8-sds-replicated-volume describe pod --field-selector=spec.nodeName={{ $labels.node }} -l app.kubernetes.io/component=csi-node` 20 | 21 | - alert: D8LinstorCsiNodePodIsNotRunning 22 | expr: absent(avg by(node,pod,namespace)(kube_pod_info{}) * on(pod, namespace) group_right(node) kube_pod_status_phase{namespace="d8-sds-replicated-volume",phase="Running",pod=~"linstor-csi-node-.*"}) 23 | for: 2m 24 | labels: 25 | severity_level: "6" 26 | tier: cluster 27 | annotations: 28 | plk_protocol_version: "1" 29 | plk_markup_format: "markdown" 30 | plk_create_group_if_not_exists__d8_linstor_csi_node_health: "D8LinstorCsiNodeHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 31 | plk_grouped_by__d8_linstor_csi_node_health: "D8LinstorCsiNodeHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 32 | summary: The linstor-csi-node Pod is NOT Running. 33 | description: | 34 | The recommended course of action: 35 | 1. Retrieve details of the DaemonSet: `kubectl -n d8-sds-replicated-volume describe daemonset linstor-csi-node` 36 | 2. View the status of the Pod and try to figure out why it is not running: `kubectl -n d8-sds-replicated-volume describe pod --field-selector=spec.nodeName={{ $labels.node }} -l app.kubernetes.io/component=csi-node` 37 | -------------------------------------------------------------------------------- /monitoring/prometheus-rules/linstor-scheduler-admission.tpl: -------------------------------------------------------------------------------- 1 | {{- if and (ne "dev" .Values.global.deckhouseVersion) (semverCompare "<1.64" .Values.global.deckhouseVersion) }} 2 | - name: kubernetes.linstor.scheduler_state 3 | rules: 4 | - alert: D8LinstorSchedulerAdmissionPodIsNotReady 5 | expr: min by (pod) (kube_pod_status_ready{condition="true", namespace="d8-sds-replicated-volume", pod=~"linstor-scheduler-admission-.*"}) != 1 6 | for: 10m 7 | labels: 8 | severity_level: "6" 9 | tier: cluster 10 | annotations: 11 | plk_protocol_version: "1" 12 | plk_markup_format: "markdown" 13 | plk_labels_as_annotations: "pod" 14 | plk_create_group_if_not_exists__d8_linstor_scheduler_health: "D8LinstorSchedulerAdmissionHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 15 | plk_grouped_by__d8_linstor_scheduler_health: "D8LinstorSchedulerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 16 | summary: The linstor-scheduler-admission Pod is NOT Ready. 17 | description: | 18 | The recommended course of action: 19 | 1. Retrieve details of the Deployment: `kubectl -n d8-sds-replicated-volume describe deploy linstor-scheduler-admission` 20 | 2. View the status of the Pod and try to figure out why it is not running: `kubectl -n d8-sds-replicated-volume describe pod -l app=linstor-scheduler-admission` 21 | 22 | - alert: D8LinstorSchedulerAdmissionPodIsNotRunning 23 | expr: absent(kube_pod_status_phase{namespace="d8-sds-replicated-volume",phase="Running",pod=~"linstor-scheduler-admission-.*"}) 24 | for: 2m 25 | labels: 26 | severity_level: "6" 27 | tier: cluster 28 | annotations: 29 | plk_protocol_version: "1" 30 | plk_markup_format: "markdown" 31 | plk_create_group_if_not_exists__d8_linstor_scheduler_health: "D8LinstorSchedulerAdmissionHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 32 | plk_grouped_by__d8_linstor_scheduler_health: "D8LinstorSchedulerAdmissionHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 33 | summary: The linstor-scheduler-admission Pod is NOT Running. 34 | description: | 35 | The recommended course of action: 36 | 1. Retrieve details of the Deployment: `kubectl -n d8-sds-replicated-volume describe deploy linstor-scheduler-admission` 37 | 2. View the status of the Pod and try to figure out why it is not running: `kubectl -n d8-sds-replicated-volume describe pod -l app=linstor-scheduler-admission` 38 | {{- end }} 39 | -------------------------------------------------------------------------------- /monitoring/prometheus-rules/linstor-scheduler.yaml: -------------------------------------------------------------------------------- 1 | - name: kubernetes.linstor.scheduler_state 2 | rules: 3 | - alert: D8LinstorSchedulerPodIsNotReady 4 | expr: min by (pod) (kube_pod_status_ready{condition="true", namespace="d8-sds-replicated-volume", pod=~"linstor-scheduler-.*",pod!~"linstor-scheduler-admission-.*"}) != 1 5 | for: 10m 6 | labels: 7 | severity_level: "6" 8 | tier: cluster 9 | annotations: 10 | plk_protocol_version: "1" 11 | plk_markup_format: "markdown" 12 | plk_labels_as_annotations: "pod" 13 | plk_create_group_if_not_exists__d8_linstor_scheduler_health: "D8LinstorSchedulerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 14 | plk_grouped_by__d8_linstor_scheduler_health: "D8LinstorSchedulerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 15 | summary: The linstor-scheduler Pod is NOT Ready. 16 | description: | 17 | The recommended course of action: 18 | 1. Retrieve details of the Deployment: `kubectl -n d8-sds-replicated-volume describe deploy linstor-scheduler` 19 | 2. View the status of the Pod and try to figure out why it is not running: `kubectl -n d8-sds-replicated-volume describe pod -l app=linstor-scheduler` 20 | 21 | - alert: D8LinstorSchedulerPodIsNotRunning 22 | expr: absent(kube_pod_status_phase{namespace="d8-sds-replicated-volume",phase="Running",pod=~"linstor-scheduler-.*",pod!~"linstor-scheduler-admission-.*"}) 23 | for: 2m 24 | labels: 25 | severity_level: "6" 26 | tier: cluster 27 | annotations: 28 | plk_protocol_version: "1" 29 | plk_markup_format: "markdown" 30 | plk_create_group_if_not_exists__d8_linstor_scheduler_health: "D8LinstorSchedulerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 31 | plk_grouped_by__d8_linstor_scheduler_health: "D8LinstorSchedulerHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 32 | summary: The linstor-scheduler Pod is NOT Running. 33 | description: | 34 | The recommended course of action: 35 | 1. Retrieve details of the Deployment: `kubectl -n d8-sds-replicated-volume describe deploy linstor-scheduler` 36 | 2. View the status of the Pod and try to figure out why it is not running: `kubectl -n d8-sds-replicated-volume describe pod -l app=linstor-scheduler` 37 | -------------------------------------------------------------------------------- /monitoring/prometheus-rules/memory-leak.yaml: -------------------------------------------------------------------------------- 1 | - name: kubernetes. 2 | rules: 3 | - alert: D8NodeHighUnknownMemoryUsage 4 | expr: ((sum ( 5 | node_memory_MemTotal_bytes 6 | - node_memory_MemFree_bytes 7 | - node_memory_AnonPages_bytes 8 | - node_memory_Mapped_bytes 9 | - node_memory_Buffers_bytes 10 | - node_memory_SReclaimable_bytes 11 | - clamp_min(node_memory_Cached_bytes - node_memory_Mapped_bytes, 0) 12 | - node_memory_SUnreclaim_bytes 13 | - node_memory_KernelStack_bytes 14 | - node_memory_PageTables_bytes 15 | ) by(node) / sum(node_memory_MemTotal_bytes) by(node)) * 100 ) > 25 16 | for: 5m 17 | labels: 18 | severity_level: "4" 19 | tier: cluster 20 | annotations: 21 | plk_markup_format: "markdown" 22 | plk_protocol_version: "1" 23 | plk_create_group_if_not_exists__d8_node_high_unknown_memory_usage: "D8PossibleMemoryProblems,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 24 | plk_grouped_by__d8_node_high_unknown_memory_usage: "D8PossibleMemoryProblems,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 25 | summary: "Unaccounted memory usage is too high on {{ $labels.node }}" 26 | description: | 27 | Unaccounted memory usage is too high on node {{ $labels.node }}. 28 | This may indicate a memory leak in the system or a misconfiguration. 29 | Please contact with tech support to investigate the issue. 30 | -------------------------------------------------------------------------------- /monitoring/prometheus-rules/spaas.yaml: -------------------------------------------------------------------------------- 1 | - name: kubernetes.drbd.spaas_state 2 | rules: 3 | - alert: D8DrbdSpaasPodIsNotReady 4 | expr: min by (pod) (kube_pod_status_ready{condition="true", namespace="d8-sds-replicated-volume", pod=~"spaas-.*"}) != 1 5 | for: 10m 6 | labels: 7 | severity_level: "6" 8 | tier: cluster 9 | annotations: 10 | plk_protocol_version: "1" 11 | plk_markup_format: "markdown" 12 | plk_labels_as_annotations: "pod" 13 | plk_create_group_if_not_exists__d8_drbd_spaas_health: "D8DrbdSpaasHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 14 | plk_grouped_by__d8_drbd_spaas_health: "D8DrbdSpaasHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 15 | summary: The spaas Pod is NOT Ready. 16 | description: | 17 | The recommended course of action: 18 | 1. Retrieve details of the Deployment: `kubectl -n d8-sds-replicated-volume describe deploy spaas` 19 | 2. View the status of the Pod and try to figure out why it is not running: `kubectl -n d8-sds-replicated-volume describe pod -l app=spaas` 20 | 21 | - alert: D8DrbdSpaasPodIsNotRunning 22 | expr: absent(kube_pod_status_phase{namespace="d8-sds-replicated-volume",phase="Running",pod=~"spaas-.*"}) 23 | for: 2m 24 | labels: 25 | severity_level: "6" 26 | tier: cluster 27 | annotations: 28 | plk_protocol_version: "1" 29 | plk_markup_format: "markdown" 30 | plk_create_group_if_not_exists__d8_drbd_spaas_health: "D8DrbdSpaasHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 31 | plk_grouped_by__d8_drbd_spaas_health: "D8DrbdSpaasHealth,tier=~tier,prometheus=deckhouse,kubernetes=~kubernetes" 32 | summary: The spaas Pod is NOT Running. 33 | description: | 34 | The recommended course of action: 35 | 1. Retrieve details of the Deployment: `kubectl -n d8-sds-replicated-volume describe deploy spaas` 36 | 2. View the status of the Pod and try to figure out why it is not running: `kubectl -n d8-sds-replicated-volume describe pod -l app=spaas` 37 | -------------------------------------------------------------------------------- /openapi/config-values.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | properties: 3 | registryScheme: 4 | type: string 5 | description: Deprecated parameter. Remove it from ModuleConfig for Deckhouse with version greater than 1.57. 6 | default: https 7 | logLevel: 8 | type: string 9 | enum: 10 | - ERROR 11 | - WARN 12 | - INFO 13 | - DEBUG 14 | - TRACE 15 | description: Module log level 16 | default: INFO 17 | drbdPortRange: 18 | type: object 19 | description: Settings for DRBD TCP ports 20 | default: {} 21 | properties: 22 | minPort: 23 | type: integer 24 | default: 7000 25 | description: | 26 | DRBD ports range start 27 | maxPort: 28 | type: integer 29 | default: 7999 30 | description: | 31 | DRBD ports range end 32 | enableThinProvisioning: 33 | type: boolean 34 | default: false 35 | description: Allow thin LVM volumes usage 36 | dataNodes: 37 | type: object 38 | description: Settings for Linstor on nodes with data 39 | default: {} 40 | properties: 41 | nodeSelector: 42 | type: object 43 | default: 44 | kubernetes.io/os: linux 45 | additionalProperties: 46 | type: string 47 | description: | 48 | The same as in the Pods `spec.nodeSelector` parameter in Kubernetes. 49 | 50 | If parameter is omitted, Linstor nodes will be placed on all nodes. 51 | 52 | **Caution!** Changing this parameter does not result in data redistribution. If node with data no longer matches the `nodeSelector`, data on that node will become inaccessible. 53 | backup: 54 | type: object 55 | description: Module backup settings 56 | properties: 57 | enabled: 58 | type: boolean 59 | default: true 60 | description: Module backup state 61 | retentionCount: 62 | type: integer 63 | default: 7 64 | description: Number of backups to keep 65 | schedule: 66 | type: string 67 | default: "0 3 * * *" 68 | description: Backup schedule 69 | -------------------------------------------------------------------------------- /openapi/doc-ru-config-values.yaml: -------------------------------------------------------------------------------- 1 | type: object 2 | properties: 3 | logLevel: 4 | description: Уровень логирования для приложений модуля 5 | dataNodes: 6 | description: Настройки для узлов Linstor с данными 7 | properties: 8 | nodeSelector: 9 | description: | 10 | Настройка аналогична `spec.nodeSelector` в Kubernetes. 11 | 12 | Если параметр не указан, поды для Linstor будут запущены на всех узлах. 13 | 14 | **Внимание!** При изменении этого параметра не происходит переразмещение данных. Если узел с данными перестанет соответствовать `nodeSelector`, данные на нем будут недоступны. 15 | backup: 16 | properties: 17 | enabled: 18 | description: Включение резервного копирования БД модуля 19 | retentionCount: 20 | description: Количество резервных копий для хранения 21 | schedule: 22 | description: Расписание резервного копирования 23 | -------------------------------------------------------------------------------- /openapi/openapi-case-tests.yaml: -------------------------------------------------------------------------------- 1 | positive: 2 | configValues: 3 | - {} 4 | values: 5 | - internal: 6 | drbdVersion: "9.3.2" 7 | negative: 8 | configValues: 9 | - { somethingInConfig: yes } 10 | values: 11 | - { somethingInConfig: yes } 12 | -------------------------------------------------------------------------------- /oss.yaml: -------------------------------------------------------------------------------- 1 | - name: DRBD 2 | link: https://github.com/LINBIT/drbd 3 | description: DRBD, developed by LINBIT, provides networked RAID 1 functionality for GNU/Linux. It is designed for high availability clusters and software defined storage. 4 | license: GPL 2.0 license 5 | -------------------------------------------------------------------------------- /templates/certs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: linstor-controller-https-cert 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 8 | type: kubernetes.io/tls 9 | data: 10 | {{- with .Values.sdsReplicatedVolume.internal.httpsControllerCert }} 11 | tls.crt: {{ .crt | b64enc }} 12 | tls.key: {{ .key | b64enc }} 13 | ca.crt: {{ .ca | b64enc }} 14 | {{- end }} 15 | --- 16 | apiVersion: v1 17 | kind: Secret 18 | metadata: 19 | name: linstor-client-https-cert 20 | namespace: d8-{{ .Chart.Name }} 21 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 22 | type: kubernetes.io/tls 23 | data: 24 | {{- with .Values.sdsReplicatedVolume.internal.httpsClientCert }} 25 | tls.crt: {{ .crt | b64enc }} 26 | tls.key: {{ .key | b64enc }} 27 | ca.crt: {{ .ca | b64enc }} 28 | {{- end }} 29 | --- 30 | apiVersion: v1 31 | kind: Secret 32 | metadata: 33 | name: linstor-controller-ssl-cert 34 | namespace: d8-{{ .Chart.Name }} 35 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 36 | type: kubernetes.io/tls 37 | data: 38 | {{- with .Values.sdsReplicatedVolume.internal.sslControllerCert }} 39 | tls.crt: {{ .crt | b64enc }} 40 | tls.key: {{ .key | b64enc }} 41 | ca.crt: {{ .ca | b64enc }} 42 | {{- end }} 43 | --- 44 | apiVersion: v1 45 | kind: Secret 46 | metadata: 47 | name: linstor-node-ssl-cert 48 | namespace: d8-{{ .Chart.Name }} 49 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 50 | type: kubernetes.io/tls 51 | data: 52 | {{- with .Values.sdsReplicatedVolume.internal.sslNodeCert }} 53 | tls.crt: {{ .crt | b64enc }} 54 | tls.key: {{ .key | b64enc }} 55 | ca.crt: {{ .ca | b64enc }} 56 | {{- end }} 57 | -------------------------------------------------------------------------------- /templates/csi/csidriver.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: CSIDriver 3 | metadata: 4 | name: replicated.csi.storage.deckhouse.io 5 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 6 | spec: 7 | attachRequired: true 8 | fsGroupPolicy: ReadWriteOnceWithFSType 9 | podInfoOnMount: true 10 | requiresRepublish: false 11 | seLinuxMount: true 12 | storageCapacity: true 13 | volumeLifecycleModes: 14 | - Persistent 15 | -------------------------------------------------------------------------------- /templates/csi/rbac-for-us.yaml: -------------------------------------------------------------------------------- 1 | {{- include "helm_lib_csi_controller_rbac" . }} 2 | --- 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | name: d8:{{ .Chart.Name }}:storagepool-reader 7 | {{- include "helm_lib_module_labels" (list . ) | nindent 2 }} 8 | rules: 9 | - apiGroups: ["storage.deckhouse.io"] 10 | resources: ["replicatedstoragepools", "lvmvolumegroups"] 11 | verbs: ["get", "list", "watch"] 12 | --- 13 | apiVersion: rbac.authorization.k8s.io/v1 14 | kind: ClusterRoleBinding 15 | metadata: 16 | name: d8:{{ .Chart.Name }}:storagepool-reader-binding 17 | {{- include "helm_lib_module_labels" (list . ) | nindent 2 }} 18 | subjects: 19 | - kind: ServiceAccount 20 | name: csi 21 | namespace: d8-sds-replicated-volume 22 | roleRef: 23 | kind: ClusterRole 24 | name: d8:{{ .Chart.Name }}:storagepool-reader 25 | apiGroup: rbac.authorization.k8s.io 26 | --- 27 | apiVersion: rbac.authorization.k8s.io/v1 28 | kind: ClusterRole 29 | metadata: 30 | name: d8:{{ .Chart.Name }}:rsc-watcher 31 | {{- include "helm_lib_module_labels" (list . ) | nindent 2 }} 32 | rules: 33 | - apiGroups: ["storage.deckhouse.io"] 34 | resources: ["replicatedstorageclasses"] 35 | verbs: ["get", "list", "watch"] 36 | --- 37 | apiVersion: rbac.authorization.k8s.io/v1 38 | kind: ClusterRoleBinding 39 | metadata: 40 | name: d8:{{ .Chart.Name }}:rsc-read-access 41 | {{- include "helm_lib_module_labels" (list . ) | nindent 2 }} 42 | subjects: 43 | - kind: ServiceAccount 44 | name: csi 45 | namespace: d8-{{ .Chart.Name }} 46 | roleRef: 47 | kind: ClusterRole 48 | name: d8:{{ .Chart.Name }}:rsc-watcher 49 | apiGroup: rbac.authorization.k8s.io 50 | -------------------------------------------------------------------------------- /templates/csi/volume-snapshot-class.yaml: -------------------------------------------------------------------------------- 1 | {{- if (.Values.global.enabledModules | has "snapshot-controller") }} 2 | --- 3 | apiVersion: snapshot.storage.k8s.io/v1beta1 4 | kind: VolumeSnapshotClass 5 | metadata: 6 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-csi-controller")) | nindent 2 }} 7 | name: {{ .Chart.Name }} 8 | driver: replicated.csi.storage.deckhouse.io 9 | deletionPolicy: Delete 10 | {{- end }} 11 | -------------------------------------------------------------------------------- /templates/linstor-affinity-controller/rbac-for-us.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: linstor-affinity-controller 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-affinity-controller")) | nindent 2 }} 8 | --- 9 | kind: ClusterRole 10 | apiVersion: rbac.authorization.k8s.io/v1 11 | metadata: 12 | name: d8:{{ .Chart.Name }}:linstor-affinity-controller 13 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-affinity-controller")) | nindent 2 }} 14 | rules: 15 | - apiGroups: 16 | - "" 17 | resources: 18 | - persistentvolumes 19 | verbs: 20 | - get 21 | - list 22 | - watch 23 | - create 24 | - update 25 | - patch 26 | - delete 27 | - apiGroups: 28 | - "storage.k8s.io" 29 | resources: 30 | - storageclasses 31 | verbs: 32 | - get 33 | - apiGroups: 34 | - events.k8s.io 35 | resources: 36 | - events 37 | verbs: 38 | - create 39 | - patch 40 | --- 41 | kind: ClusterRoleBinding 42 | apiVersion: rbac.authorization.k8s.io/v1 43 | metadata: 44 | name: d8:{{ .Chart.Name }}:linstor-affinity-controller 45 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-affinity-controller")) | nindent 2 }} 46 | subjects: 47 | - kind: ServiceAccount 48 | name: linstor-affinity-controller 49 | namespace: d8-{{ .Chart.Name }} 50 | roleRef: 51 | kind: ClusterRole 52 | name: d8:{{ .Chart.Name }}:linstor-affinity-controller 53 | apiGroup: rbac.authorization.k8s.io 54 | --- 55 | apiVersion: rbac.authorization.k8s.io/v1 56 | kind: Role 57 | metadata: 58 | name: linstor-affinity-controller 59 | namespace: d8-{{ .Chart.Name }} 60 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-affinity-controller")) | nindent 2 }} 61 | rules: 62 | - apiGroups: 63 | - coordination.k8s.io 64 | resources: 65 | - leases 66 | verbs: 67 | - create 68 | - get 69 | - update 70 | --- 71 | apiVersion: rbac.authorization.k8s.io/v1 72 | kind: RoleBinding 73 | metadata: 74 | name: linstor-affinity-controller 75 | namespace: d8-{{ .Chart.Name }} 76 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-affinity-controller")) | nindent 2 }} 77 | roleRef: 78 | apiGroup: rbac.authorization.k8s.io 79 | kind: Role 80 | name: linstor-affinity-controller 81 | subjects: 82 | - kind: ServiceAccount 83 | name: linstor-affinity-controller 84 | namespace: d8-{{ .Chart.Name }} 85 | 86 | -------------------------------------------------------------------------------- /templates/linstor-controller/configmap-linstor-controller-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: linstor-controller-config 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-controller")) | nindent 2 }} 8 | data: 9 | linstor-client.conf: | 10 | [global] 11 | controllers = https://linstor.d8-{{ .Chart.Name }}.svc:3371 12 | cafile = /etc/linstor/client/ca.crt 13 | certfile = /etc/linstor/client/tls.crt 14 | keyfile = /etc/linstor/client/tls.key 15 | linstor.toml: | 16 | [http] 17 | listen_addr = "127.0.0.1" 18 | 19 | [https] 20 | enabled = true 21 | listen_addr = "0.0.0.0" 22 | keystore = "/etc/linstor/https/keystore.jks" 23 | keystore_password = "linstor" 24 | truststore = "/etc/linstor/https/truststore.jks" 25 | truststore_password = "linstor" 26 | 27 | [db] 28 | connection_url = "k8s" 29 | 30 | [logging] 31 | linstor_level = "INFO" 32 | -------------------------------------------------------------------------------- /templates/linstor-controller/configmap-linstor-port-range.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: linstor-port-range 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-controller")) | nindent 2 }} 8 | data: 9 | minPort: "{{ $.Values.sdsReplicatedVolume.drbdPortRange.minPort }}" 10 | maxPort: "{{ $.Values.sdsReplicatedVolume.drbdPortRange.maxPort }}" 11 | -------------------------------------------------------------------------------- /templates/linstor-controller/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-controller" "app.kubernetes.io/instance" "linstor-controller")) | nindent 2 }} 6 | name: linstor 7 | namespace: d8-{{ .Chart.Name }} 8 | spec: 9 | selector: 10 | app: linstor-controller 11 | storage.deckhouse.io/linstor-leader: "true" 12 | ports: 13 | - name: metrics 14 | port: 3370 15 | protocol: TCP 16 | targetPort: metrics 17 | - name: linstor 18 | port: 3371 19 | protocol: TCP 20 | targetPort: linstor 21 | -------------------------------------------------------------------------------- /templates/linstor-controller/servicemonitor.yaml: -------------------------------------------------------------------------------- 1 | {{- if (.Values.global.enabledModules | has "operator-prometheus-crd") }} 2 | --- 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: ServiceMonitor 5 | metadata: 6 | name: linstor-controller 7 | namespace: d8-monitoring 8 | {{- include "helm_lib_module_labels" (list $ (dict "prometheus" "main")) | nindent 2 }} 9 | spec: 10 | endpoints: 11 | - port: metrics 12 | scheme: https 13 | path: /metrics 14 | bearerTokenSecret: 15 | name: "prometheus-token" 16 | key: "token" 17 | tlsConfig: 18 | insecureSkipVerify: true 19 | relabelings: 20 | - regex: endpoint|namespace|pod|container 21 | action: labeldrop 22 | - targetLabel: job 23 | replacement: linstor-controller 24 | - targetLabel: tier 25 | replacement: cluster 26 | - sourceLabels: [__meta_kubernetes_endpointslice_endpoint_conditions_ready] 27 | regex: "true" 28 | action: keep 29 | selector: 30 | matchLabels: 31 | app.kubernetes.io/instance: linstor-controller 32 | app.kubernetes.io/managed-by: Helm 33 | namespaceSelector: 34 | matchNames: 35 | - d8-{{ .Chart.Name }} 36 | {{- end }} 37 | -------------------------------------------------------------------------------- /templates/linstor-node/configmap-linstor-node-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: linstor-node-config 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-node")) | nindent 2 }} 8 | data: 9 | linstor-client.conf: | 10 | [global] 11 | controllers = https://linstor.d8-{{ .Chart.Name }}.svc:3371 12 | cafile = /etc/linstor/client/ca.crt 13 | certfile = /etc/linstor/client/tls.crt 14 | keyfile = /etc/linstor/client/tls.key 15 | linstor_satellite.toml: | 16 | [netcom] 17 | type = "SSL" 18 | port = 3367 19 | server_certificate = "/etc/linstor/ssl/keystore.jks" 20 | key_password = "linstor" 21 | keystore_password = "linstor" 22 | trusted_certificates = "/etc/linstor/ssl/certificates.jks" 23 | truststore_password = "linstor" 24 | ssl_protocol = "TLSv1.2" 25 | 26 | [logging] 27 | linstor_level = "INFO" 28 | -------------------------------------------------------------------------------- /templates/linstor-node/configmap-linstor-node-monitoring.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: linstor-node-monitoring 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-node")) | nindent 2 }} 8 | data: 9 | prometheus.toml: |2 10 | 11 | [[prometheus]] 12 | address = "127.0.0.1:4215" 13 | enums = true 14 | -------------------------------------------------------------------------------- /templates/linstor-node/podmonitor.yaml: -------------------------------------------------------------------------------- 1 | {{- if (.Values.global.enabledModules | has "operator-prometheus-crd") }} 2 | --- 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: PodMonitor 5 | metadata: 6 | name: linstor-node 7 | namespace: d8-monitoring 8 | {{- include "helm_lib_module_labels" (list $ (dict "prometheus" "main")) | nindent 2 }} 9 | spec: 10 | podMetricsEndpoints: 11 | - targetPort: 4215 12 | scheme: https 13 | path: /metrics 14 | bearerTokenSecret: 15 | name: "prometheus-token" 16 | key: "token" 17 | tlsConfig: 18 | insecureSkipVerify: true 19 | relabelings: 20 | - regex: endpoint|namespace|pod|container 21 | action: labeldrop 22 | - targetLabel: job 23 | replacement: linstor-node 24 | - sourceLabels: [__meta_kubernetes_pod_node_name] 25 | targetLabel: node 26 | - targetLabel: tier 27 | replacement: cluster 28 | - sourceLabels: [__meta_kubernetes_pod_ready] 29 | regex: "true" 30 | action: keep 31 | selector: 32 | matchLabels: 33 | app: linstor-node 34 | namespaceSelector: 35 | matchNames: 36 | - d8-{{ .Chart.Name }} 37 | {{- end }} 38 | -------------------------------------------------------------------------------- /templates/linstor-node/rbac-for-us.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: linstor-node 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-node")) | nindent 2 }} 8 | --- 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRole 11 | metadata: 12 | name: d8:{{ .Chart.Name }}:linstor-node 13 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-node")) | nindent 2 }} 14 | rules: 15 | - apiGroups: 16 | - security.openshift.io 17 | resources: 18 | - securitycontextconstraints 19 | resourceNames: 20 | - privileged 21 | verbs: 22 | - use 23 | --- 24 | apiVersion: rbac.authorization.k8s.io/v1 25 | kind: ClusterRoleBinding 26 | metadata: 27 | name: d8:{{ .Chart.Name }}:linstor-node 28 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-node")) | nindent 2 }} 29 | subjects: 30 | - kind: ServiceAccount 31 | name: linstor-node 32 | namespace: d8-{{ .Chart.Name }} 33 | roleRef: 34 | apiGroup: rbac.authorization.k8s.io 35 | kind: ClusterRole 36 | name: d8:{{ .Chart.Name }}:linstor-node 37 | --- 38 | apiVersion: rbac.authorization.k8s.io/v1 39 | kind: ClusterRoleBinding 40 | metadata: 41 | name: d8:{{ .Chart.Name }}:linstor-node-rbac-proxy 42 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-node")) | nindent 2 }} 43 | subjects: 44 | - kind: ServiceAccount 45 | name: linstor-node 46 | namespace: d8-{{ .Chart.Name }} 47 | roleRef: 48 | apiGroup: rbac.authorization.k8s.io 49 | kind: ClusterRole 50 | name: d8:rbac-proxy 51 | -------------------------------------------------------------------------------- /templates/linstor-scheduler-admission/rbac-for-us.yaml: -------------------------------------------------------------------------------- 1 | {{- $dhVersionIsDev := or (hasPrefix "dev" .Values.global.deckhouseVersion) (hasSuffix "dev" .Values.global.deckhouseVersion) }} 2 | {{- if and (not $dhVersionIsDev) (semverCompare "<1.64" .Values.global.deckhouseVersion) }} 3 | --- 4 | apiVersion: v1 5 | kind: ServiceAccount 6 | metadata: 7 | name: linstor-scheduler-admission 8 | namespace: d8-{{ .Chart.Name }} 9 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler-admission")) | nindent 2 }} 10 | --- 11 | kind: ClusterRole 12 | apiVersion: rbac.authorization.k8s.io/v1 13 | metadata: 14 | name: d8:{{ .Chart.Name }}:linstor-scheduler-admission 15 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler-admission")) | nindent 2 }} 16 | rules: 17 | - apiGroups: [""] 18 | resources: ["pods", "persistentvolumeclaims", "persistentvolumes"] 19 | verbs: ["get"] 20 | - apiGroups: ["storage.k8s.io"] 21 | resources: ["storageclasses"] 22 | verbs: ["get"] 23 | --- 24 | apiVersion: rbac.authorization.k8s.io/v1 25 | kind: ClusterRoleBinding 26 | metadata: 27 | name: d8:{{ .Chart.Name }}:linstor-scheduler-admission 28 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler-admission")) | nindent 2 }} 29 | roleRef: 30 | apiGroup: rbac.authorization.k8s.io 31 | kind: ClusterRole 32 | name: d8:{{ .Chart.Name }}:linstor-scheduler-admission 33 | subjects: 34 | - kind: ServiceAccount 35 | name: linstor-scheduler-admission 36 | namespace: d8-{{ .Chart.Name }} 37 | {{- end }} -------------------------------------------------------------------------------- /templates/linstor-scheduler-admission/secret.yaml: -------------------------------------------------------------------------------- 1 | {{- /* 2 | TODO: This secret should be removed after almost all clients moved to 1.64+ Deckhouse version (February 2025?). 3 | Also remove it from hooks/generate_webhook_certs.py and set in module.yaml following: 4 | requirements: 5 | deckhouse: >= 1.64 6 | */}} 7 | --- 8 | apiVersion: v1 9 | kind: Secret 10 | metadata: 11 | name: linstor-scheduler-admission-certs 12 | namespace: d8-{{ .Chart.Name }} 13 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler-admission")) | nindent 2 }} 14 | type: kubernetes.io/tls 15 | data: 16 | {{- with .Values.sdsReplicatedVolume.internal.webhookCert }} 17 | tls.crt: {{ .crt | b64enc }} 18 | tls.key: {{ .key | b64enc }} 19 | ca.crt: {{ .ca | b64enc }} 20 | {{- end }} 21 | -------------------------------------------------------------------------------- /templates/linstor-scheduler-admission/service.yaml: -------------------------------------------------------------------------------- 1 | {{- $dhVersionIsDev := or (hasPrefix "dev" .Values.global.deckhouseVersion) (hasSuffix "dev" .Values.global.deckhouseVersion) }} 2 | {{- if and (not $dhVersionIsDev) (semverCompare "<1.64" .Values.global.deckhouseVersion) }} 3 | --- 4 | apiVersion: v1 5 | kind: Service 6 | metadata: 7 | name: linstor-scheduler-admission 8 | namespace: d8-{{ .Chart.Name }} 9 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler-admission")) | nindent 2 }} 10 | spec: 11 | selector: 12 | app: linstor-scheduler-admission 13 | ports: 14 | - protocol: TCP 15 | port: 4443 16 | targetPort: 8080 17 | {{- end }} -------------------------------------------------------------------------------- /templates/linstor-scheduler-admission/webhook.yaml: -------------------------------------------------------------------------------- 1 | {{- $dhVersionIsDev := or (hasPrefix "dev" .Values.global.deckhouseVersion) (hasSuffix "dev" .Values.global.deckhouseVersion) }} 2 | {{- if and (not $dhVersionIsDev) (semverCompare "<1.64" .Values.global.deckhouseVersion) }} 3 | # File generated by "tools/linstor_scheduler_webhook.go" DO NOT EDIT. 4 | # To generate run 'make generate' 5 | --- 6 | apiVersion: admissionregistration.k8s.io/v1 7 | kind: MutatingWebhookConfiguration 8 | metadata: 9 | name: linstor-scheduler-admission 10 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler-admission")) | nindent 2 }} 11 | webhooks: 12 | - name: scheduler-admission.linstor.deckhouse.io 13 | namespaceSelector: 14 | matchExpressions: 15 | - key: kubernetes.io/metadata.name 16 | operator: NotIn 17 | values: 18 | - kube-basic-auth 19 | - d8-cloud-provider-openstack 20 | - d8-cloud-provider-vsphere 21 | - d8-multitenancy-manager 22 | - kube-system 23 | - d8-metallb 24 | - d8-keepalived 25 | - d8-network-gateway 26 | - d8-operator-trivy 27 | - d8-delivery 28 | - d8-flant-integration 29 | - d8-runtime-audit-engine 30 | - d8-system 31 | - d8-admission-policy-engine 32 | - d8-cni-cilium 33 | - d8-cloud-provider-aws 34 | - d8-cloud-provider-azure 35 | - d8-cloud-provider-gcp 36 | - d8-cloud-provider-yandex 37 | - d8-ceph-csi 38 | - d8-local-path-provisioner 39 | - d8-cni-flannel 40 | - d8-cni-simple-bridge 41 | - d8-cloud-instance-manager 42 | - d8-{{ .Chart.Name }} 43 | - d8-snapshot-controller 44 | - d8-cert-manager 45 | - d8-istio 46 | - d8-user-authz 47 | - d8-user-authn 48 | - d8-operator-prometheus 49 | - kube-prometheus-pushgateway 50 | - d8-descheduler 51 | - d8-ingress-nginx 52 | - d8-log-shipper 53 | - d8-pod-reloader 54 | - d8-chrony 55 | - d8-virtualization 56 | - d8-cdi 57 | - d8-okmeter 58 | - d8-openvpn 59 | rules: 60 | - apiGroups: [""] 61 | apiVersions: ["v1"] 62 | operations: ["CREATE"] 63 | resources: ["pods"] 64 | scope: "*" 65 | clientConfig: 66 | service: 67 | namespace: d8-{{ .Chart.Name }} 68 | name: "linstor-scheduler-admission" 69 | path: "/mutate" 70 | port: 4443 71 | caBundle: {{ .Values.sdsReplicatedVolume.internal.webhookCert.ca | b64enc }} 72 | admissionReviewVersions: ["v1", "v1beta1"] 73 | sideEffects: None 74 | failurePolicy: Ignore 75 | timeoutSeconds: 10 76 | {{- end }} -------------------------------------------------------------------------------- /templates/linstor-scheduler-extender/configmap.yaml: -------------------------------------------------------------------------------- 1 | {{- $dhVersionIsDev := or (hasPrefix "dev" .Values.global.deckhouseVersion) (hasSuffix "dev" .Values.global.deckhouseVersion) }} 2 | {{- if and (not $dhVersionIsDev) (semverCompare "<1.64" .Values.global.deckhouseVersion) }} 3 | --- 4 | apiVersion: v1 5 | kind: ConfigMap 6 | metadata: 7 | name: linstor-scheduler 8 | namespace: d8-{{ .Chart.Name }} 9 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler")) | nindent 2 }} 10 | data: 11 | scheduler-config.yaml: |- 12 | {{- if semverCompare ">= 1.26" .Values.global.discovery.kubernetesVersion }} 13 | apiVersion: kubescheduler.config.k8s.io/v1 14 | {{- else }} 15 | apiVersion: kubescheduler.config.k8s.io/v1beta3 16 | {{- end }} 17 | kind: KubeSchedulerConfiguration 18 | profiles: 19 | - schedulerName: linstor 20 | extenders: 21 | - urlPrefix: https://localhost:8099 22 | filterVerb: filter 23 | prioritizeVerb: prioritize 24 | weight: 5 25 | enableHTTPS: true 26 | httpTimeout: 300s 27 | nodeCacheCapable: true 28 | tlsConfig: 29 | caData: {{ .Values.sdsReplicatedVolume.internal.customSchedulerExtenderCert.ca | b64enc }} 30 | {{- end }} -------------------------------------------------------------------------------- /templates/linstor-scheduler-extender/kube-scheduler-webhook-configuration.yaml: -------------------------------------------------------------------------------- 1 | {{- if or (hasPrefix "dev" .Values.global.deckhouseVersion) (hasSuffix "dev" .Values.global.deckhouseVersion) (semverCompare ">=1.64" .Values.global.deckhouseVersion) }} 2 | apiVersion: deckhouse.io/v1alpha1 3 | kind: KubeSchedulerWebhookConfiguration 4 | metadata: 5 | name: d8-{{ .Chart.Name }} 6 | {{- include "helm_lib_module_labels" (list . ) | nindent 2 }} 7 | webhooks: 8 | - weight: 5 9 | failurePolicy: Ignore 10 | clientConfig: 11 | service: 12 | name: linstor-scheduler-extender 13 | namespace: d8-{{ .Chart.Name }} 14 | port: 8099 15 | path: / 16 | caBundle: {{ .Values.sdsReplicatedVolume.internal.customSchedulerExtenderCert.ca | b64enc }} 17 | timeoutSeconds: 5 18 | 19 | {{- end }} -------------------------------------------------------------------------------- /templates/linstor-scheduler-extender/rbac-for-us.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: linstor-scheduler-extender 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler-extender")) | nindent 2 }} 8 | --- 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRoleBinding 11 | metadata: 12 | name: d8:{{ .Chart.Name }}:linstor-scheduler-extender-kube-scheduler 13 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler-extender")) | nindent 2 }} 14 | roleRef: 15 | apiGroup: rbac.authorization.k8s.io 16 | kind: ClusterRole 17 | name: system:kube-scheduler 18 | subjects: 19 | - kind: ServiceAccount 20 | name: linstor-scheduler-extender 21 | namespace: d8-{{ .Chart.Name }} 22 | --- 23 | apiVersion: rbac.authorization.k8s.io/v1 24 | kind: ClusterRoleBinding 25 | metadata: 26 | name: d8:{{ .Chart.Name }}:linstor-scheduler-extender-volume-scheduler 27 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler-extender")) | nindent 2 }} 28 | roleRef: 29 | apiGroup: rbac.authorization.k8s.io 30 | kind: ClusterRole 31 | name: system:volume-scheduler 32 | subjects: 33 | - kind: ServiceAccount 34 | name: linstor-scheduler-extender 35 | namespace: d8-{{ .Chart.Name }} 36 | --- 37 | apiVersion: rbac.authorization.k8s.io/v1 38 | kind: Role 39 | metadata: 40 | name: linstor-scheduler-extender 41 | namespace: d8-{{ .Chart.Name }} 42 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler-extender")) | nindent 2 }} 43 | rules: 44 | - apiGroups: ["coordination.k8s.io"] 45 | resources: ["leases"] 46 | verbs: ["create", "get", "update"] 47 | --- 48 | apiVersion: rbac.authorization.k8s.io/v1 49 | kind: RoleBinding 50 | metadata: 51 | name: linstor-scheduler-extender 52 | namespace: d8-{{ .Chart.Name }} 53 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler-extender")) | nindent 2 }} 54 | roleRef: 55 | apiGroup: rbac.authorization.k8s.io 56 | kind: Role 57 | name: linstor-scheduler-extender 58 | subjects: 59 | - kind: ServiceAccount 60 | name: linstor-scheduler-extender 61 | namespace: d8-{{ .Chart.Name }} 62 | --- 63 | apiVersion: rbac.authorization.k8s.io/v1 64 | kind: RoleBinding 65 | metadata: 66 | name: d8:{{ .Chart.Name }}:linstor-scheduler-extender:extension-apiserver-authentication-reader 67 | namespace: kube-system 68 | {{- include "helm_lib_module_labels" (list . (dict "app" "linstor-scheduler-extender" )) | nindent 2 }} 69 | roleRef: 70 | apiGroup: rbac.authorization.k8s.io 71 | kind: Role 72 | name: extension-apiserver-authentication-reader 73 | subjects: 74 | - kind: ServiceAccount 75 | name: linstor-scheduler-extender 76 | namespace: d8-{{ .Chart.Name }} 77 | -------------------------------------------------------------------------------- /templates/linstor-scheduler-extender/secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: linstor-scheduler-extender-https-certs 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "sds-replicated-volume-scheduler-extender")) | nindent 2 }} 8 | type: kubernetes.io/tls 9 | data: 10 | ca.crt: {{ .Values.sdsReplicatedVolume.internal.customSchedulerExtenderCert.ca | b64enc }} 11 | tls.crt: {{ .Values.sdsReplicatedVolume.internal.customSchedulerExtenderCert.crt | b64enc }} 12 | tls.key: {{ .Values.sdsReplicatedVolume.internal.customSchedulerExtenderCert.key | b64enc }} -------------------------------------------------------------------------------- /templates/linstor-scheduler-extender/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if or (hasPrefix "dev" .Values.global.deckhouseVersion) (hasSuffix "dev" .Values.global.deckhouseVersion) (semverCompare ">=1.64" .Values.global.deckhouseVersion) }} 2 | --- 3 | apiVersion: v1 4 | kind: Service 5 | metadata: 6 | name: linstor-scheduler-extender 7 | namespace: d8-{{ .Chart.Name }} 8 | {{- include "helm_lib_module_labels" (list . (dict "app" "sds-replicated-volume-scheduler-extender" )) | nindent 2 }} 9 | spec: 10 | type: ClusterIP 11 | ports: 12 | - port: 8099 13 | targetPort: scheduler 14 | protocol: TCP 15 | name: http 16 | selector: 17 | app: linstor-scheduler-extender 18 | {{- end }} 19 | -------------------------------------------------------------------------------- /templates/metadata-backup/job.yaml: -------------------------------------------------------------------------------- 1 | {{- define "metadata_backup_resources" }} 2 | cpu: 10m 3 | memory: 25Mi 4 | {{- end }} 5 | 6 | {{- if dig "backup" "enabled" true .Values.sdsReplicatedVolume }} 7 | --- 8 | apiVersion: batch/v1 9 | kind: CronJob 10 | metadata: 11 | name: metadata-scheduled-backup-daily 12 | namespace: d8-{{ .Chart.Name }} 13 | {{- include "helm_lib_module_labels" (list . (dict "app" "metadata-backup")) | nindent 2 }} 14 | spec: 15 | schedule: {{ dig "backup" "schedule" "0 3 * * *" .Values.sdsReplicatedVolume }} 16 | concurrencyPolicy: Forbid 17 | failedJobsHistoryLimit: 1 18 | jobTemplate: 19 | spec: 20 | template: 21 | metadata: 22 | namespace: d8-{{ .Chart.Name }} 23 | labels: 24 | app: metadata-backup-daily 25 | spec: 26 | restartPolicy: OnFailure 27 | {{- include "helm_lib_priority_class" (tuple . "cluster-medium") | nindent 10 }} 28 | {{- include "helm_lib_node_selector" (tuple . "system") | nindent 10 }} 29 | {{- include "helm_lib_tolerations" (tuple . "system") | nindent 10 }} 30 | {{- include "helm_lib_module_pod_security_context_run_as_user_nobody" . | nindent 10 }} 31 | imagePullSecrets: 32 | - name: {{ .Chart.Name }}-module-registry 33 | serviceAccount: metadata-backup 34 | serviceAccountName: metadata-backup 35 | containers: 36 | - name: metadata-backup 37 | {{- include "helm_lib_module_container_security_context_read_only_root_filesystem_capabilities_drop_all" . | nindent 12 }} 38 | image: {{ include "helm_lib_module_image" (list . "metadataBackup") }} 39 | env: 40 | - name: BACKUP_TYPE 41 | value: "daily-backup" 42 | imagePullPolicy: IfNotPresent 43 | command: 44 | - /backup.py 45 | - --retentionCount 46 | - {{ dig "backup" "retentionCount" 7 .Values.sdsReplicatedVolume | quote }} 47 | volumeMounts: 48 | - name: tmp 49 | mountPath: /tmp 50 | resources: 51 | requests: 52 | {{- include "helm_lib_module_ephemeral_storage_logs_with_extra" 10 | nindent 16 }} 53 | {{- include "metadata_backup_resources" . | nindent 16 }} 54 | volumes: 55 | - name: tmp 56 | emptyDir: {} 57 | {{- end }} 58 | -------------------------------------------------------------------------------- /templates/metadata-backup/job_weekly.yaml: -------------------------------------------------------------------------------- 1 | {{- define "metadata_backup_resources" }} 2 | cpu: 10m 3 | memory: 25Mi 4 | {{- end }} 5 | 6 | {{- if dig "backup" "enabled" true .Values.sdsReplicatedVolume }} 7 | --- 8 | apiVersion: batch/v1 9 | kind: CronJob 10 | metadata: 11 | name: metadata-scheduled-backup-weekly 12 | namespace: d8-{{ .Chart.Name }} 13 | {{- include "helm_lib_module_labels" (list . (dict "app" "metadata-backup")) | nindent 2 }} 14 | spec: 15 | schedule: "0 4 * * 2,4" 16 | concurrencyPolicy: Forbid 17 | failedJobsHistoryLimit: 1 18 | jobTemplate: 19 | spec: 20 | template: 21 | metadata: 22 | namespace: d8-{{ .Chart.Name }} 23 | labels: 24 | app: metadata-backup-weekly 25 | spec: 26 | restartPolicy: OnFailure 27 | {{- include "helm_lib_priority_class" (tuple . "cluster-medium") | nindent 10 }} 28 | {{- include "helm_lib_node_selector" (tuple . "system") | nindent 10 }} 29 | {{- include "helm_lib_tolerations" (tuple . "system") | nindent 10 }} 30 | {{- include "helm_lib_module_pod_security_context_run_as_user_nobody" . | nindent 10 }} 31 | imagePullSecrets: 32 | - name: {{ .Chart.Name }}-module-registry 33 | serviceAccount: metadata-backup 34 | serviceAccountName: metadata-backup 35 | containers: 36 | - name: metadata-backup 37 | {{- include "helm_lib_module_container_security_context_read_only_root_filesystem_capabilities_drop_all" . | nindent 12 }} 38 | image: {{ include "helm_lib_module_image" (list . "metadataBackup") }} 39 | env: 40 | - name: BACKUP_TYPE 41 | value: "weekly-backup" 42 | imagePullPolicy: IfNotPresent 43 | command: 44 | - /backup.py 45 | - --retentionCount 46 | - {{ dig "backup" "retentionCount" 4 .Values.sdsReplicatedVolume | quote }} 47 | volumeMounts: 48 | - name: tmp 49 | mountPath: /tmp 50 | resources: 51 | requests: 52 | {{- include "helm_lib_module_ephemeral_storage_logs_with_extra" 10 | nindent 16 }} 53 | {{- include "metadata_backup_resources" . | nindent 16 }} 54 | volumes: 55 | - name: tmp 56 | emptyDir: {} 57 | {{- end }} 58 | -------------------------------------------------------------------------------- /templates/monitoring.yaml: -------------------------------------------------------------------------------- 1 | {{- include "helm_lib_grafana_dashboard_definitions" . }} 2 | {{- include "helm_lib_prometheus_rules" (list . "d8-sds-replicated-volume") }} 3 | -------------------------------------------------------------------------------- /templates/namespace.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: d8-{{ .Chart.Name }} 6 | {{- include "helm_lib_module_labels" (list . (dict "extended-monitoring.deckhouse.io/enabled" "" "prometheus.deckhouse.io/rules-watcher-enabled" "true")) | nindent 2 }} 7 | --- 8 | {{- include "helm_lib_kube_rbac_proxy_ca_certificate" (list . (printf "d8-%s" .Chart.Name)) }} 9 | -------------------------------------------------------------------------------- /templates/nodegroupconfiguration-blacklist-drbd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: deckhouse.io/v1alpha1 2 | kind: NodeGroupConfiguration 3 | metadata: 4 | name: add-drbd-to-blacklist.sh 5 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 6 | spec: 7 | weight: 100 8 | nodeGroups: ["*"] 9 | bundles: ["*"] 10 | content: | 11 | # Copyright 2021 Flant JSC 12 | # 13 | # Licensed under the Apache License, Version 2.0 (the "License"); 14 | # you may not use this file except in compliance with the License. 15 | # You may obtain a copy of the License at 16 | # 17 | # http://www.apache.org/licenses/LICENSE-2.0 18 | # 19 | # Unless required by applicable law or agreed to in writing, software 20 | # distributed under the License is distributed on an "AS IS" BASIS, 21 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | # See the License for the specific language governing permissions and 23 | # limitations under the License. 24 | 25 | # DRBD devices should not be queried by the LVM and multipath commands. 26 | # So we add DRBD devices into blacklist for multipath and configure 27 | # global_filter in lvm.conf for them 28 | 29 | bb-event-on 'bb-sync-file-changed' '_on_multipath_config_changed' 30 | _on_multipath_config_changed() { 31 | if systemctl is-enabled --quiet multipathd 2>/dev/null; then 32 | systemctl reload multipathd 33 | fi 34 | } 35 | 36 | configure_lvm() { 37 | command -V lvmconfig >/dev/null 2>&1 || return 0 38 | test -f /etc/lvm/lvm.conf || return 0 39 | current_global_filter=$(lvmconfig devices/global_filter 2>/dev/null || true) 40 | 41 | case "${current_global_filter}" in 42 | '' ) new_global_filter='["r|^/dev/drbd|"]' ;; 43 | */dev/drbd*) return 0 ;; 44 | 'global_filter="'*) new_global_filter='["r|^/dev/drbd|",'${current_global_filter#*=}] ;; 45 | 'global_filter=['*) new_global_filter='["r|^/dev/drbd|",'${current_global_filter#*[} ;; 46 | *) echo error parsing global_filter >&2; return 1 ;; 47 | esac 48 | 49 | lvmconfig --config "devices/global_filter=$new_global_filter" --withcomments --merge > /etc/lvm/lvm.conf.$$ 50 | mv /etc/lvm/lvm.conf.$$ /etc/lvm/lvm.conf 51 | } 52 | 53 | configure_multipath() { 54 | mkdir -p /etc/multipath/conf.d 55 | bb-sync-file /etc/multipath/conf.d/drbd.conf - </dev/null; then 37 | systemctl disable --quiet $service_name 38 | systemctl mask --quiet $service_name 39 | fi 40 | } 41 | 42 | if ! test -f /etc/lvm/lvm.conf; then 43 | return 0 44 | fi 45 | if ! command -V lvmconfig >/dev/null 2>&1; then 46 | return 0 47 | fi 48 | 49 | bb-sync-file /etc/lvm/lvm.conf - <<< "$(lvmconfig --config "global/use_lvmetad=0" --withcomments --merge)" 50 | disable_service lvm2-lvmetad.socket 51 | disable_service lvm2-lvmetad.service 52 | -------------------------------------------------------------------------------- /templates/nodegroupconfiguration-restart-kubelet.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.sdsReplicatedVolume.internal.csiMigrationHook.completed }} 2 | apiVersion: deckhouse.io/v1alpha1 3 | kind: NodeGroupConfiguration 4 | metadata: 5 | name: sds-replicated-volume-migrate-csi-restart-kubelet.sh 6 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 7 | spec: 8 | weight: 101 9 | nodeGroups: ["*"] 10 | bundles: ["*"] 11 | content: | 12 | # Copyright 2024 Flant JSC 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); 15 | # you may not use this file except in compliance with the License. 16 | # You may obtain a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, 22 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23 | # See the License for the specific language governing permissions and 24 | # limitations under the License. 25 | 26 | # The lvmetad service should not be used by LVM on the node. 27 | # So we disable the service and set the setting use_lvmetad to 0 in lvm.conf. 28 | 29 | # affectedPVsHash: {{ .Values.sdsReplicatedVolume.internal.csiMigrationHook.affectedPVsHash }} 30 | export LABEL_KEY="storage.deckhouse.io/need-kubelet-restart" 31 | export kubeconfig="/etc/kubernetes/kubelet.conf" 32 | 33 | is_kubelet_restart_needed=$(bb-kubectl --kubeconfig $kubeconfig get node "$(hostname)" -o json | jq -c '.metadata.labels | contains({"'$LABEL_KEY'": ""})') 34 | 35 | 36 | echo "is_kubelet_restart_needed: $is_kubelet_restart_needed" 37 | 38 | if [ "$is_kubelet_restart_needed" = "true" ]; then 39 | echo "Kubelet restart is needed. Restarting kubelet." 40 | systemctl restart kubelet 41 | 42 | echo "Sleeping for 180 seconds before restarting kubelet again." 43 | sleep 180 44 | 45 | echo "Restarting kubelet again." 46 | systemctl restart kubelet 47 | 48 | bb-kubectl --kubeconfig $kubeconfig label node "$(hostname)" "$LABEL_KEY"- 49 | else 50 | echo "Kubelet restart is not needed. Exiting." 51 | fi 52 | 53 | {{- end }} 54 | -------------------------------------------------------------------------------- /templates/passphrase.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.sdsReplicatedVolume.internal.masterPassphrase }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: linstor-passphrase 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 8 | type: Opaque 9 | data: 10 | MASTER_PASSPHRASE: {{ b64enc .Values.sdsReplicatedVolume.internal.masterPassphrase }} 11 | {{- end }} 12 | -------------------------------------------------------------------------------- /templates/rbac-to-us.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: access-to-linstor 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 8 | rules: 9 | - apiGroups: ["apps"] 10 | resources: ["daemonsets/prometheus-metrics", "deployments/prometheus-metrics"] 11 | resourceNames: ["linstor-controller", "linstor-node"] 12 | verbs: ["get"] 13 | 14 | {{- if (.Values.global.enabledModules | has "prometheus") }} 15 | --- 16 | apiVersion: rbac.authorization.k8s.io/v1 17 | kind: RoleBinding 18 | metadata: 19 | name: access-to-linstor 20 | namespace: d8-{{ .Chart.Name }} 21 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 22 | roleRef: 23 | apiGroup: rbac.authorization.k8s.io 24 | kind: Role 25 | name: access-to-linstor 26 | subjects: 27 | - kind: User 28 | name: d8-monitoring:scraper 29 | - kind: ServiceAccount 30 | name: prometheus 31 | namespace: d8-monitoring 32 | {{- end }} 33 | -------------------------------------------------------------------------------- /templates/registry-secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ .Chart.Name }}-module-registry 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 8 | type: kubernetes.io/dockerconfigjson 9 | data: 10 | {{- if dig "registry" "dockercfg" false .Values.sdsReplicatedVolume }} 11 | .dockerconfigjson: {{ .Values.sdsReplicatedVolume.registry.dockercfg }} 12 | {{- else }} 13 | .dockerconfigjson: "eyJhdXRocyI6IHsgInJlZ2lzdHJ5LmRlY2tob3VzZS5pbyI6IHt9fX0=" 14 | {{- end }} 15 | --- 16 | apiVersion: v1 17 | kind: Secret 18 | metadata: 19 | name: deckhouse-registry 20 | namespace: d8-{{ .Chart.Name }} 21 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 22 | type: kubernetes.io/dockerconfigjson 23 | data: 24 | .dockerconfigjson: {{ .Values.global.modulesImages.registry.dockercfg }} 25 | -------------------------------------------------------------------------------- /templates/sds-replicated-volume-controller/configmap.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: sds-replicated-volume-controller-config 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "sds-replicated-volume-controller")) | nindent 2 }} 8 | data: 9 | {{- if has "virtualization" .Values.global.enabledModules }} 10 | virtualizationEnabled: "true" 11 | {{- else }} 12 | virtualizationEnabled: "false" 13 | {{- end }} 14 | -------------------------------------------------------------------------------- /templates/sds-replicated-volume-controller/secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: d8-sds-replicated-volume-controller-config 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "sds-replicated-volume-controller")) | nindent 2 }} 8 | type: Opaque 9 | stringData: 10 | config: |- 11 | nodeSelector: {{ .Values.sdsReplicatedVolume.dataNodes.nodeSelector | toYaml | nindent 6 }} 12 | -------------------------------------------------------------------------------- /templates/spaas/secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: spaas-certs 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "spaas")) | nindent 2 }} 8 | type: kubernetes.io/tls 9 | data: 10 | {{- with .Values.sdsReplicatedVolume.internal.spaasCert }} 11 | tls.crt: {{ .crt | b64enc }} 12 | tls.key: {{ .key | b64enc }} 13 | ca.crt: {{ .ca | b64enc }} 14 | {{- end }} 15 | -------------------------------------------------------------------------------- /templates/spaas/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Service 3 | apiVersion: v1 4 | metadata: 5 | name: spaas 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "spaas")) | nindent 2 }} 8 | spec: 9 | ports: 10 | - name: http 11 | port: 2020 12 | targetPort: http 13 | selector: 14 | app: spaas 15 | -------------------------------------------------------------------------------- /templates/webhooks/rbac-for-us.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: webhooks 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "webhooks")) | nindent 2 }} 8 | --- 9 | kind: ClusterRole 10 | apiVersion: rbac.authorization.k8s.io/v1 11 | metadata: 12 | name: d8:{{ .Chart.Name }}:webhooks 13 | {{- include "helm_lib_module_labels" (list . (dict "app" "webhooks")) | nindent 2 }} 14 | rules: 15 | - apiGroups: 16 | - deckhouse.io 17 | resources: 18 | - moduleconfigs 19 | verbs: 20 | - get 21 | - watch 22 | - update 23 | - list 24 | - patch 25 | - verbs: 26 | - get 27 | - list 28 | - watch 29 | apiGroups: 30 | - storage.deckhouse.io 31 | resources: 32 | - replicatedstorageclasses 33 | - lvmvolumegroups 34 | - verbs: 35 | - get 36 | - list 37 | apiGroups: 38 | - "" 39 | resources: 40 | - nodes 41 | - apiGroups: 42 | - storage.k8s.io 43 | verbs: 44 | - get 45 | - list 46 | resources: 47 | - storageclasses 48 | --- 49 | kind: ClusterRoleBinding 50 | apiVersion: rbac.authorization.k8s.io/v1 51 | metadata: 52 | name: d8:{{ .Chart.Name }}:webhooks 53 | {{- include "helm_lib_module_labels" (list . (dict "app" "webhooks")) | nindent 2 }} 54 | roleRef: 55 | apiGroup: rbac.authorization.k8s.io 56 | kind: ClusterRole 57 | name: d8:{{ .Chart.Name }}:webhooks 58 | subjects: 59 | - kind: ServiceAccount 60 | name: webhooks 61 | namespace: d8-{{ .Chart.Name }} 62 | -------------------------------------------------------------------------------- /templates/webhooks/secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: webhooks-https-certs 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "webhooks")) | nindent 2 }} 8 | type: kubernetes.io/tls 9 | data: 10 | ca.crt: {{ .Values.sdsReplicatedVolume.internal.customWebhookCert.ca | b64enc }} 11 | tls.crt: {{ .Values.sdsReplicatedVolume.internal.customWebhookCert.crt | b64enc }} 12 | tls.key: {{ .Values.sdsReplicatedVolume.internal.customWebhookCert.key | b64enc }} 13 | -------------------------------------------------------------------------------- /templates/webhooks/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: webhooks 6 | namespace: d8-{{ .Chart.Name }} 7 | {{- include "helm_lib_module_labels" (list . (dict "app" "webhooks" )) | nindent 2 }} 8 | spec: 9 | type: ClusterIP 10 | ports: 11 | - port: 443 12 | targetPort: http 13 | protocol: TCP 14 | name: http 15 | selector: 16 | app: webhooks -------------------------------------------------------------------------------- /templates/webhooks/webhook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: admissionregistration.k8s.io/v1 3 | kind: ValidatingWebhookConfiguration 4 | metadata: 5 | name: "d8-sds-replicated-volume-rsp-validation" 6 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 7 | webhooks: 8 | - name: "d8-sds-replicated-volume-rsp-validation.storage.deckhouse.io" 9 | rules: 10 | - apiGroups: ["storage.deckhouse.io"] 11 | apiVersions: ["v1alpha1"] 12 | operations: ["CREATE", "UPDATE"] 13 | resources: ["replicatedstoragepools"] 14 | scope: "Cluster" 15 | clientConfig: 16 | service: 17 | namespace: "d8-{{ .Chart.Name }}" 18 | name: "webhooks" 19 | path: "/rsp-validate" 20 | caBundle: | 21 | {{ .Values.sdsReplicatedVolume.internal.customWebhookCert.ca | b64enc }} 22 | admissionReviewVersions: ["v1", "v1beta1"] 23 | sideEffects: None 24 | timeoutSeconds: 5 25 | --- 26 | apiVersion: admissionregistration.k8s.io/v1 27 | kind: ValidatingWebhookConfiguration 28 | metadata: 29 | name: "d8-sds-replicated-volume-rsc-validation" 30 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 31 | webhooks: 32 | - name: "d8-sds-replicated-volume-rsc-validation.storage.deckhouse.io" 33 | rules: 34 | - apiGroups: ["storage.deckhouse.io"] 35 | apiVersions: ["v1alpha1"] 36 | operations: ["CREATE", "UPDATE"] 37 | resources: ["replicatedstorageclasses"] 38 | scope: "Cluster" 39 | clientConfig: 40 | service: 41 | namespace: "d8-{{ .Chart.Name }}" 42 | name: "webhooks" 43 | path: "/rsc-validate" 44 | caBundle: | 45 | {{ .Values.sdsReplicatedVolume.internal.customWebhookCert.ca | b64enc }} 46 | admissionReviewVersions: ["v1", "v1beta1"] 47 | sideEffects: None 48 | timeoutSeconds: 5 49 | --- 50 | apiVersion: admissionregistration.k8s.io/v1 51 | kind: ValidatingWebhookConfiguration 52 | metadata: 53 | name: "d8-sds-replicated-volume-sc-validation" 54 | {{- include "helm_lib_module_labels" (list .) | nindent 2 }} 55 | webhooks: 56 | - name: "d8-sds-replicated-volume-sc-validation.storage.deckhouse.io" 57 | rules: 58 | - apiGroups: ["storage.k8s.io"] 59 | apiVersions: ["v1"] 60 | operations: ["*"] 61 | resources: ["storageclasses"] 62 | scope: "Cluster" 63 | clientConfig: 64 | service: 65 | namespace: "d8-{{ .Chart.Name }}" 66 | name: "webhooks" 67 | path: "/sc-validate" 68 | caBundle: | 69 | {{ .Values.sdsReplicatedVolume.internal.customWebhookCert.ca | b64enc }} 70 | admissionReviewVersions: ["v1", "v1beta1"] 71 | sideEffects: None 72 | timeoutSeconds: 5 73 | -------------------------------------------------------------------------------- /werf-giterminism.yaml: -------------------------------------------------------------------------------- 1 | giterminismConfigVersion: 1 2 | config: 3 | goTemplateRendering: # The rules for the Go-template functions to be able to pass build context to the release 4 | allowEnvVariables: 5 | - /CI_.+/ 6 | - MODULES_MODULE_TAG 7 | - MODULE_EDITION 8 | - WERF_DISABLE_META_TAGS 9 | - GOLANG_VERSION 10 | - GOPROXY 11 | - SOURCE_REPO 12 | - SOURCE_REPO_TAG 13 | allowUncommittedFiles: 14 | - "base_images.yml" 15 | stapel: 16 | mount: 17 | allowBuildDir: true 18 | allowFromPaths: 19 | - ~/go-pkg-cache 20 | -------------------------------------------------------------------------------- /werf.yaml: -------------------------------------------------------------------------------- 1 | project: sds-replicated-volume 2 | configVersion: 1 3 | build: 4 | imageSpec: 5 | author: "Deckhouse Kubernetes Platform " 6 | clearHistory: true 7 | config: 8 | clearWerfLabels: true 9 | removeLabels: 10 | - /.*/ 11 | --- 12 | {{ tpl (.Files.Get ".werf/base-images.yaml") $ }} 13 | {{ tpl (.Files.Get ".werf/consts.yaml") $ }} 14 | {{ tpl (.Files.Get ".werf/choose-edition.yaml") $ }} 15 | {{ tpl (.Files.Get ".werf/utils.yaml") $ }} 16 | {{ tpl (.Files.Get ".werf/images.yaml") $ }} 17 | {{ tpl (.Files.Get ".werf/images-digests.yaml") $ }} 18 | {{ tpl (.Files.Get ".werf/python-deps.yaml") $ }} 19 | {{ tpl (.Files.Get ".werf/bundle.yaml") $ }} 20 | {{ tpl (.Files.Get ".werf/release.yaml") $ }} 21 | -------------------------------------------------------------------------------- /werf_cleanup.yaml: -------------------------------------------------------------------------------- 1 | project: sds-replicated-volume 2 | configVersion: 1 3 | cleanup: 4 | keepPolicies: 5 | - references: 6 | branch: /.*/ 7 | limit: 8 | in: 168h # keep dev images build during last week which not main|pre-alpha 9 | - references: 10 | branch: /main|pre-alpha/ 11 | imagesPerReference: 12 | last: 5 # keep 5 images for branches main|pre-alpha 13 | --------------------------------------------------------------------------------