feat: add support for imported cluster secrets
Some checks failed
default / default (push) Has been cancelled
default / e2e-backups (push) Has been cancelled
default / e2e-cluster-import (push) Has been cancelled
default / e2e-forced-removal (push) Has been cancelled
default / e2e-omni-upgrade (push) Has been cancelled
default / e2e-scaling (push) Has been cancelled
default / e2e-short (push) Has been cancelled
default / e2e-short-secureboot (push) Has been cancelled
default / e2e-templates (push) Has been cancelled
default / e2e-upgrades (push) Has been cancelled
default / e2e-workload-proxy (push) Has been cancelled

Introduce new resource `ImportedClusterSecrets` for importing an existing secrets bundle.
Add new field `imported` to `ClusterSpec` for utilizing resource `ImportedCreatedSecrets`.
Add new field `imported` to `ClusterSecrets` for pointing out source of the secrets bundle.

This is a feature-gated feature to allow using an existing secrets bundle (`talos gen secrets`) while creating a new Cluster. Cluster created with this method are marked as `tainted`. This feature is part of a story to facilitate importing existing talos clusters to omni.

Signed-off-by: Oguz Kilcan <oguz.kilcan@siderolabs.com>
This commit is contained in:
Oguz Kilcan 2025-07-14 15:02:55 +02:00
parent 753259c26e
commit f8de9a6d96
No known key found for this signature in database
GPG Key ID: 372F271E3AD80BFC
45 changed files with 1337 additions and 467 deletions

View File

@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2025-07-11T15:30:30Z by kres c691b83.
# Generated on 2025-07-14T11:13:09Z by kres c691b83.
concurrency:
group: ${{ github.head_ref || github.run_id }}
@ -105,7 +105,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "true"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|Auth|DefaultCluster|CLICommands)$
RUN_TALEMU_TESTS: "true"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |
@ -301,7 +301,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|EtcdBackupAndRestore)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |
@ -317,6 +317,86 @@ jobs:
/tmp/integration-test
retention-days: "5"
continue-on-error: true
e2e-cluster-import:
runs-on:
- self-hosted
- omni
if: contains(fromJSON(needs.default.outputs.labels), 'integration/e2e') || contains(fromJSON(needs.default.outputs.labels), 'integration/e2e-cluster-import')
needs:
- default
steps:
- name: gather-system-info
id: system-info
uses: kenchan0130/actions-system-info@v1.3.1
continue-on-error: true
- name: print-system-info
run: |
MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))
OUTPUTS=(
"CPU Core: ${{ steps.system-info.outputs.cpu-core }}"
"CPU Model: ${{ steps.system-info.outputs.cpu-model }}"
"Hostname: ${{ steps.system-info.outputs.hostname }}"
"NodeName: ${NODE_NAME}"
"Kernel release: ${{ steps.system-info.outputs.kernel-release }}"
"Kernel version: ${{ steps.system-info.outputs.kernel-version }}"
"Name: ${{ steps.system-info.outputs.name }}"
"Platform: ${{ steps.system-info.outputs.platform }}"
"Release: ${{ steps.system-info.outputs.release }}"
"Total memory: ${MEMORY_GB} GB"
)
for OUTPUT in "${OUTPUTS[@]}";do
echo "${OUTPUT}"
done
continue-on-error: true
- name: checkout
uses: actions/checkout@v4
- name: Unshallow
run: |
git fetch --prune --unshallow
- name: Set up Docker Buildx
id: setup-buildx
uses: docker/setup-buildx-action@v3
with:
driver: remote
endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234
timeout-minutes: 10
- name: Mask secrets
run: |
echo "$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | "::add-mask::" + .value')"
- name: Set secrets for job
run: |
sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + "=" + .value' >> "$GITHUB_ENV"
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: artifacts
path: _out
- name: Fix artifact permissions
run: |
xargs -a _out/executable-artifacts -I {} chmod +x {}
- name: run-integration-test
env:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|ClusterImport)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |
sudo -E make run-integration-test
- name: save-integration-test-artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: integration-test-e2e-cluster-import
path: |-
~/.talos/clusters/**/*.log
!~/.talos/clusters/**/swtpm.log
/tmp/integration-test
retention-days: "5"
continue-on-error: true
e2e-forced-removal:
runs-on:
- self-hosted
@ -381,7 +461,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|ForcedMachineRemoval|ReplaceControlPlanes|ConfigPatching|KubernetesNodeAudit)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |
@ -462,7 +542,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(OmniUpgradeVerify)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |
@ -542,7 +622,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|RollingUpdateParallelism)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |
@ -622,7 +702,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|TalosImageGeneration|ImmediateClusterDestruction|DefaultCluster|EncryptedCluster|SinglenodeCluster|Auth)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |
@ -703,7 +783,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|TalosImageGeneration|ImmediateClusterDestruction|DefaultCluster|EncryptedCluster|SinglenodeCluster|Auth)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |
@ -783,7 +863,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|ClusterTemplate)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |
@ -863,7 +943,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |
@ -943,7 +1023,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|WorkloadProxy)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |

View File

@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2025-07-11T15:30:30Z by kres c691b83.
# Generated on 2025-07-14T11:13:09Z by kres c691b83.
concurrency:
group: ${{ github.head_ref || github.run_id }}
@ -63,7 +63,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|EtcdBackupAndRestore)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |

View File

@ -0,0 +1,80 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2025-07-14T11:13:09Z by kres c691b83.
concurrency:
group: ${{ github.head_ref || github.run_id }}
cancel-in-progress: true
"on":
schedule:
- cron: 30 1 * * *
name: e2e-cluster-import-cron
jobs:
default:
runs-on:
- self-hosted
- omni
steps:
- name: gather-system-info
id: system-info
uses: kenchan0130/actions-system-info@v1.3.1
continue-on-error: true
- name: print-system-info
run: |
MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))
OUTPUTS=(
"CPU Core: ${{ steps.system-info.outputs.cpu-core }}"
"CPU Model: ${{ steps.system-info.outputs.cpu-model }}"
"Hostname: ${{ steps.system-info.outputs.hostname }}"
"NodeName: ${NODE_NAME}"
"Kernel release: ${{ steps.system-info.outputs.kernel-release }}"
"Kernel version: ${{ steps.system-info.outputs.kernel-version }}"
"Name: ${{ steps.system-info.outputs.name }}"
"Platform: ${{ steps.system-info.outputs.platform }}"
"Release: ${{ steps.system-info.outputs.release }}"
"Total memory: ${MEMORY_GB} GB"
)
for OUTPUT in "${OUTPUTS[@]}";do
echo "${OUTPUT}"
done
continue-on-error: true
- name: checkout
uses: actions/checkout@v4
- name: Unshallow
run: |
git fetch --prune --unshallow
- name: Set up Docker Buildx
id: setup-buildx
uses: docker/setup-buildx-action@v3
with:
driver: remote
endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234
timeout-minutes: 10
- name: Mask secrets
run: |
echo "$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | "::add-mask::" + .value')"
- name: Set secrets for job
run: |
sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + "=" + .value' >> "$GITHUB_ENV"
- name: run-integration-test
env:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|ClusterImport)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |
sudo -E make run-integration-test
- name: save-integration-test-artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: integration-test
path: |-
~/.talos/clusters/**/*.log
!~/.talos/clusters/**/swtpm.log
/tmp/integration-test
retention-days: "5"

View File

@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2025-07-11T15:30:30Z by kres c691b83.
# Generated on 2025-07-14T11:13:09Z by kres c691b83.
concurrency:
group: ${{ github.head_ref || github.run_id }}
@ -63,7 +63,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|ForcedMachineRemoval|ReplaceControlPlanes|ConfigPatching|KubernetesNodeAudit)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |

View File

@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2025-07-11T15:30:30Z by kres c691b83.
# Generated on 2025-07-14T11:13:09Z by kres c691b83.
concurrency:
group: ${{ github.head_ref || github.run_id }}
@ -64,7 +64,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(OmniUpgradeVerify)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |

View File

@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2025-07-11T15:30:30Z by kres c691b83.
# Generated on 2025-07-14T11:13:09Z by kres c691b83.
concurrency:
group: ${{ github.head_ref || github.run_id }}
@ -63,7 +63,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|RollingUpdateParallelism)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |

View File

@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2025-07-11T15:30:30Z by kres c691b83.
# Generated on 2025-07-14T11:13:09Z by kres c691b83.
concurrency:
group: ${{ github.head_ref || github.run_id }}
@ -63,7 +63,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|TalosImageGeneration|ImmediateClusterDestruction|DefaultCluster|EncryptedCluster|SinglenodeCluster|Auth)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |

View File

@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2025-07-11T15:30:30Z by kres c691b83.
# Generated on 2025-07-14T11:13:09Z by kres c691b83.
concurrency:
group: ${{ github.head_ref || github.run_id }}
@ -64,7 +64,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|TalosImageGeneration|ImmediateClusterDestruction|DefaultCluster|EncryptedCluster|SinglenodeCluster|Auth)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |

View File

@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2025-07-11T15:30:30Z by kres c691b83.
# Generated on 2025-07-14T11:13:09Z by kres c691b83.
concurrency:
group: ${{ github.head_ref || github.run_id }}
@ -63,7 +63,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|ClusterTemplate)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |

View File

@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2025-07-11T15:30:30Z by kres c691b83.
# Generated on 2025-07-14T11:13:09Z by kres c691b83.
concurrency:
group: ${{ github.head_ref || github.run_id }}
@ -63,7 +63,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |

View File

@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2025-07-11T15:30:30Z by kres c691b83.
# Generated on 2025-07-14T11:13:09Z by kres c691b83.
concurrency:
group: ${{ github.head_ref || github.run_id }}
@ -63,7 +63,7 @@ jobs:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: --test.run TestIntegration/Suites/(CleanState|WorkloadProxy)$
RUN_TALEMU_TESTS: "false"
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$
TALEMU_TEST_ARGS: --test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$
WITH_DEBUG: "true"
WITH_RACE: "true"
run: |

View File

@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2025-07-11T15:30:30Z by kres c691b83.
# Generated on 2025-07-14T11:13:09Z by kres c691b83.
"on":
workflow_run:
@ -15,6 +15,7 @@
- e2e-backups-cron
- e2e-workload-proxy-cron
- e2e-omni-upgrade-cron
- e2e-cluster-import-cron
types:
- completed
name: slack-notify

View File

@ -212,7 +212,7 @@ spec:
WITH_RACE: "true"
INTEGRATION_RUN_E2E_TEST: "true"
INTEGRATION_TEST_ARGS: "--test.run TestIntegration/Suites/(CleanState|Auth|DefaultCluster|CLICommands)$"
TALEMU_TEST_ARGS: "--test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets)$"
TALEMU_TEST_ARGS: "--test.run TestIntegration/Suites/(ImmediateClusterDestruction|EncryptedCluster|SinglenodeCluster|ScaleUpAndDown|ScaleUpAndDownMachineClassBasedMachineSets|TalosUpgrades|KubernetesUpgrades|MaintenanceUpgrade|ClusterTemplate|ScaleUpAndDownAutoProvisionMachineSets|ClusterImport)$"
RUN_TALEMU_TESTS: true
jobs:
- name: e2e-short-secureboot
@ -324,6 +324,18 @@ spec:
INTEGRATION_PREPARE_TEST_ARGS: "--test.run TestIntegration/Suites/(CleanState|OmniUpgradePrepare)$"
INTEGRATION_TEST_ARGS: "--test.run TestIntegration/Suites/(OmniUpgradeVerify)$"
RUN_TALEMU_TESTS: false
- name: e2e-cluster-import
crons:
- '30 1 * * *'
runnerLabels:
- omni
triggerLabels:
- integration/e2e
- integration/e2e-cluster-import
environmentOverride:
INTEGRATION_RUN_E2E_TEST: "false"
INTEGRATION_TEST_ARGS: "--test.run TestIntegration/Suites/(CleanState|ClusterImport)$"
RUN_TALEMU_TESTS: false
---
kind: common.Build
spec:

File diff suppressed because it is too large Load Diff

View File

@ -613,6 +613,14 @@ message ClusterBootstrapStatusSpec {
message ClusterSecretsSpec {
// Bytes holding serialized cluster secrets.
bytes data = 1;
// imported holds origin of the cluster secrets.
bool imported = 2;
}
// ImportedClusterSecretsSpec describes imported cluster secrets.
message ImportedClusterSecretsSpec {
// data holds imported cluster secrets.
string data = 1;
}
// LoadBalancerConfigSpec describes the configuration of a load balancer.

View File

@ -987,6 +987,7 @@ func (m *ClusterSecretsSpec) CloneVT() *ClusterSecretsSpec {
return (*ClusterSecretsSpec)(nil)
}
r := new(ClusterSecretsSpec)
r.Imported = m.Imported
if rhs := m.Data; rhs != nil {
tmpBytes := make([]byte, len(rhs))
copy(tmpBytes, rhs)
@ -1003,6 +1004,23 @@ func (m *ClusterSecretsSpec) CloneMessageVT() proto.Message {
return m.CloneVT()
}
func (m *ImportedClusterSecretsSpec) CloneVT() *ImportedClusterSecretsSpec {
if m == nil {
return (*ImportedClusterSecretsSpec)(nil)
}
r := new(ImportedClusterSecretsSpec)
r.Data = m.Data
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields)
}
return r
}
func (m *ImportedClusterSecretsSpec) CloneMessageVT() proto.Message {
return m.CloneVT()
}
func (m *LoadBalancerConfigSpec) CloneVT() *LoadBalancerConfigSpec {
if m == nil {
return (*LoadBalancerConfigSpec)(nil)
@ -3912,6 +3930,9 @@ func (this *ClusterSecretsSpec) EqualVT(that *ClusterSecretsSpec) bool {
if string(this.Data) != string(that.Data) {
return false
}
if this.Imported != that.Imported {
return false
}
return string(this.unknownFields) == string(that.unknownFields)
}
@ -3922,6 +3943,25 @@ func (this *ClusterSecretsSpec) EqualMessageVT(thatMsg proto.Message) bool {
}
return this.EqualVT(that)
}
func (this *ImportedClusterSecretsSpec) EqualVT(that *ImportedClusterSecretsSpec) bool {
if this == that {
return true
} else if this == nil || that == nil {
return false
}
if this.Data != that.Data {
return false
}
return string(this.unknownFields) == string(that.unknownFields)
}
func (this *ImportedClusterSecretsSpec) EqualMessageVT(thatMsg proto.Message) bool {
that, ok := thatMsg.(*ImportedClusterSecretsSpec)
if !ok {
return false
}
return this.EqualVT(that)
}
func (this *LoadBalancerConfigSpec) EqualVT(that *LoadBalancerConfigSpec) bool {
if this == that {
return true
@ -8817,6 +8857,56 @@ func (m *ClusterSecretsSpec) MarshalToVT(dAtA []byte) (int, error) {
}
func (m *ClusterSecretsSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if m.Imported {
i--
if m.Imported {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x10
}
if len(m.Data) > 0 {
i -= len(m.Data)
copy(dAtA[i:], m.Data)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Data)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *ImportedClusterSecretsSpec) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ImportedClusterSecretsSpec) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *ImportedClusterSecretsSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
@ -13978,6 +14068,23 @@ func (m *ClusterBootstrapStatusSpec) SizeVT() (n int) {
}
func (m *ClusterSecretsSpec) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Data)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
if m.Imported {
n += 2
}
n += len(m.unknownFields)
return n
}
func (m *ImportedClusterSecretsSpec) SizeVT() (n int) {
if m == nil {
return 0
}
@ -22832,6 +22939,109 @@ func (m *ClusterSecretsSpec) UnmarshalVT(dAtA []byte) error {
m.Data = []byte{}
}
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Imported", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.Imported = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ImportedClusterSecretsSpec) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ImportedClusterSecretsSpec: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ImportedClusterSecretsSpec: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Data = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])

View File

@ -32,6 +32,7 @@ var UserManagedResourceTypes = []resource.Type{
omni.EtcdBackupS3ConfType,
omni.ExtensionsConfigurationType,
omni.MachineRequestSetType,
omni.ImportedClusterSecretsType,
omni.InfraMachineBMCConfigType,
omni.InfraMachineConfigType,
omni.NodeForceDestroyRequestType,

View File

@ -0,0 +1,65 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package omni
import (
"time"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/resource/meta"
"github.com/cosi-project/runtime/pkg/resource/protobuf"
"github.com/cosi-project/runtime/pkg/resource/typed"
"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets"
"gopkg.in/yaml.v3"
"github.com/siderolabs/omni/client/api/omni/specs"
"github.com/siderolabs/omni/client/pkg/omni/resources"
)
// NewImportedClusterSecrets creates new ImportedClusterSecrets state.
func NewImportedClusterSecrets(ns string, id resource.ID) *ImportedClusterSecrets {
return typed.NewResource[ImportedClusterSecretsSpec, ImportedClusterSecretsExtension](
resource.NewMetadata(ns, ImportedClusterSecretsType, id, resource.VersionUndefined),
protobuf.NewResourceSpec(&specs.ImportedClusterSecretsSpec{}),
)
}
// ImportedClusterSecretsType is the type of ImportedClusterSecrets resource.
//
// tsgen:ImportedClusterSecretsType
const ImportedClusterSecretsType = resource.Type("ImportedClusterSecrets.omni.sidero.dev")
// ImportedClusterSecrets resource describes imported cluster secrets.
type ImportedClusterSecrets = typed.Resource[ImportedClusterSecretsSpec, ImportedClusterSecretsExtension]
// ImportedClusterSecretsSpec wraps specs.ImportedClusterSecretsSpec.
type ImportedClusterSecretsSpec = protobuf.ResourceSpec[specs.ImportedClusterSecretsSpec, *specs.ImportedClusterSecretsSpec]
// ImportedClusterSecretsExtension providers auxiliary methods for ImportedClusterSecrets resource.
type ImportedClusterSecretsExtension struct{}
// ResourceDefinition implements [typed.Extension] interface.
func (ImportedClusterSecretsExtension) ResourceDefinition() meta.ResourceDefinitionSpec {
return meta.ResourceDefinitionSpec{
Type: ImportedClusterSecretsType,
Aliases: []resource.Type{},
DefaultNamespace: resources.DefaultNamespace,
PrintColumns: []meta.PrintColumn{},
}
}
// FromImportedSecretsToSecretsBundle converts the resource into generate.SecretsBundle resource.
func FromImportedSecretsToSecretsBundle(ics *ImportedClusterSecrets) (*secrets.Bundle, error) {
secretBundle := &secrets.Bundle{}
err := yaml.Unmarshal([]byte(ics.TypedSpec().Value.Data), secretBundle)
if err != nil {
return nil, err
}
secretBundle.Clock = secrets.NewFixedClock(time.Now())
return secretBundle, err
}

View File

@ -101,6 +101,10 @@ const (
// InfraProviderLabelPrefixFormat is the prefix of all labels which are managed by the infra providers.
InfraProviderLabelPrefixFormat = InfraProviderLabelPrefix + "/%s/"
// LabelClusterTainted is added to the ClusterStatus and is used to relay if the cluster secrets are sourced from ImportedClusterSecrets.
// tsgen:LabelClusterTainted
LabelClusterTainted = SystemLabelPrefix + "tainted"
)
const (

View File

@ -47,6 +47,7 @@ func init() {
registry.MustRegisterResource(FeaturesConfigType, &FeaturesConfig{})
registry.MustRegisterResource(ImagePullRequestType, &ImagePullRequest{})
registry.MustRegisterResource(ImagePullStatusType, &ImagePullStatus{})
registry.MustRegisterResource(ImportedClusterSecretsType, &ImportedClusterSecrets{})
registry.MustRegisterResource(InfraMachineBMCConfigType, &InfraMachineBMCConfig{})
registry.MustRegisterResource(InfraMachineConfigType, &InfraMachineConfig{})
registry.MustRegisterResource(InfraProviderCombinedStatusType, &InfraProviderCombinedStatus{})

View File

@ -663,6 +663,13 @@ func defineFeatureFlags() {
cmdConfig.Features.DisableControllerRuntimeCache,
"disable watch-based cache for controller-runtime (affects performance)",
)
rootCmd.Flags().BoolVar(
&cmdConfig.Features.EnableClusterImport,
"enable-cluster-import",
cmdConfig.Features.EnableClusterImport,
"enable cluster import feature.",
)
}
func defineDebugFlags() {

View File

@ -472,6 +472,11 @@ export type ClusterBootstrapStatusSpec = {
export type ClusterSecretsSpec = {
data?: Uint8Array
imported?: boolean
}
export type ImportedClusterSecretsSpec = {
data?: string
}
export type LoadBalancerConfigSpec = {

View File

@ -114,6 +114,7 @@ export const FeaturesConfigID = "features-config";
export const FeaturesConfigType = "FeaturesConfigs.omni.sidero.dev";
export const ImagePullRequestType = "ImagePullRequests.omni.sidero.dev";
export const ImagePullStatusType = "ImagePullStatuses.omni.sidero.dev";
export const ImportedClusterSecretsType = "ImportedClusterSecrets.omni.sidero.dev";
export const InfraMachineBMCConfigType = "InfraMachineBMCConfigs.omni.sidero.dev";
export const InfraMachineConfigType = "InfraMachineConfigs.omni.sidero.dev";
export const InfraProviderCombinedStatusType = "InfraProviderCombinedStatuses.omni.sidero.dev";
@ -142,6 +143,7 @@ export const LabelNoManualAllocation = "omni.sidero.dev/no-manual-allocation";
export const LabelIsManagedByStaticInfraProvider = "omni.sidero.dev/is-managed-by-static-infra-provider";
export const LabelMachinePendingAccept = "omni.sidero.dev/accept-pending";
export const InfraProviderLabelPrefix = "omni.sidero.dev/infra-provider";
export const LabelClusterTainted = "omni.sidero.dev/tainted";
export const MachineStatusLabelConnected = "omni.sidero.dev/connected";
export const MachineStatusLabelReadyToUse = "omni.sidero.dev/ready-to-use";
export const MachineStatusLabelDisconnected = "omni.sidero.dev/disconnected";

12
go.mod
View File

@ -61,7 +61,7 @@ require (
github.com/prometheus/client_golang v1.22.0
github.com/prometheus/common v0.63.0
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
github.com/siderolabs/crypto v0.6.0
github.com/siderolabs/crypto v0.6.3
github.com/siderolabs/discovery-api v0.1.6
github.com/siderolabs/discovery-client v0.1.11
github.com/siderolabs/discovery-service v1.0.10
@ -82,7 +82,7 @@ require (
github.com/siderolabs/omni/client v0.49.0
github.com/siderolabs/proto-codec v0.1.2
github.com/siderolabs/siderolink v0.3.15
github.com/siderolabs/talos/pkg/machinery v1.10.5
github.com/siderolabs/talos/pkg/machinery v1.11.0-alpha.3.0.20250714094650-da5a4449f1a9
github.com/siderolabs/tcpproxy v0.1.0 // indirect
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.9.1
@ -105,7 +105,7 @@ require (
golang.org/x/tools v0.33.0
golang.zx2c4.com/wireguard v0.0.0-20250505131008-436f7fdc1670
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
google.golang.org/grpc v1.72.0
google.golang.org/grpc v1.73.0
google.golang.org/protobuf v1.36.6
gopkg.in/yaml.v3 v3.0.3
k8s.io/api v0.34.0-alpha.0
@ -189,7 +189,7 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/jsimonetti/rtnetlink/v2 v2.0.3 // indirect
github.com/jsimonetti/rtnetlink/v2 v2.0.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/jxskiss/base62 v1.1.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
@ -260,8 +260,8 @@ require (
golang.org/x/term v0.32.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect

32
go.sum
View File

@ -87,8 +87,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cevatbarisyilmaz/ara v0.0.4 h1:SGH10hXpBJhhTlObuZzTuFn1rrdmjQImITXnZVPSodc=
github.com/cevatbarisyilmaz/ara v0.0.4/go.mod h1:BfFOxnUd6Mj6xmcvRxHN3Sr21Z1T3U2MYkYOmoQe4Ts=
github.com/cilium/ebpf v0.17.3 h1:FnP4r16PWYSE4ux6zN+//jMcW4nMVRvuTLVTvCjyyjg=
github.com/cilium/ebpf v0.17.3/go.mod h1:G5EDHij8yiLzaqn0WjyfJHvRa+3aDlReIaLVRMvOyJk=
github.com/cilium/ebpf v0.19.0 h1:Ro/rE64RmFBeA9FGjcTc+KmCeY6jXmryu6FfnzPRIao=
github.com/cilium/ebpf v0.19.0/go.mod h1:fLCgMo3l8tZmAdM3B2XqdFzXBpwkcSTroaVqN08OWVY=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
@ -290,8 +290,8 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/jsimonetti/rtnetlink/v2 v2.0.3 h1:Jcp7GTnTPepoUAJ9+LhTa7ZiebvNS56T1GtlEUaPNFE=
github.com/jsimonetti/rtnetlink/v2 v2.0.3/go.mod h1:atIkksp/9fqtf6rpAw45JnttnP2gtuH9X88WPfWfS9A=
github.com/jsimonetti/rtnetlink/v2 v2.0.5 h1:l5S9iedrSW4thUfgiU+Hzsnk1cOR0upGD5ttt6mirHw=
github.com/jsimonetti/rtnetlink/v2 v2.0.5/go.mod h1:9yTlq3Ojr1rbmh/Y5L30/KIojpFhTRph2xKeZ+y+Pic=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
@ -405,8 +405,8 @@ github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb
github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/siderolabs/crypto v0.6.0 h1:s33hNOneGhlxCI3fLKj2hgopeJkeRO7UYo3KL0HNVu4=
github.com/siderolabs/crypto v0.6.0/go.mod h1:7RHC7eUKBx6RLS2lDaNXrQ83zY9iPH/aQSTxk1I4/j4=
github.com/siderolabs/crypto v0.6.3 h1:9eGHzAJQg7FvPcjVANLQKnepc0nrl5IkLJ3FxhMvsQw=
github.com/siderolabs/crypto v0.6.3/go.mod h1:LEhGuXlvwElMgh+rYjCFw6JgfOgyaC+sqsl/YwWU+EM=
github.com/siderolabs/discovery-api v0.1.6 h1:/LhsF1ytqFEfWwV0UKfUgn90k9fk5+rhYMJ9yeUB2yc=
github.com/siderolabs/discovery-api v0.1.6/go.mod h1:s5CnTyRMGid/vJNSJs8Jw9I4tnKHu/2SGqP2ytTaePQ=
github.com/siderolabs/discovery-client v0.1.11 h1:Au+7QZ+CIB6g4C7ZCC4m5Ai5Uso1g/I3/E4bSUElzF8=
@ -451,8 +451,8 @@ github.com/siderolabs/protoenc v0.2.2 h1:vVQDrTjV+QSOiroWTca6h2Sn5XWYk7VSUPav5J0
github.com/siderolabs/protoenc v0.2.2/go.mod h1:gtkHkjSCFEceXUHUzKDpnuvXu1mab9D3pVxTnQN+z+o=
github.com/siderolabs/siderolink v0.3.15 h1:WSsgKQGJY/ObIKjTcYYGEaGfRMyox+r/Ft+9lIgJqOI=
github.com/siderolabs/siderolink v0.3.15/go.mod h1:iWdlsHji90zotgDg4+a2zJL2ZMNJckQ8/VwqR39ThBM=
github.com/siderolabs/talos/pkg/machinery v1.10.5 h1:R0ZSf9OrHIQ70+LEpQVK/KVCq3E6sUi/OpIjLDVH3Sk=
github.com/siderolabs/talos/pkg/machinery v1.10.5/go.mod h1:GxGnHH6gtX3J9s713+UbKvE9rLnlbYLv+Yn4rqD9Jh0=
github.com/siderolabs/talos/pkg/machinery v1.11.0-alpha.3.0.20250714094650-da5a4449f1a9 h1:Eb9Jz9UPjoImr170FzeV3wR0x9GpCNpMGTdPTfXQ62M=
github.com/siderolabs/talos/pkg/machinery v1.11.0-alpha.3.0.20250714094650-da5a4449f1a9/go.mod h1:9k/rwITuBS1fZsZ4+uzA4zyKQXK9pV7bcVz+FQIUnEw=
github.com/siderolabs/tcpproxy v0.1.0 h1:IbkS9vRhjMOscc1US3M5P1RnsGKFgB6U5IzUk+4WkKA=
github.com/siderolabs/tcpproxy v0.1.0/go.mod h1:onn6CPPj/w1UNqQ0U97oRPF0CqbrgEApYCw4P9IiCW8=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@ -543,8 +543,8 @@ go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI=
@ -694,18 +694,18 @@ google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9 h1:WvBuA5rjZx9SNIzgcU53OohgZy6lKSus++uY4xLaWKc=
google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:W3S/3np0/dPWsWLi1h/UymYctGXaGBM2StwzD0y140U=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 h1:IkAfh6J/yllPtpYFU0zZN1hUPYdT0ogkBT/9hMxHjvg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -207,6 +207,7 @@ features:
enableTalosPreReleaseVersions: ${ENABLE_TALOS_PRERELEASE_VERSIONS}
enableConfigDataCompression: true
enableBreakGlassConfigs: true
enableClusterImport: true
disableControllerRuntimeCache: false" > ${OMNI_CONFIG}
if [[ "${RUN_TALEMU_TESTS:-false}" == "true" ]]; then
@ -398,6 +399,7 @@ if [ "${INTEGRATION_RUN_E2E_TEST:-true}" == "true" ]; then
--audit-log-dir ${TEST_OUTPUTS_DIR}/audit-log \
--config-data-compression-enabled \
--enable-talos-pre-release-versions="${ENABLE_TALOS_PRERELEASE_VERSIONS}" \
--enable-cluster-import \
"${REGISTRY_MIRROR_FLAGS[@]}"&
# Run the e2e test.

View File

@ -17,6 +17,7 @@ import (
"github.com/siderolabs/omni/client/pkg/omni/resources/omni"
"github.com/siderolabs/omni/internal/backend/runtime"
"github.com/siderolabs/omni/internal/backend/runtime/kubernetes"
"github.com/siderolabs/omni/internal/backend/runtime/omni/controllers/helpers"
)
// ClusterController manages Cluster resource lifecycle.
@ -94,6 +95,7 @@ func NewClusterController() *ClusterController {
cleanup.HasNoOutputs[*omni.ClusterMachineConfig](func(cluster *omni.Cluster) state.ListOption {
return state.WithLabelQuery(resource.LabelEqual(omni.LabelCluster, cluster.Metadata().ID()))
}),
&helpers.SameIDHandler[*omni.Cluster, *omni.ImportedClusterSecrets]{},
),
},
},

View File

@ -376,6 +376,8 @@ func (suite *ClusterMachineConfigSuite) testConfigEncodingStabilityFrom(talosVer
case "1.9.1":
fallthrough
case "1.10.1":
fallthrough
case "1.11.1":
default:
suite.T().Fatalf("untested initial version: %s", initialVersion)
}

View File

@ -73,6 +73,11 @@ func NewClusterStatusController(embeddedDiscoveryServiceEnabled bool) *ClusterSt
return err
}
clusterSecrets, err := safe.ReaderGetByID[*omni.ClusterSecrets](ctx, r, cluster.Metadata().ID())
if err != nil && !state.IsNotFoundError(err) {
return err
}
cpStatusReady := false
clusterIsAvailable := false
@ -167,6 +172,12 @@ func NewClusterStatusController(embeddedDiscoveryServiceEnabled bool) *ClusterSt
helpers.CopyUserLabels(clusterStatus, cluster.Metadata().Labels().Raw())
if clusterSecrets != nil && clusterSecrets.TypedSpec().Value.Imported {
clusterStatus.Metadata().Labels().Set(omni.LabelClusterTainted, "")
} else {
clusterStatus.Metadata().Labels().Delete(omni.LabelClusterTainted)
}
return nil
},
},
@ -179,6 +190,9 @@ func NewClusterStatusController(embeddedDiscoveryServiceEnabled bool) *ClusterSt
qtransform.WithExtraMappedInput(
mappers.MapByClusterLabel[*omni.ControlPlaneStatus, *omni.Cluster](),
),
qtransform.WithExtraMappedInput(
qtransform.MapperSameID[*omni.ClusterSecrets, *omni.Cluster](),
),
qtransform.WithIgnoreTeardownUntil(), // keep ClusterStatus alive until every other controller is done with Cluster
)
}

View File

@ -0,0 +1,3 @@
cluster
id: rRxLgAjUwkp17VYlg5XSbTfKMpV4nn-i5yj-ZmSsxfM=
secret: tad0uMK9YeZBiSaN8+pMRH53ftmYl3Sdjv9Yko1f8Dc=

View File

@ -0,0 +1,15 @@
cluster:
id: rRxLgAjUwkp17VYlg5XSbTfKMpV4nn-i5yj-ZmSsxfM=
secrets:
bootstraptoken: 78kycc.kb6cn9nk46sqv0zb
certs:
etcd:
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmakNDQVNPZ0F3SUJBZ0lRRlgra1BBRGlINnZoTEJDRkdOMlMyekFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEkxTURjd09UQTVNakl3TTFvWERUTTFNRGN3TnpBNU1qSXdNMW93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkNKVCtib2J0VUY2CmlCMmJWbm5PVnIzWkN0dkVPK1A5Q29oQ2NlU3JDc3BxV0FHRWEwTUM0dVFpWkRKbU4raGFUK3cwTXZZMXhsR1kKSzRBTmxzOVczM3VqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVOVJvRGIrWVVBUEM1Cmd1MXdxNkFuQkNvcUFmUXdDZ1lJS29aSXpqMEVBd0lEU1FBd1JnSWhBS3VJQUcrY21LcFprUVQzRDFYNk4zVEMKSmk5aVdGMWJWWm1SUmJXYm9jZTVBaUVBbCtxRTdwUDlTOHVuNS9ZZmYwZktNMkpKSG53dThOQU9kQWFFdDVMcwpRbG89Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
k8s:
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRUHVUNktmTkpiUEp1Uk5rdmZiOFQ0akFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSTFNRGN3T1RBNU1qSXdNMW9YRFRNMU1EY3dOekE1TWpJdwpNMW93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCR0YvVEFaWTlCSUtYU3J5dlZZSE9wdEpRaUFkZzI4OEtsQ1pMMUQ3T3VVQ29ZM2xrVVB4azZzZUNGaE0KZ20vMVNnWHo1Q1htTmpTRFREcEdqdXRwNWlhallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVVhYWJ1cVhNcktwOGVzcUJ3V1dUWkZ5cnk5Y0F3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUs2eEpOVUkKU05xaklLZjBHRHAvVTc4aTBwaDZVRURVekVPN0xCazhzNkdjQWlBS015emtVMER3aGlQMC93ajdielN3ais4bQpPNWxURlg2bFJPU3ByN01rTWc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU01OGtaYURTeVl5WGtRajZJQUdPZ1ZtMFFWZFJIZ2E1QVpyVTQ0Z2VHYk5vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFWVg5TUJsajBFZ3BkS3ZLOVZnYzZtMGxDSUIyRGJ6d3FVSmt2VVBzNjVRS2hqZVdSUS9HVApxeDRJV0V5Q2IvVktCZlBrSmVZMk5JTk1Pa2FPNjJubUpnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
k8sserviceaccount:
key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS0FJQkFBS0NBZ0VBNHBhTVZNVDBVU0s0T21zdDc2MTBhbTVzTXcyK1NETEFsVkpmbnZqbHg1blNaTXQ2CmNLM1RvYy9SNWQ5WEk3S1pKcWk5Z3daZlZlRk9mN0VmdklWcG8zN3R6cUEzbXBlSWcxNUx3N3owa2loQjlJejgKa21iaXpoV0duQnNOUU0xS25kS2VSN1lvcTNCUlpVTHFoVm9MMDBLSDFqaWNVdjNUMkMra2FFMVlwZ0tUSFJucAp2Nit4K2hKcGJTN3psZ2d6RUNXK2w1d1UwMHZPSHJDNXoxZnNzZGQ2QmFwNFJwUE9SVTVGdDhnYm80UlhtSHY0CnBHQWFIS2JnKy92em5tQ25HeFdTc0dWVjNyY1BvYjMyQ0NjelozakhGeVJVUERhWXVWUkxrdW9sL0JBUDZhRUQKMHFScUhzeHcwK3RqTFpMU1I4TktNNjRjSjBHVXlBRnF2eXAzNXdFYSt2bUpxdUZhZGg1MFlvSXk1RkNoQ3RDYQoxZVdTTVZlTm1TM2Mza0xsbVIyT1dZaG9OZi9oWU5sQ3hxVlZLYVJuWFR2ZlczWTdaVXRWMHkyNVFITHYwOFRDCmFyV3owU1FXdFdsZUZ6THltVHo3dWhBaDFhaGNEWDJ0UHpleDg1eXEyQk9KdU4rejVjVHZKMVlndHRjV29tUkoKMS9FUGlsaEdHMnlEVG9HQzBWM2ZKa25hTUdicVJOcnZzb0dDa0s3dkVWb2JFY2c5cU1CTFFyVkVpaFFVMHlJQgpOTmJCU05VMWFYVEppY0hRN2MybStxOWN2OUlQYWFsUktpY3VPMVVyTVptQUdxbXdvZ3U1VkkxNHFtZVFzZVlaCjJtOHZtS2M2MittT1J5bnVLWXozL0hsUE10R3ZHaXQ5aTh6eG1uNmlmdDFUQ2JFQVF5MHA5U1cvRklNQ0F3RUEKQVFLQ0FnQWFoRDdBN3RtZW94OEhLeUxSa1MxMkJSMGhibUxOeFM2M2FzL281VHpTdW9RZUtwZldGdW1VM3FLMApNWXBia1p1TnBDS2xjam4yN1dxSDAvMGdUVWFiRFJBY1piQ01KVjZpN1FhVnpnZWJFUjRDMWZyNjBSS0t4b2NkCnZxYXk1ak5zdThpdElMcXFzWGE5RUhNc2p1aWlYUDlUaVFWMlN1RWZSQmdMNHIxVWxDbU9Oc21kbHB5UDVOYTAKb2RGOHhkSGYrbUxQRUVONXBMM201b3lnSUt5QTlYUUF0TDNsbUllRG9kRFQzSldyY2FIa3BPRm9yeHh2TFBKWQpXdGhjT1BobFdZVjBvaTlGNUl0dVJMSkZxdnkvaDZsWTRuWC9JKzZFaGNKZ1c0bDljWTNETEFZc0FQU3dUUUdKCk0xdEVhcEcwTnp6NFJsQmlJYkVkSk5sT3JOUWlHcUYxUFk2cHRsazduQ1ZPbXRiaElENVFpNU4rZ1ZxVkxlak4KbW44dnBPMWRscjYwTGsyRkIrMmZQY3R5MlVoZWU3NHFHYUFaNW1ndDVzZExSeTkzQUVVVWdkVWF4Z0pwSjZLNQpYWVFPeHFIQnUyUFg1YU1UZ0twc2M4SG1pbzFVZ1BXWFF5S3ROb0tRbHpKNEtmK29UY3pJV2hWT0NJU1BrNUVpCmI3MmhsRFhKT1puWEE3cUxETEZtNWVQb0pkOWdyRXczcUhQZnltZHNmZmsyUlJRb0RqblN0S0xYOVhXZTJmRGEKaStRU0pzdlI3cEROM0lUcklQS09rZDZHZEs0aVBVdVFhaUppMU8wcUlBVTUxOGtYdnRxOGt1VTR5cW5jUlgrZgpYcEtIUWF4RmpYVThnZHdCaTMyN1BPYlFJLzU0blQzUGZzV05sWWNpK2xXR2dqcHkrUUtDQVFFQTZvbXh4L1AwCjBoNFMxeWlXdWtNSzBubCtKYU9Odis3Z1ZhUWZ3UkNxWWFUQzF4cXQyaHNacEx2aEVob1M2TXlkbTF1MDNXM0YKRFM3RThHUDR3Y211REY0bUJCQzNKaGxFbkd3SGYxdUFXUnEzVU1Qdks1NjFxL0p1YzhtakFRditjK1lYYlQ2UgpWQnVKV212aTJ1Tm9oK2dIVGhyMk5vMHJsZFZDMWh1SFNoNEVhSFRkSElvai9ZbitWd0h1Z2Y4NVByU2IvK2tDClBQcWxPTW0rNWpHdTBibUtxcHJPTTNCcENpQ2dyLzJSUE1kTFFLL2dnOW9uTEZJVHMvM2dnL1lBNkhUMGJSN2QKUkZQYWR0R2lXYk11cVhiMjhWNXJQVjNZUnJxRitOQytXb2dPQTRUcXgzYU9YbjVLTEVaNzF2T040MnpYdi9XMQoramZEVlpJRXdYS3NTUUtDQVFFQTkxS2ZCdmFOSHF6dEo0V21iTkFYTk5idC9PU3Y0Skx0SHdUZ3hlQmdJdm5qCnRPQmE0d2lGeE1DZlNsMkpSVXZqZDhJMlowaE1BaU9xRGFIczVjY1RzL1NhMENVV3hyQ0dCUDM1L2xManFwUGMKVi9Jd0ZPVmF4bVFrcGdwMEQyWWVWdGhXcmpUWWYyY09rVXdRTmdSMzFZdlVCTnF0N2lqNlpzSW9ONXRhem9uSgpaQkIxalZOTExFTEQ4Wm9WVVE2WTJ2WVZRK244eHBYeWdtenR1aktVSmpTWllONFlRUWRsanJWZTh3R0s2RmRNCjJwMFFuTjlaKzU0VFp6SE1OWkVWOFozbUVIY0psTlBTOE9jSWVFUm41b29yZEpTWGVGeFgxcmRxV0Zvak51dzcKd2JNNWd6dHArRmpLK0EyNG1RL0ZGYkk3WFZtMXorUzg0R2ZMakxTQ2F3S0NBUUVBajNXd0dBV0NEL0F6U0FaYwp4QXYwRjdBVzJFRUZtSXd1RGxSNDArZzB2OHMvSHNJRDYzQStMRVI3dEUzY21TZG5sRHJ4RTZ4c0p0Y2Z3WWIxCkJ0d3RLUVdCcldUb0VsYk1YLzI0VEUrVTMydjNDMkQ5NzZtQnFHNSszelpNRFh6ZnBOYnVKM1ZwQVpCaVlMdXoKSkg2TFZ1NDNZYkFlUUZuemVnL2JkUW1icEZ0ZUNPTEt5UVU2WklBKzRjdWRyMGlGSkhUbkl3N012cTMxMkJtWApPa2pUalJjMzJZa2RiZHRwZExkbWNwL2djZFBabFBTL21RY2NoUUNqYXFwMDVXTFpSVmNjbDQ2VWU1SHJCRmpRClBKdmNnKzN2dU00dlBIY2xyb1d6SXZIVUxaNGhMRWZtTUNHMWpka2oxNWM1Y3M3QlVJWW9KaFBPdndIUzZvbUoKZlNaK2VRS0NBUUJKSk1BdldQOUhVVEVaL1NiSkM0bXhjTmNWY2JTcUlBbk1vSzZ4RnJpWDMzdCtaTk84VFNyeQprMTBJcXowTHAzUHdXUm1wMWZIVXVDTjB3S3pGRCtrOTBWdHZyMmhhL3AzRUlEQ3RER3FVYWdKQ2FEZmNGakNRCmQ5RjI0YVNOWVZBYnN3Ti9wZFZaYUdzZ2dYUlI1V1JqWFdVb3dsdXFFYWhzZDROWlhyS3VYb1dXK0Y4cm1yU2kKdEdRcXNiMFlLYzcvQXNRclA2b29PUFJ0cWpWc1djVUN2NCtVM0ZvajhVSVJ3SVlDTERTZW5pTDJqSGo3Uy9yYQp0VmRicjVpTFJ3dE1WN3hRcGtQSkpoUStkclZFakVhR0lkclVNWlhTWE0wRmpWMEFJRGhGNS91TVA2c0VxcStlCmFQUXVCRERSNDU0UDJwUS8rV1lSdzc0d1I4SWxMTVZkQW9JQkFDc2FWRzAxb3Jzei8vTkUwWnFzL0VXNmtEUXAKb21sbW5mRXZjOUpnM3N3bitHQVhkcXVHbllkTFpGYnpJSFdTbjNMSzlRVDgzbXd2ZXJ0Y0Y2eWxidllZMktsRwo0blBpZGF2ajI4c1kvbnRVU3RFenFqc0hZbEVST1MrcUJMcnRBQURyZmtOR3BrcWQrOGx1WmM1U3RjanBLaGRECkJYcWVVQmVhZG5BTExtdkZxeFc1QVpNd3lWeGM2NlRrVUtRUzJobVRqaWhFeDg5WHZqNXIzZG9XNHMrbTYrbjMKcEhrbjJqeXZTSFppMlVpa0dJYVN5ZXh3TG9zSUd3c3NKZmZOTlBkL3A2TFh4aG1Ja3dJVW5WcDN5c3ZpUVNvRgpCTTdrVDArNWFZQXEzbS9kYUhFUmJtbzlEWk1Wa2dza1RDbUdqa1hXeXB2WENaajkxcTgxc2dBVGlQYz0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K
os:
crt: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJRDJhaEtPVkxmUEZlRWo2Y2RnS20vcXpVQmY5bjZUbUpmSFJmYUhiZ0JvcAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K
key: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBeEErVWl1OWtmbjV2RVZReC96ekp2REFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qVXdOekE1TURreU1qQXpXaGNOTXpVd056QTNNRGt5TWpBeldqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUptNzhzalJla2ZKYklhNGJzNDl4QkV1WC9qbW4rajNsdDJNCmZuMkxKa2JjbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRlBVR1ZPS1Y3UHVMbSs2agppZ2tOdnVDYUZnbUZNQVVHQXl0bGNBTkJBQm5RV2xpNzEwdi9raFlCUStGeGZ2NEJ2dmladVNDYy94c3dXQTgwCjRsdU1GeVRwUzcvdHdnMUdLb1hoR0dqeEY2dy9CMTE2SS9YL0R2d3FYRDJTMWd3PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==

View File

@ -0,0 +1,23 @@
cluster:
id: rRxLgAjUwkp17VYlg5XSbTfKMpV4nn-i5yj-ZmSsxfM=
secret: tad0uMK9YeZBiSaN8+pMRH53ftmYl3Sdjv9Yko1f8Dc=
secrets:
bootstraptoken: 78kycc.kb6cn9nk46sqv0zb
secretboxencryptionsecret: QNMWU1T61NEW+AOErxYQrzdhMHWeuBQvgncYdocMnh8=
trustdinfo:
token: gxcmg1.9wa1x9n1vb27x4an
certs:
etcd:
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmakNDQVNPZ0F3SUJBZ0lRRlgra1BBRGlINnZoTEJDRkdOMlMyekFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEkxTURjd09UQTVNakl3TTFvWERUTTFNRGN3TnpBNU1qSXdNMW93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkNKVCtib2J0VUY2CmlCMmJWbm5PVnIzWkN0dkVPK1A5Q29oQ2NlU3JDc3BxV0FHRWEwTUM0dVFpWkRKbU4raGFUK3cwTXZZMXhsR1kKSzRBTmxzOVczM3VqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVOVJvRGIrWVVBUEM1Cmd1MXdxNkFuQkNvcUFmUXdDZ1lJS29aSXpqMEVBd0lEU1FBd1JnSWhBS3VJQUcrY21LcFprUVQzRDFYNk4zVEMKSmk5aVdGMWJWWm1SUmJXYm9jZTVBaUVBbCtxRTdwUDlTOHVuNS9ZZmYwZktNMkpKSG53dThOQU9kQWFFdDVMcwpRbG89Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSVBiaEp6cG5UTzRmK0xyZmFhZlJmU1ZaY28xN3FXVFlYUmhSYzR6R2NwcVJvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSWxQNXVodTFRWHFJSFp0V2VjNVd2ZGtLMjhRNzQvMEtpRUp4NUtzS3ltcFlBWVJyUXdMaQo1Q0prTW1ZMzZGcFA3RFF5OWpYR1VaZ3JnQTJXejFiZmV3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
k8s:
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRUHVUNktmTkpiUEp1Uk5rdmZiOFQ0akFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSTFNRGN3T1RBNU1qSXdNMW9YRFRNMU1EY3dOekE1TWpJdwpNMW93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCR0YvVEFaWTlCSUtYU3J5dlZZSE9wdEpRaUFkZzI4OEtsQ1pMMUQ3T3VVQ29ZM2xrVVB4azZzZUNGaE0KZ20vMVNnWHo1Q1htTmpTRFREcEdqdXRwNWlhallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVVhYWJ1cVhNcktwOGVzcUJ3V1dUWkZ5cnk5Y0F3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUs2eEpOVUkKU05xaklLZjBHRHAvVTc4aTBwaDZVRURVekVPN0xCazhzNkdjQWlBS015emtVMER3aGlQMC93ajdielN3ais4bQpPNWxURlg2bFJPU3ByN01rTWc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU01OGtaYURTeVl5WGtRajZJQUdPZ1ZtMFFWZFJIZ2E1QVpyVTQ0Z2VHYk5vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFWVg5TUJsajBFZ3BkS3ZLOVZnYzZtMGxDSUIyRGJ6d3FVSmt2VVBzNjVRS2hqZVdSUS9HVApxeDRJV0V5Q2IvVktCZlBrSmVZMk5JTk1Pa2FPNjJubUpnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
k8saggregator:
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYekNDQVFXZ0F3SUJBZ0lRWFVFaStrTG16ckcvazZRNUdyMzNyREFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJMU1EY3dPVEE1TWpJd00xb1hEVE0xTURjd056QTVNakl3TTFvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRm9ZSm5kOTExbzgxQnRINWRRREllQm5DSFN5cFdCVHdXZlg2RXNHZ05oUDcyb1NBMWlQCnRYNHAwVG16bFNvWmFuV0ZHVkNMTHgxNFNWUHNhUk1nQ2ttallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVViT2lQN3RwbW1YcnplM2xLRkVTdGNFTjZZRnd3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnClJ1UjRVL3JXZjk5YVVENnYzblhQZjVVYlBBZjhSS3VHQzZkeWxtdFJDRFlDSVFEYmtLdCt0TTJYSVhyTmIrVWoKL1BUR0RvYzJWZ1I2QUtZSTY2ZTJxQ0FxUFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUtlSmdYaDN6S3NSMUxMZTJHQzJ2SVBTN2YrVkk4dkJwTlVVU3R3eHBxQ2RvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFV2hnbWQzM1hXanpVRzBmbDFBTWg0R2NJZExLbFlGUEJaOWZvU3dhQTJFL3ZhaElEV0krMQpmaW5ST2JPVktobHFkWVVaVUlzdkhYaEpVK3hwRXlBS1NRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
k8sserviceaccount:
key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS0FJQkFBS0NBZ0VBNHBhTVZNVDBVU0s0T21zdDc2MTBhbTVzTXcyK1NETEFsVkpmbnZqbHg1blNaTXQ2CmNLM1RvYy9SNWQ5WEk3S1pKcWk5Z3daZlZlRk9mN0VmdklWcG8zN3R6cUEzbXBlSWcxNUx3N3owa2loQjlJejgKa21iaXpoV0duQnNOUU0xS25kS2VSN1lvcTNCUlpVTHFoVm9MMDBLSDFqaWNVdjNUMkMra2FFMVlwZ0tUSFJucAp2Nit4K2hKcGJTN3psZ2d6RUNXK2w1d1UwMHZPSHJDNXoxZnNzZGQ2QmFwNFJwUE9SVTVGdDhnYm80UlhtSHY0CnBHQWFIS2JnKy92em5tQ25HeFdTc0dWVjNyY1BvYjMyQ0NjelozakhGeVJVUERhWXVWUkxrdW9sL0JBUDZhRUQKMHFScUhzeHcwK3RqTFpMU1I4TktNNjRjSjBHVXlBRnF2eXAzNXdFYSt2bUpxdUZhZGg1MFlvSXk1RkNoQ3RDYQoxZVdTTVZlTm1TM2Mza0xsbVIyT1dZaG9OZi9oWU5sQ3hxVlZLYVJuWFR2ZlczWTdaVXRWMHkyNVFITHYwOFRDCmFyV3owU1FXdFdsZUZ6THltVHo3dWhBaDFhaGNEWDJ0UHpleDg1eXEyQk9KdU4rejVjVHZKMVlndHRjV29tUkoKMS9FUGlsaEdHMnlEVG9HQzBWM2ZKa25hTUdicVJOcnZzb0dDa0s3dkVWb2JFY2c5cU1CTFFyVkVpaFFVMHlJQgpOTmJCU05VMWFYVEppY0hRN2MybStxOWN2OUlQYWFsUktpY3VPMVVyTVptQUdxbXdvZ3U1VkkxNHFtZVFzZVlaCjJtOHZtS2M2MittT1J5bnVLWXozL0hsUE10R3ZHaXQ5aTh6eG1uNmlmdDFUQ2JFQVF5MHA5U1cvRklNQ0F3RUEKQVFLQ0FnQWFoRDdBN3RtZW94OEhLeUxSa1MxMkJSMGhibUxOeFM2M2FzL281VHpTdW9RZUtwZldGdW1VM3FLMApNWXBia1p1TnBDS2xjam4yN1dxSDAvMGdUVWFiRFJBY1piQ01KVjZpN1FhVnpnZWJFUjRDMWZyNjBSS0t4b2NkCnZxYXk1ak5zdThpdElMcXFzWGE5RUhNc2p1aWlYUDlUaVFWMlN1RWZSQmdMNHIxVWxDbU9Oc21kbHB5UDVOYTAKb2RGOHhkSGYrbUxQRUVONXBMM201b3lnSUt5QTlYUUF0TDNsbUllRG9kRFQzSldyY2FIa3BPRm9yeHh2TFBKWQpXdGhjT1BobFdZVjBvaTlGNUl0dVJMSkZxdnkvaDZsWTRuWC9JKzZFaGNKZ1c0bDljWTNETEFZc0FQU3dUUUdKCk0xdEVhcEcwTnp6NFJsQmlJYkVkSk5sT3JOUWlHcUYxUFk2cHRsazduQ1ZPbXRiaElENVFpNU4rZ1ZxVkxlak4KbW44dnBPMWRscjYwTGsyRkIrMmZQY3R5MlVoZWU3NHFHYUFaNW1ndDVzZExSeTkzQUVVVWdkVWF4Z0pwSjZLNQpYWVFPeHFIQnUyUFg1YU1UZ0twc2M4SG1pbzFVZ1BXWFF5S3ROb0tRbHpKNEtmK29UY3pJV2hWT0NJU1BrNUVpCmI3MmhsRFhKT1puWEE3cUxETEZtNWVQb0pkOWdyRXczcUhQZnltZHNmZmsyUlJRb0RqblN0S0xYOVhXZTJmRGEKaStRU0pzdlI3cEROM0lUcklQS09rZDZHZEs0aVBVdVFhaUppMU8wcUlBVTUxOGtYdnRxOGt1VTR5cW5jUlgrZgpYcEtIUWF4RmpYVThnZHdCaTMyN1BPYlFJLzU0blQzUGZzV05sWWNpK2xXR2dqcHkrUUtDQVFFQTZvbXh4L1AwCjBoNFMxeWlXdWtNSzBubCtKYU9Odis3Z1ZhUWZ3UkNxWWFUQzF4cXQyaHNacEx2aEVob1M2TXlkbTF1MDNXM0YKRFM3RThHUDR3Y211REY0bUJCQzNKaGxFbkd3SGYxdUFXUnEzVU1Qdks1NjFxL0p1YzhtakFRditjK1lYYlQ2UgpWQnVKV212aTJ1Tm9oK2dIVGhyMk5vMHJsZFZDMWh1SFNoNEVhSFRkSElvai9ZbitWd0h1Z2Y4NVByU2IvK2tDClBQcWxPTW0rNWpHdTBibUtxcHJPTTNCcENpQ2dyLzJSUE1kTFFLL2dnOW9uTEZJVHMvM2dnL1lBNkhUMGJSN2QKUkZQYWR0R2lXYk11cVhiMjhWNXJQVjNZUnJxRitOQytXb2dPQTRUcXgzYU9YbjVLTEVaNzF2T040MnpYdi9XMQoramZEVlpJRXdYS3NTUUtDQVFFQTkxS2ZCdmFOSHF6dEo0V21iTkFYTk5idC9PU3Y0Skx0SHdUZ3hlQmdJdm5qCnRPQmE0d2lGeE1DZlNsMkpSVXZqZDhJMlowaE1BaU9xRGFIczVjY1RzL1NhMENVV3hyQ0dCUDM1L2xManFwUGMKVi9Jd0ZPVmF4bVFrcGdwMEQyWWVWdGhXcmpUWWYyY09rVXdRTmdSMzFZdlVCTnF0N2lqNlpzSW9ONXRhem9uSgpaQkIxalZOTExFTEQ4Wm9WVVE2WTJ2WVZRK244eHBYeWdtenR1aktVSmpTWllONFlRUWRsanJWZTh3R0s2RmRNCjJwMFFuTjlaKzU0VFp6SE1OWkVWOFozbUVIY0psTlBTOE9jSWVFUm41b29yZEpTWGVGeFgxcmRxV0Zvak51dzcKd2JNNWd6dHArRmpLK0EyNG1RL0ZGYkk3WFZtMXorUzg0R2ZMakxTQ2F3S0NBUUVBajNXd0dBV0NEL0F6U0FaYwp4QXYwRjdBVzJFRUZtSXd1RGxSNDArZzB2OHMvSHNJRDYzQStMRVI3dEUzY21TZG5sRHJ4RTZ4c0p0Y2Z3WWIxCkJ0d3RLUVdCcldUb0VsYk1YLzI0VEUrVTMydjNDMkQ5NzZtQnFHNSszelpNRFh6ZnBOYnVKM1ZwQVpCaVlMdXoKSkg2TFZ1NDNZYkFlUUZuemVnL2JkUW1icEZ0ZUNPTEt5UVU2WklBKzRjdWRyMGlGSkhUbkl3N012cTMxMkJtWApPa2pUalJjMzJZa2RiZHRwZExkbWNwL2djZFBabFBTL21RY2NoUUNqYXFwMDVXTFpSVmNjbDQ2VWU1SHJCRmpRClBKdmNnKzN2dU00dlBIY2xyb1d6SXZIVUxaNGhMRWZtTUNHMWpka2oxNWM1Y3M3QlVJWW9KaFBPdndIUzZvbUoKZlNaK2VRS0NBUUJKSk1BdldQOUhVVEVaL1NiSkM0bXhjTmNWY2JTcUlBbk1vSzZ4RnJpWDMzdCtaTk84VFNyeQprMTBJcXowTHAzUHdXUm1wMWZIVXVDTjB3S3pGRCtrOTBWdHZyMmhhL3AzRUlEQ3RER3FVYWdKQ2FEZmNGakNRCmQ5RjI0YVNOWVZBYnN3Ti9wZFZaYUdzZ2dYUlI1V1JqWFdVb3dsdXFFYWhzZDROWlhyS3VYb1dXK0Y4cm1yU2kKdEdRcXNiMFlLYzcvQXNRclA2b29PUFJ0cWpWc1djVUN2NCtVM0ZvajhVSVJ3SVlDTERTZW5pTDJqSGo3Uy9yYQp0VmRicjVpTFJ3dE1WN3hRcGtQSkpoUStkclZFakVhR0lkclVNWlhTWE0wRmpWMEFJRGhGNS91TVA2c0VxcStlCmFQUXVCRERSNDU0UDJwUS8rV1lSdzc0d1I4SWxMTVZkQW9JQkFDc2FWRzAxb3Jzei8vTkUwWnFzL0VXNmtEUXAKb21sbW5mRXZjOUpnM3N3bitHQVhkcXVHbllkTFpGYnpJSFdTbjNMSzlRVDgzbXd2ZXJ0Y0Y2eWxidllZMktsRwo0blBpZGF2ajI4c1kvbnRVU3RFenFqc0hZbEVST1MrcUJMcnRBQURyZmtOR3BrcWQrOGx1WmM1U3RjanBLaGRECkJYcWVVQmVhZG5BTExtdkZxeFc1QVpNd3lWeGM2NlRrVUtRUzJobVRqaWhFeDg5WHZqNXIzZG9XNHMrbTYrbjMKcEhrbjJqeXZTSFppMlVpa0dJYVN5ZXh3TG9zSUd3c3NKZmZOTlBkL3A2TFh4aG1Ja3dJVW5WcDN5c3ZpUVNvRgpCTTdrVDArNWFZQXEzbS9kYUhFUmJtbzlEWk1Wa2dza1RDbUdqa1hXeXB2WENaajkxcTgxc2dBVGlQYz0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K
os:
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBeEErVWl1OWtmbjV2RVZReC96ekp2REFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qVXdOekE1TURreU1qQXpXaGNOTXpVd056QTNNRGt5TWpBeldqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUptNzhzalJla2ZKYklhNGJzNDl4QkV1WC9qbW4rajNsdDJNCmZuMkxKa2JjbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRlBVR1ZPS1Y3UHVMbSs2agppZ2tOdnVDYUZnbUZNQVVHQXl0bGNBTkJBQm5RV2xpNzEwdi9raFlCUStGeGZ2NEJ2dmladVNDYy94c3dXQTgwCjRsdU1GeVRwUzcvdHdnMUdLb1hoR0dqeEY2dy9CMTE2SS9YL0R2d3FYRDJTMWd3PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJRDJhaEtPVkxmUEZlRWo2Y2RnS20vcXpVQmY5bjZUbUpmSFJmYUhiZ0JvcAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K

View File

@ -35,6 +35,8 @@ import (
type SecretsController = qtransform.QController[*omni.Cluster, *omni.ClusterSecrets]
// NewSecretsController instantiates the secrets controller.
//
//nolint:gocognit
func NewSecretsController(etcdBackupStoreFactory store.Factory) *SecretsController {
return qtransform.NewQController(
qtransform.Settings[*omni.Cluster, *omni.ClusterSecrets]{
@ -65,6 +67,30 @@ func NewSecretsController(etcdBackupStoreFactory store.Factory) *SecretsControll
return err
}
ics, err := safe.ReaderGetByID[*omni.ImportedClusterSecrets](ctx, r, cluster.Metadata().ID())
if err != nil {
if !state.IsNotFoundError(err) {
return err
}
} else {
var bundle *talossecrets.Bundle
bundle, err = omni.FromImportedSecretsToSecretsBundle(ics)
if err != nil {
return fmt.Errorf("failed to decode imported cluster secrets: %w", err)
}
var data []byte
data, err = json.Marshal(bundle)
if err != nil {
return fmt.Errorf("error marshaling secrets: %w", err)
}
secrets.TypedSpec().Value.Imported = true
secrets.TypedSpec().Value.Data = data
return nil
}
bundle, err := talossecrets.NewBundle(talossecrets.NewFixedClock(time.Now()), versionContract)
if err != nil {
return fmt.Errorf("error generating secrets: %w", err)
@ -88,6 +114,7 @@ func NewSecretsController(etcdBackupStoreFactory store.Factory) *SecretsControll
return fmt.Errorf("error marshaling secrets: %w", err)
}
secrets.TypedSpec().Value.Imported = false
secrets.TypedSpec().Value.Data = data
return nil
@ -126,6 +153,9 @@ func NewSecretsController(etcdBackupStoreFactory store.Factory) *SecretsControll
// no need to requeue anything, just allow the controller to read data (when restoring from another cluster backup)
qtransform.MapperNone[*omni.BackupData](),
),
qtransform.WithExtraMappedInput(
qtransform.MapperSameID[*omni.ImportedClusterSecrets, *omni.Cluster](),
),
)
}

View File

@ -8,6 +8,7 @@ package omni_test
import (
"bytes"
"context"
_ "embed"
"encoding/json"
"io"
"iter"
@ -63,6 +64,7 @@ func (suite *ClusterSecretsSuite) TestNewSecrets() {
err := json.Unmarshal(clusterSecretsSpec.Data, &bundle)
suite.Require().NoError(err)
suite.Require().NotEmpty(bundle)
suite.Require().Equal(clusterSecretsSpec.Imported, false)
})
// Check that we can get cluster secrets by metadata.
@ -162,6 +164,56 @@ func (suite *ClusterSecretsSuite) TestSecretsFromBackup() {
})
}
//go:embed data/secrets-valid.yaml
var validSecretsBundle string
func (suite *ClusterSecretsSuite) TestImportedSecrets() {
require := suite.Require()
suite.startRuntime()
suite.Require().NoError(suite.runtime.RegisterQController(omnictrl.NewSecretsController(&mockBackupStoreFactory{})))
cluster := omni.NewCluster(resources.DefaultNamespace, "clusterID")
cluster.TypedSpec().Value.TalosVersion = "1.10.5"
require.NoError(suite.state.Create(suite.ctx, cluster))
// create ClusterUUID, as it will be looked up by SecretsController to find the source cluster ID
clusterUUID := omni.NewClusterUUID(cluster.Metadata().ID())
clusterUUID.TypedSpec().Value.Uuid = "test-uuid"
clusterUUID.Metadata().Labels().Set(omni.LabelClusterUUID, "test-uuid")
require.NoError(suite.state.Create(suite.ctx, clusterUUID))
// create ImportedClusterSecret, as it will be looked up by SecretsController to attempt importing secrets bundle
importedClusterSecrets := omni.NewImportedClusterSecrets(resources.DefaultNamespace, cluster.Metadata().ID())
importedClusterSecrets.TypedSpec().Value.Data = validSecretsBundle
require.NoError(suite.state.Create(suite.ctx, importedClusterSecrets))
machineSet := omni.NewMachineSet(resources.DefaultNamespace, omni.ControlPlanesResourceID(cluster.Metadata().ID()))
require.NoError(suite.state.Create(suite.ctx, machineSet))
var foundClusterSecrets *omni.ClusterSecrets
assertResource(
&suite.OmniSuite,
*omni.NewClusterSecrets(resources.DefaultNamespace, cluster.Metadata().ID()).Metadata(),
func(res *omni.ClusterSecrets, _ *assert.Assertions) {
foundClusterSecrets = res
clusterSecretsSpec := foundClusterSecrets.TypedSpec().Value
suite.Require().NotEmpty(clusterSecretsSpec.GetData())
var bundle secrets.Bundle
err := json.Unmarshal(clusterSecretsSpec.Data, &bundle)
suite.Require().NoError(err)
suite.Require().NotEmpty(bundle)
suite.Require().Equal(clusterSecretsSpec.Imported, true)
})
}
func TestClusterSecretsSuite(t *testing.T) {
t.Parallel()

View File

@ -97,3 +97,7 @@ func JoinTokenValidationOptions(st state.State) []validated.StateOption {
func DefaultJoinTokenValidationOptions() []validated.StateOption {
return defaultJoinTokenValidationOptions()
}
func ImportedClusterSecretValidationOptions(st state.State, clusterImportEnabled bool) []validated.StateOption {
return importedClusterSecretValidationOptions(st, clusterImportEnabled)
}

View File

@ -125,6 +125,7 @@ func NewRuntime(talosClientFactory *talos.ClientFactory, dnsService *dns.Service
safe.WithResourceCache[*omni.ExtensionsConfiguration](),
safe.WithResourceCache[*omni.ImagePullRequest](),
safe.WithResourceCache[*omni.ImagePullStatus](),
safe.WithResourceCache[*omni.ImportedClusterSecrets](),
safe.WithResourceCache[*omni.InfraProviderCombinedStatus](),
safe.WithResourceCache[*omni.Kubeconfig](),
safe.WithResourceCache[*omni.KubernetesNodeAuditResult](),
@ -399,6 +400,7 @@ func NewRuntime(talosClientFactory *talos.ClientFactory, dnsService *dns.Service
nodeForceDestroyRequestValidationOptions(cachedState),
joinTokenValidationOptions(cachedState),
defaultJoinTokenValidationOptions(),
importedClusterSecretValidationOptions(cachedState, config.Config.Features.EnableClusterImport),
)
return &Runtime{

View File

@ -51,6 +51,7 @@ var (
omni.EtcdAuditResultType,
omni.EtcdBackupStatusType,
omni.EtcdManualBackupType,
omni.ImportedClusterSecretsType,
})
// clusterLabelTypeSet is the set of resource types which have the related cluster's ID as a label.
@ -399,6 +400,7 @@ func filterAccess(ctx context.Context, access state.Access) error {
omni.EtcdManualBackupType,
omni.ImagePullRequestType,
omni.ImagePullStatusType,
omni.ImportedClusterSecretsType,
omni.InfraMachineConfigType,
omni.KubernetesStatusType,
omni.KubernetesUpgradeManifestStatusType,

View File

@ -1200,3 +1200,42 @@ func defaultJoinTokenValidationOptions() []validated.StateOption {
)),
}
}
func importedClusterSecretValidationOptions(st state.State, clusterImportEnabled bool) []validated.StateOption {
return []validated.StateOption{
validated.WithCreateValidations(validated.NewCreateValidationForType(func(ctx context.Context, res *omni.ImportedClusterSecrets, _ ...state.CreateOption) error {
if !clusterImportEnabled {
return errors.New("cluster import feature is not enabled")
}
return validateImportedClusterSecrets(ctx, st, res)
})),
validated.WithUpdateValidations(validated.NewUpdateValidationForType(
func(ctx context.Context, oldRes *omni.ImportedClusterSecrets, newRes *omni.ImportedClusterSecrets, _ ...state.UpdateOption) error {
return validateImportedClusterSecrets(ctx, st, newRes)
})),
}
}
func validateImportedClusterSecrets(ctx context.Context, st state.State, res *omni.ImportedClusterSecrets) error {
_, err := safe.StateGetByID[*omni.Cluster](ctx, st, res.Metadata().ID())
if err != nil {
if !state.IsNotFoundError(err) {
return err
}
} else {
return fmt.Errorf("cannot create/update an ImportedClusterSecrets, as there is already an existing cluster with name: %q", res.Metadata().ID())
}
bundle, err := omni.FromImportedSecretsToSecretsBundle(res)
if err != nil {
return fmt.Errorf("failed to unmarshal imported cluster secret: %w", err)
}
err = bundle.Validate()
if err != nil {
return fmt.Errorf("failed to validate imported cluster secret: %w", err)
}
return nil
}

View File

@ -1500,6 +1500,57 @@ func TestDefaultJoinTokenValidation(t *testing.T) {
assert.ErrorContains(t, err, "destroying")
}
var (
//go:embed controllers/omni/data/secrets-valid.yaml
validSecrets string
//go:embed controllers/omni/data/secrets-broken.yaml
brokenSecrets string
//go:embed controllers/omni/data/secrets-invalid.yaml
invalidSecrets string
)
func TestImportedClusterSecretValidation(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(t.Context(), time.Second)
t.Cleanup(cancel)
innerSt := state.WrapCore(namespaced.NewState(inmem.Build))
st := validated.NewState(innerSt, omni.ImportedClusterSecretValidationOptions(innerSt, true)...)
res := omnires.NewImportedClusterSecrets(resources.DefaultNamespace, "test")
res.TypedSpec().Value.Data = brokenSecrets
require.True(t, validated.IsValidationError(st.Create(ctx, res)), "expected validation error")
res.TypedSpec().Value.Data = validSecrets
require.NoError(t, st.Create(ctx, res))
require.NoError(t, st.Update(ctx, res))
res.TypedSpec().Value.Data = brokenSecrets
require.True(t, validated.IsValidationError(st.Update(ctx, res)), "expected validation error")
require.NoError(t, st.Destroy(ctx, res.Metadata()))
res.TypedSpec().Value.Data = invalidSecrets
err := st.Create(ctx, res)
require.True(t, validated.IsValidationError(err), "expected validation error")
assert.ErrorContains(t, err, "cluster.secret is required")
assert.ErrorContains(t, err, "one of [secrets.secretboxencryptionsecret, secrets.aescbcencryptionsecret] is required")
assert.ErrorContains(t, err, "trustdinfo is required")
assert.ErrorContains(t, err, "certs.etcd is invalid")
assert.ErrorContains(t, err, "certs.k8saggregator is required")
assert.ErrorContains(t, err, "certs.os is invalid")
cluster := omnires.NewCluster(resources.DefaultNamespace, "test")
require.NoError(t, st.Create(ctx, cluster))
res.TypedSpec().Value.Data = validSecrets
err = st.Create(ctx, res)
require.True(t, validated.IsValidationError(err), "expected validation error")
assert.ErrorContains(t, err, "cannot create/update an ImportedClusterSecrets, as there is already an existing cluster with name")
}
type mockEtcdBackupStoreFactory struct {
store etcdbackup.Store
}

View File

@ -641,6 +641,8 @@ func AssertResourceAuthz(rootCtx context.Context, rootCli *client.Client, client
defaultJoinToken := siderolink.NewDefaultJoinToken()
*defaultJoinToken.Metadata() = resource.NewMetadata(resources.DefaultNamespace, siderolink.DefaultJoinTokenType, uuid.New().String(), resource.VersionUndefined)
importedClusterSecret := omni.NewImportedClusterSecrets(resources.DefaultNamespace, cluster.Metadata().ID())
testCases := []resourceAuthzTestCase{
{
resource: identity,
@ -735,6 +737,10 @@ func AssertResourceAuthz(rootCtx context.Context, rootCli *client.Client, client
resource: machineExtensionsStatus,
allowedVerbSet: readOnlyVerbSet,
},
{
resource: importedClusterSecret,
allowedVerbSet: allVerbsSet,
},
}
// read-only resources

View File

@ -231,26 +231,23 @@ func AssertBlockKubernetesDeploymentCreateAndRunning(ctx context.Context, manage
}
// AssertClusterCreateAndReady is a reusable group of tests that can be used to verify that a cluster is created and ready.
func AssertClusterCreateAndReady(ctx context.Context, rootClient *client.Client, name string, options ClusterOptions) []subTest { //nolint:nolintlint,revive
clusterName := "integration-" + name
options.Name = clusterName
func AssertClusterCreateAndReady(ctx context.Context, rootClient *client.Client, options ClusterOptions) []subTest { //nolint:nolintlint,revive
return subTests(
subTest{
"ClusterShouldBeCreated",
CreateCluster(ctx, rootClient, options),
},
).Append(
AssertBlockClusterAndTalosAPIAndKubernetesShouldBeReady(ctx, rootClient, clusterName, options.MachineOptions.TalosVersion, options.MachineOptions.KubernetesVersion)...,
AssertBlockClusterAndTalosAPIAndKubernetesShouldBeReady(ctx, rootClient, options.Name, options.MachineOptions.TalosVersion, options.MachineOptions.KubernetesVersion)...,
).Append(
subTest{
"AssertSupportBundleContents",
AssertSupportBundleContents(ctx, rootClient, clusterName),
AssertSupportBundleContents(ctx, rootClient, options.Name),
},
).Append(
subTest{
"ClusterShouldBeDestroyed",
AssertDestroyCluster(ctx, rootClient.Omni().State(), clusterName, options.InfraProvider != "", false),
AssertDestroyCluster(ctx, rootClient.Omni().State(), options.Name, options.InfraProvider != "", false),
},
)
}

View File

@ -9,6 +9,8 @@ package integration_test
import (
"context"
_ "embed"
"encoding/base64"
"fmt"
"math/rand/v2"
"os"
@ -24,6 +26,9 @@ import (
"github.com/siderolabs/gen/pair"
"github.com/siderolabs/gen/xslices"
"github.com/siderolabs/go-retry/retry"
talosclient "github.com/siderolabs/talos/pkg/machinery/client"
talossecrets "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets"
"github.com/siderolabs/talos/pkg/machinery/role"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
@ -600,6 +605,7 @@ func AssertDestroyCluster(testCtx context.Context, omniState state.State, cluste
require.NoError(t, err)
rtestutils.AssertNoResource[*omni.Cluster](ctx, t, omniState, clusterName)
rtestutils.AssertNoResource[*omni.ImportedClusterSecrets](ctx, t, omniState, clusterName)
for _, id := range patches {
rtestutils.AssertNoResource[*omni.ConfigPatch](ctx, t, omniState, id)
@ -943,3 +949,34 @@ func updateMachineClassMachineSets(ctx context.Context, t *testing.T, st state.S
})
}
}
func assertClusterIsImported(ctx context.Context, t *testing.T, st state.State, clusterID string, secretsBundle []byte) {
clusterStatus, err := safe.StateGetByID[*omni.ClusterStatus](ctx, st, clusterID)
require.NoError(t, err)
_, ok := clusterStatus.Metadata().Labels().Get(omni.LabelClusterTainted)
require.True(t, ok, "cluster status doesn't have cluster tainted label")
var bundle *talossecrets.Bundle
require.NoError(t, yaml.Unmarshal(secretsBundle, &bundle))
talosConfig := omni.NewTalosConfig(resources.DefaultNamespace, clusterID)
clientCert, err := talossecrets.NewAdminCertificateAndKey(time.Now(), bundle.Certs.OS, role.MakeSet(role.Admin), time.Hour)
require.NoError(t, err)
talosConfig.TypedSpec().Value.Key = base64.StdEncoding.EncodeToString(clientCert.Key)
talosConfig.TypedSpec().Value.Crt = base64.StdEncoding.EncodeToString(clientCert.Crt)
talosConfig.TypedSpec().Value.Ca = base64.StdEncoding.EncodeToString(bundle.Certs.OS.Crt)
endpoints, err := safe.ReaderGetByID[*omni.ClusterEndpoint](ctx, st, clusterID)
require.NoError(t, err)
talosCli, err := talosclient.New(ctx,
talosclient.WithCluster(clusterID),
talosclient.WithConfig(omni.NewTalosClientConfig(talosConfig, endpoints.TypedSpec().Value.ManagementAddresses...)),
)
require.NoError(t, err)
_, err = talosCli.Version(ctx)
require.NoError(t, err)
}

View File

@ -235,6 +235,7 @@ func TestIntegration(t *testing.T) {
t.Run("StaticInfraProvider", testStaticInfraProvider(testOptions))
t.Run("OmniUpgradePrepare", testOmniUpgradePrepare(testOptions))
t.Run("OmniUpgradeVerify", testOmniUpgradeVerify(testOptions))
t.Run("ClusterImport", testClusterImport(testOptions))
})
postRunHooks(t, testOptions)

View File

@ -13,9 +13,14 @@ import (
"testing"
"time"
"github.com/siderolabs/talos/pkg/machinery/config"
talossecrets "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/durationpb"
"gopkg.in/yaml.v3"
"github.com/siderolabs/omni/client/api/omni/specs"
"github.com/siderolabs/omni/client/pkg/omni/resources"
"github.com/siderolabs/omni/client/pkg/omni/resources/omni"
"github.com/siderolabs/omni/internal/integration/workloadproxy"
"github.com/siderolabs/omni/internal/pkg/clientconfig"
@ -316,6 +321,7 @@ Don't do any changes to the cluster.`)
t.Parallel()
clusterOptions := ClusterOptions{
Name: "integration-default",
ControlPlanes: 3,
Workers: 2,
@ -324,7 +330,7 @@ Don't do any changes to the cluster.`)
options.claimMachines(t, clusterOptions.ControlPlanes+clusterOptions.Workers)
runTests(t, AssertClusterCreateAndReady(t.Context(), options.omniClient, "default", clusterOptions))
runTests(t, AssertClusterCreateAndReady(t.Context(), options.omniClient, clusterOptions))
}
}
@ -337,6 +343,7 @@ Don't do any changes to the cluster.`)
t.Parallel()
clusterOptions := ClusterOptions{
Name: "integration-encrypted",
ControlPlanes: 1,
Workers: 1,
@ -348,7 +355,7 @@ Don't do any changes to the cluster.`)
options.claimMachines(t, clusterOptions.ControlPlanes+clusterOptions.Workers)
runTests(t, AssertClusterCreateAndReady(t.Context(), options.omniClient, "encrypted", clusterOptions))
runTests(t, AssertClusterCreateAndReady(t.Context(), options.omniClient, clusterOptions))
}
}
@ -361,6 +368,7 @@ Don't do any changes to the cluster.`)
t.Parallel()
clusterOptions := ClusterOptions{
Name: "integration-singlenode",
ControlPlanes: 1,
Workers: 0,
@ -369,7 +377,7 @@ Don't do any changes to the cluster.`)
options.claimMachines(t, clusterOptions.ControlPlanes+clusterOptions.Workers)
runTests(t, AssertClusterCreateAndReady(t.Context(), options.omniClient, "singlenode", clusterOptions))
runTests(t, AssertClusterCreateAndReady(t.Context(), options.omniClient, clusterOptions))
}
}
@ -1463,3 +1471,47 @@ Test Omni upgrades, the second half that runs on the current Omni version
)
}
}
func testClusterImport(options *TestOptions) TestFunc {
return func(t *testing.T) {
t.Log(`
Create a single node imported cluster, assert that the cluster is ready and accessible and using the imported secrets bundle.`)
t.Parallel()
clusterOptions := ClusterOptions{
Name: "integration-imported-cluster",
ControlPlanes: 1,
Workers: 0,
MachineOptions: options.MachineOptions,
SkipExtensionCheckOnCreate: true,
}
bundle, err := talossecrets.NewBundle(talossecrets.NewFixedClock(time.Now()), config.TalosVersion1_10)
require.NoError(t, err)
bundleYaml, err := yaml.Marshal(bundle)
require.NoError(t, err)
ics := omni.NewImportedClusterSecrets(resources.DefaultNamespace, clusterOptions.Name)
ics.TypedSpec().Value.Data = string(bundleYaml)
require.NoError(t, options.omniClient.Omni().State().Create(t.Context(), ics))
options.claimMachines(t, clusterOptions.ControlPlanes+clusterOptions.Workers)
t.Run(
"ClusterShouldBeCreated",
CreateCluster(t.Context(), options.omniClient, clusterOptions),
)
assertClusterAndAPIReady(t, clusterOptions.Name, options)
assertClusterIsImported(t.Context(), t, options.omniClient.Omni().State(), clusterOptions.Name, bundleYaml)
t.Run(
"ClusterShouldBeDestroyed",
AssertDestroyCluster(t.Context(), options.omniClient.Omni().State(), clusterOptions.Name, false, false),
)
}
}

View File

@ -10,6 +10,7 @@ type Features struct {
EnableTalosPreReleaseVersions bool `yaml:"enableTalosPreReleaseVersions"`
EnableBreakGlassConfigs bool `yaml:"enableBreakGlassConfigs"`
EnableConfigDataCompression bool `yaml:"enableConfigDataCompression"`
EnableClusterImport bool `yaml:"enableClusterImport"`
DisableControllerRuntimeCache bool `yaml:"disableControllerRuntimeCache"`
}