├── .conform.yaml ├── .github ├── renovate.json └── workflows │ ├── acceptance-tests.yaml │ ├── pull-request.yaml │ ├── release.yml │ └── slack-notify.yaml ├── .gitignore ├── .golangci.yml ├── .goreleaser.yml ├── .vscode └── launch.json ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── docs ├── data-sources │ ├── client_configuration.md │ ├── cluster_health.md │ ├── cluster_kubeconfig.md │ ├── image_factory_extensions_versions.md │ ├── image_factory_overlays_versions.md │ ├── image_factory_urls.md │ ├── image_factory_versions.md │ ├── machine_configuration.md │ └── machine_disks.md ├── guides │ └── version-0.2-upgrade.html.md ├── index.md └── resources │ ├── cluster_kubeconfig.md │ ├── image_factory_schematic.md │ ├── machine_bootstrap.md │ ├── machine_configuration_apply.md │ └── machine_secrets.md ├── examples ├── README.md ├── data-sources │ ├── talos_client_configuration │ │ └── data-source.tf │ ├── talos_cluster_kubeconfig │ │ └── data-source.tf │ ├── talos_image_factory_extensions_versions │ │ └── data-source.tf │ ├── talos_image_factory_overlays_versions │ │ └── data-source.tf │ ├── talos_image_factory_urls │ │ └── data-source.tf │ ├── talos_image_factory_versions │ │ └── data-source.tf │ ├── talos_machine_configuration │ │ └── data-source.tf │ └── talos_machine_disks │ │ └── data-source.tf └── resources │ ├── talos_cluster_kubeconfig │ └── resource.tf │ ├── talos_image_factory_schematic │ └── resource.tf │ ├── talos_machine_bootstrap │ ├── import.sh │ └── resource.tf │ ├── talos_machine_configuration_apply │ └── resource.tf │ └── talos_machine_secrets │ ├── import.sh │ └── resource.tf ├── go.mod ├── go.sum ├── hack ├── release.sh └── release.toml ├── main.go ├── pkg └── talos │ ├── internal │ └── gen │ │ └── diskspec.go │ ├── provider.go │ ├── provider_test.go │ ├── talos_client_configuration_data_source.go │ ├── talos_client_configuration_data_source_test.go │ ├── talos_cluster_health_data_source.go │ ├── talos_cluster_health_data_source_test.go │ ├── talos_cluster_kubeconfig_data_source.go │ ├── talos_cluster_kubeconfig_resource.go │ ├── talos_cluster_kubeconfig_resource_test.go │ ├── talos_image_factory_extensions_versions_data_source.go │ ├── talos_image_factory_extensions_versions_data_source_test.go │ ├── talos_image_factory_overlays_versions_data_source.go │ ├── talos_image_factory_overlays_versions_data_source_test.go │ ├── talos_image_factory_schematic_resource.go │ ├── talos_image_factory_schematic_resource_test.go │ ├── talos_image_factory_urls_data_source.go │ ├── talos_image_factory_urls_data_source_test.go │ ├── talos_image_factory_versions_data_source.go │ ├── talos_image_factory_versions_data_source_test.go │ ├── talos_machine_bootstrap_resource.go │ ├── talos_machine_bootstrap_resource_test.go │ ├── talos_machine_configuration_apply_resource.go │ ├── talos_machine_configuration_apply_resource_test.go │ ├── talos_machine_configuration_data_source.go │ ├── talos_machine_configuration_data_source_test.go │ ├── talos_machine_disks_data_source.go │ ├── talos_machine_disks_data_source_test.go │ ├── talos_machine_disks_data_source_types.go │ ├── talos_machine_secrets_resource.go │ ├── talos_machine_secrets_resource_test.go │ ├── testdata │ ├── patch-invalid.yaml │ ├── patch-json6502.json │ ├── patch-strategic.yaml │ ├── secrets.yaml │ └── secretsv1.2.yaml │ └── util.go ├── templates ├── data-sources │ ├── machine_configuration.md.tmpl │ └── machine_disks.md.tmpl ├── guides │ └── version-0.2-upgrade.html.md ├── index.md.tmpl └── resources.md.tmpl ├── terraform-registry-manifest.json └── tools └── tools.go /.conform.yaml: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. 2 | # 3 | # Generated on 2022-03-23T19:45:28Z by kres latest. 4 | 5 | --- 6 | policies: 7 | - type: commit 8 | spec: 9 | dco: true 10 | gpg: 11 | required: true 12 | identity: 13 | gitHubOrganization: siderolabs 14 | spellcheck: 15 | locale: US 16 | maximumOfOneCommit: true 17 | header: 18 | length: 89 19 | imperative: true 20 | case: lower 21 | invalidLastCharacters: . 22 | body: 23 | required: true 24 | conventional: 25 | types: ["chore","docs","perf","refactor","style","test","release"] 26 | scopes: [".*"] -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | ":semanticCommitScopeDisabled", 5 | "schedule:earlyMondays" 6 | ], 7 | "packageRules": [ 8 | { 9 | "matchDatasources": [ 10 | "go", 11 | "golang-version" 12 | ], 13 | "groupName": "go packages", 14 | "matchPackageNames": [ 15 | "*" 16 | ] 17 | } 18 | ], 19 | "dependencyDashboard": true 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/acceptance-tests.yaml: -------------------------------------------------------------------------------- 1 | name: acceptance-tests 2 | concurrency: 3 | group: ${{ github.head_ref || github.run_id }} 4 | cancel-in-progress: true 5 | on: 6 | pull_request: 7 | paths: 8 | - 'go.mod' 9 | - 'go.sum' 10 | - '**.go' 11 | jobs: 12 | acc-tests: 13 | if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/')) 14 | runs-on: 15 | - self-hosted 16 | - generic 17 | env: 18 | GOTOOLCHAIN: local 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | - name: Set up Go 23 | uses: actions/setup-go@v5 24 | with: 25 | go-version-file: 'go.mod' 26 | cache: true 27 | - name: Set up Terraform 28 | uses: hashicorp/setup-terraform@v3 29 | with: 30 | terraform_wrapper: false 31 | - name: Set up libvirt 32 | env: 33 | LIBVIRT_DEFAULT_URI: qemu:///system 34 | run: | 35 | sudo apt-get update 36 | sudo apt-get install -y \ 37 | bridge-utils \ 38 | dnsmasq-base \ 39 | libvirt-daemon-system \ 40 | qemu-kvm \ 41 | qemu-utils \ 42 | qemu-block-extra \ 43 | ovmf 44 | 45 | sudo ln -s OVMF_VARS_4M.fd /usr/share/OVMF/OVMF_VARS.fd 46 | sudo ln -s OVMF_CODE_4M.fd /usr/share/OVMF/OVMF_CODE.fd 47 | 48 | sudo virtlockd -d 49 | sudo virtlogd -d 50 | sudo libvirtd -d 51 | echo -e "\ndefault\n\n/pool-default\n\n" > pool.xml 52 | sudo mkdir /pool-default 53 | sudo chmod a+rwx /pool-default 54 | sudo virsh pool-define pool.xml 55 | sudo virsh pool-start default 56 | echo 'security_driver = "none"' | sudo tee --append /etc/libvirt/qemu.conf 57 | cat < net.xml 58 | 59 | default 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | EOF 70 | sudo virsh net-destroy default 71 | sudo virsh net-undefine default 72 | sudo virsh net-create net.xml 73 | - name: acceptance-test 74 | env: 75 | TERRAFORM_LIBVIRT_TEST_DOMAIN_TYPE: qemu 76 | LIBVIRT_DEFAULT_URI: qemu:///system 77 | CI: "true" 78 | run: | 79 | make testacc 80 | -------------------------------------------------------------------------------- /.github/workflows/pull-request.yaml: -------------------------------------------------------------------------------- 1 | name: check-dirty 2 | on: 3 | pull_request: 4 | jobs: 5 | check-dirty: 6 | if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/')) 7 | runs-on: 8 | - self-hosted 9 | - generic 10 | env: 11 | GOTOOLCHAIN: local 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | - name: Set up Go 16 | uses: actions/setup-go@v5 17 | with: 18 | go-version-file: 'go.mod' 19 | cache: true 20 | - name: Set up Terraform 21 | uses: hashicorp/setup-terraform@v3 22 | with: 23 | terraform_wrapper: false 24 | - name: dirty-check 25 | run: | 26 | make check-dirty 27 | - name: golangci-lint 28 | uses: golangci/golangci-lint-action@v8 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # This GitHub action can publish assets for release when a tag is created. 2 | # Currently its setup to run on any tag that matches the pattern "v*" (ie. v0.1.0). 3 | # 4 | # This uses an action (hashicorp/ghaction-import-gpg) that assumes you set your 5 | # private key in the `GPG_PRIVATE_KEY` secret and passphrase in the `PASSPHRASE` 6 | # secret. If you would rather own your own GPG handling, please fork this action 7 | # or use an alternative one for key handling. 8 | # 9 | # You will need to pass the `--batch` flag to `gpg` in your signing step 10 | # in `goreleaser` to indicate this is being used in a non-interactive mode. 11 | # 12 | name: release 13 | on: 14 | push: 15 | tags: 16 | - 'v*' 17 | permissions: 18 | contents: write 19 | jobs: 20 | goreleaser: 21 | runs-on: 22 | - self-hosted 23 | - generic 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | - name: Unshallow 28 | run: git fetch --prune --unshallow 29 | - name: Set up Go 30 | uses: actions/setup-go@v5 31 | with: 32 | go-version-file: 'go.mod' 33 | cache: true 34 | - name: Import GPG key 35 | uses: crazy-max/ghaction-import-gpg@v6 36 | id: import_gpg 37 | with: 38 | gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} 39 | passphrase: ${{ secrets.PASSPHRASE }} 40 | - name: release-notes 41 | run: make release-notes 42 | - name: Run GoReleaser 43 | uses: goreleaser/goreleaser-action@v6 44 | with: 45 | version: latest 46 | args: release --clean --release-notes=_out/RELEASE_NOTES.md 47 | env: 48 | GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} 49 | # GitHub sets this automatically 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | -------------------------------------------------------------------------------- /.github/workflows/slack-notify.yaml: -------------------------------------------------------------------------------- 1 | name: slack-notify 2 | "on": 3 | workflow_run: 4 | workflows: 5 | - check-dirty 6 | - acceptance-tests 7 | - release 8 | types: 9 | - completed 10 | jobs: 11 | slack-notify: 12 | runs-on: 13 | - self-hosted 14 | - generic 15 | if: github.event.workflow_run.conclusion != 'skipped' 16 | steps: 17 | - name: Get PR number 18 | id: get-pr-number 19 | if: github.event.workflow_run.event == 'pull_request' 20 | env: 21 | GH_TOKEN: ${{ github.token }} 22 | run: | 23 | echo pull_request_number=$(gh pr view -R ${{ github.repository }} ${{ github.event.workflow_run.head_repository.owner.login }}:${{ github.event.workflow_run.head_branch }} --json number --jq .number) >> $GITHUB_OUTPUT 24 | - name: Slack Notify 25 | uses: slackapi/slack-github-action@v2 26 | with: 27 | method: chat.postMessage 28 | payload: | 29 | { 30 | "channel": "proj-talos-maintainers", 31 | "attachments": [ 32 | { 33 | "color": "${{ github.event.workflow_run.conclusion == 'success' && '#2EB886' || github.event.workflow_run.conclusion == 'failure' && '#A30002' || '#FFCC00' }}", 34 | "fallback": "test", 35 | "blocks": [ 36 | { 37 | "type": "section", 38 | "fields": [ 39 | { 40 | "type": "mrkdwn", 41 | "text": "${{ github.event.workflow_run.event == 'pull_request' && format('*Pull Request:* {0} (`{1}`)\n<{2}/pull/{3}|{4}>', github.repository, github.ref_name, github.event.repository.html_url, steps.get-pr-number.outputs.pull_request_number, github.event.workflow_run.display_title) || format('*Build:* {0} (`{1}`)\n<{2}/commit/{3}|{4}>', github.repository, github.ref_name, github.event.repository.html_url, github.sha, github.event.workflow_run.display_title) }}" 42 | }, 43 | { 44 | "type": "mrkdwn", 45 | "text": "*Status:*\n`${{ github.event.workflow_run.conclusion }}`" 46 | } 47 | ] 48 | }, 49 | { 50 | "type": "section", 51 | "fields": [ 52 | { 53 | "type": "mrkdwn", 54 | "text": "*Author:*\n`${{ github.actor }}`" 55 | }, 56 | { 57 | "type": "mrkdwn", 58 | "text": "*Event:*\n`${{ github.event.workflow_run.event }}`" 59 | } 60 | ] 61 | }, 62 | { 63 | "type": "divider" 64 | }, 65 | { 66 | "type": "actions", 67 | "elements": [ 68 | { 69 | "type": "button", 70 | "text": { 71 | "type": "plain_text", 72 | "text": "Logs" 73 | }, 74 | "url": "${{ github.event.workflow_run.html_url }}" 75 | }, 76 | { 77 | "type": "button", 78 | "text": { 79 | "type": "plain_text", 80 | "text": "Commit" 81 | }, 82 | "url": "${{ github.event.repository.html_url }}/commit/${{ github.sha }}" 83 | } 84 | ] 85 | } 86 | ] 87 | } 88 | ] 89 | } 90 | token: ${{ secrets.SLACK_BOT_TOKEN }} 91 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | terraform-provider-talos 3 | _out 4 | 5 | ### Terraform ### 6 | # Local .terraform directories 7 | **/.terraform/* 8 | 9 | # .tfstate files 10 | *.tfstate 11 | *.tfstate.* 12 | 13 | # Crash log files 14 | crash.*.log 15 | 16 | # Exclude all .tfvars files, which are likely to contain sensitive data, such as 17 | # password, private keys, and other secrets. These should not be part of version 18 | # control as they are data points which are potentially sensitive and subject 19 | # to change depending on the environment. 20 | #*.tfvars 21 | #*.tfvars.json 22 | 23 | # Ignore override files as they are usually used to override resources locally and so 24 | # are not checked in 25 | override.tf 26 | override.tf.json 27 | *_override.tf 28 | *_override.tf.json 29 | 30 | # Include override files you do wish to add to version control using negated pattern 31 | # !example_override.tf 32 | 33 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 34 | # example: *tfplan* 35 | 36 | # Ignore CLI configuration files 37 | .terraformrc 38 | terraform.rc 39 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. 2 | # 3 | # Generated on 2025-05-05T10:34:00Z by kres be6d3a6a. 4 | 5 | version: "2" 6 | 7 | # options for analysis running 8 | run: 9 | modules-download-mode: readonly 10 | issues-exit-code: 1 11 | tests: true 12 | 13 | # output configuration options 14 | output: 15 | formats: 16 | text: 17 | path: stdout 18 | print-issued-lines: true 19 | print-linter-name: true 20 | path-prefix: "" 21 | 22 | 23 | linters: 24 | default: all 25 | disable: 26 | - exhaustruct 27 | - err113 28 | - forbidigo 29 | - funcorder 30 | - funlen 31 | - gochecknoglobals 32 | - gochecknoinits 33 | - godox 34 | - gomoddirectives 35 | - gosec 36 | - inamedparam 37 | - ireturn 38 | - mnd 39 | - nestif 40 | - nonamedreturns 41 | - paralleltest 42 | - tagalign 43 | - tagliatelle 44 | - thelper 45 | - varnamelen 46 | - wrapcheck 47 | - testifylint # complains about our assert recorder and has a number of false positives for assert.Greater(t, thing, 1) 48 | - protogetter # complains about us using Value field on typed spec, instead of GetValue which has a different signature 49 | - perfsprint # complains about us using fmt.Sprintf in non-performance critical code, updating just kres took too long 50 | - musttag # seems to be broken - goes into imported libraries and reports issues there 51 | - nolintlint # gives false positives - disable until https://github.com/golangci/golangci-lint/issues/3228 is resolved 52 | # all available settings of specific linters 53 | settings: 54 | cyclop: 55 | # the maximal code complexity to report 56 | max-complexity: 20 57 | dogsled: 58 | max-blank-identifiers: 2 59 | dupl: 60 | threshold: 150 61 | errcheck: 62 | check-type-assertions: true 63 | check-blank: true 64 | exhaustive: 65 | default-signifies-exhaustive: false 66 | gocognit: 67 | min-complexity: 30 68 | nestif: 69 | min-complexity: 5 70 | goconst: 71 | min-len: 3 72 | min-occurrences: 3 73 | gocritic: 74 | disabled-checks: [ ] 75 | gocyclo: 76 | min-complexity: 20 77 | godot: 78 | scope: declarations 79 | gomodguard: { } 80 | govet: 81 | enable-all: true 82 | lll: 83 | line-length: 200 84 | tab-width: 4 85 | misspell: 86 | locale: US 87 | nakedret: 88 | max-func-lines: 30 89 | prealloc: 90 | simple: true 91 | range-loops: true # Report preallocation suggestions on range loops, true by default 92 | for-loops: false # Report preallocation suggestions on for loops, false by default 93 | rowserrcheck: { } 94 | testpackage: { } 95 | unparam: 96 | check-exported: false 97 | unused: 98 | local-variables-are-used: false 99 | whitespace: 100 | multi-if: false # Enforces newlines (or comments) after every multi-line if statement 101 | multi-func: false # Enforces newlines (or comments) after every multi-line function signature 102 | wsl: 103 | strict-append: true 104 | allow-assign-and-call: true 105 | allow-multiline-assign: true 106 | allow-trailing-comment: false 107 | force-case-trailing-whitespace: 0 108 | allow-separated-leading-comment: false 109 | allow-cuddle-declarations: false 110 | force-err-cuddling: false 111 | depguard: 112 | rules: 113 | prevent_unmaintained_packages: 114 | list-mode: lax # allow unless explicitly denied 115 | files: 116 | - $all 117 | deny: 118 | - pkg: io/ioutil 119 | desc: "replaced by io and os packages since Go 1.16: https://tip.golang.org/doc/go1.16#ioutil" 120 | test_kres_depguard_extra_rule_1: 121 | deny: 122 | - desc: Test rule 1 123 | pkg: io/ioutil 124 | files: 125 | - test_1.go 126 | list-mode: lax 127 | test_kres_depguard_extra_rule_2: 128 | deny: 129 | - desc: Test rule 2 130 | pkg: io/ioutil 131 | files: 132 | - test_2.go 133 | list-mode: lax 134 | 135 | exclusions: 136 | generated: lax 137 | paths: 138 | - third_party$ 139 | - builtin$ 140 | - examples$ 141 | issues: 142 | max-issues-per-linter: 10 143 | max-same-issues: 3 144 | uniq-by-line: true 145 | new: false 146 | 147 | severity: 148 | default: error 149 | formatters: 150 | enable: 151 | - gci 152 | - gofmt 153 | - gofumpt 154 | settings: 155 | gci: 156 | sections: 157 | - standard 158 | - default 159 | - localmodule 160 | gofmt: 161 | simplify: true 162 | gofumpt: 163 | extra-rules: false 164 | exclusions: 165 | generated: lax 166 | paths: 167 | - third_party$ 168 | - builtin$ 169 | - examples$ 170 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # Visit https://goreleaser.com for documentation on how to customize this 2 | # behavior. 3 | version: 2 4 | before: 5 | hooks: 6 | # this is just an example and not a requirement for provider building/publishing 7 | - go mod tidy 8 | builds: 9 | - env: 10 | # goreleaser does not work with CGO, it could also complicate 11 | # usage by users in CI/CD systems like Terraform Cloud where 12 | # they are unable to install libraries. 13 | - CGO_ENABLED=0 14 | mod_timestamp: '{{ .CommitTimestamp }}' 15 | flags: 16 | - -trimpath 17 | ldflags: 18 | - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' 19 | goos: 20 | - freebsd 21 | - windows 22 | - linux 23 | - darwin 24 | goarch: 25 | - amd64 26 | - '386' 27 | - arm 28 | - arm64 29 | ignore: 30 | - goos: darwin 31 | goarch: '386' 32 | binary: '{{ .ProjectName }}_v{{ .Version }}' 33 | archives: 34 | - format: zip 35 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' 36 | checksum: 37 | extra_files: 38 | - glob: 'terraform-registry-manifest.json' 39 | name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' 40 | name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' 41 | algorithm: sha256 42 | signs: 43 | - artifacts: checksum 44 | args: 45 | # if you are using this in a GitHub action or some other automated pipeline, you 46 | # need to pass the batch flag to indicate its not interactive. 47 | - "--batch" 48 | - "--local-user" 49 | - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key 50 | - "--output" 51 | - "${signature}" 52 | - "--detach-sign" 53 | - "${artifact}" 54 | release: 55 | extra_files: 56 | - glob: 'terraform-registry-manifest.json' 57 | name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' 58 | # If you want to manually examine the release before its live, uncomment this line: 59 | # draft: true 60 | changelog: 61 | disable: false 62 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Debug Talos Terraform Provider", 6 | "type": "go", 7 | "request": "launch", 8 | "mode": "debug", 9 | // this assumes your workspace is the root of the repo 10 | "program": "${workspaceFolder}", 11 | "env": {}, 12 | "args": [ 13 | "-debug", 14 | ] 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TAG ?= $(shell git describe --tag --always --dirty) 2 | ARTIFACTS ?= _out 3 | TEST_TIMEOUT ?= 600s 4 | 5 | ifneq ($(origin TESTS), undefined) 6 | RUNARGS = -run='$(TESTS)' 7 | endif 8 | 9 | ifneq ($(origin CI), undefined) 10 | RUNARGS += -parallel=3 11 | RUNARGS += -timeout=25m 12 | RUNARGS += -exec="sudo -E" 13 | endif 14 | 15 | .PHONY: generate 16 | generate: 17 | go generate ./pkg/talos 18 | go generate 19 | 20 | .PHONY: testacc 21 | testacc: 22 | # TF_CLI_CONFIG_FILE is set here to avoid using the user's .terraformrc file. Ref: https://github.com/hashicorp/terraform-plugin-sdk/issues/1171 23 | TF_CLI_CONFIG_FILE="thisfiledoesnotexist" TF_ACC=1 go test -v -failfast -cover $(RUNARGS) ./... 24 | 25 | .PHONY: check-dirty 26 | check-dirty: generate ## Verifies that source tree is not dirty 27 | @if test -n "`git status --porcelain`"; then echo "Source tree is dirty"; git status; exit 1 ; fi 28 | 29 | build-debug: 30 | go build -gcflags='all=-N -l' 31 | 32 | install: 33 | go install . 34 | 35 | release-notes: 36 | mkdir -p $(ARTIFACTS) 37 | @ARTIFACTS=$(ARTIFACTS) ./hack/release.sh $@ $(ARTIFACTS)/RELEASE_NOTES.md $(TAG) 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terraform-provider-talos 2 | 3 | ## Debugging 4 | 5 | In a bash shell, build a debug version of this provider binary: 6 | 7 | ```bash 8 | make build-debug 9 | ``` 10 | 11 | In Visual Studio Code, [start the provider in a debug session](https://developer.hashicorp.com/terraform/plugin/debugging#starting-a-provider-in-debug-mode). 12 | 13 | In a new bash shell, go into your terraform project directory, and run 14 | terraform with `TF_REATTACH_PROVIDERS` set to the value printed in the VSCode debug windows. 15 | -------------------------------------------------------------------------------- /docs/data-sources/client_configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "talos_client_configuration Data Source - talos" 4 | subcategory: "" 5 | description: |- 6 | Generate client configuration for a Talos cluster 7 | --- 8 | 9 | # talos_client_configuration (Data Source) 10 | 11 | Generate client configuration for a Talos cluster 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "talos_machine_secrets" "this" {} 17 | 18 | data "talos_client_configuration" "this" { 19 | cluster_name = "example-cluster" 20 | client_configuration = talos_machine_secrets.this.client_configuration 21 | nodes = ["10.5.0.2"] 22 | } 23 | ``` 24 | 25 | 26 | ## Schema 27 | 28 | ### Required 29 | 30 | - `client_configuration` (Attributes) The client configuration data (see [below for nested schema](#nestedatt--client_configuration)) 31 | - `cluster_name` (String) The name of the cluster in the generated config 32 | 33 | ### Optional 34 | 35 | - `endpoints` (List of String) endpoints to set in the generated config 36 | - `nodes` (List of String) nodes to set in the generated config 37 | 38 | ### Read-Only 39 | 40 | - `id` (String) The ID of this resource 41 | - `talos_config` (String, Sensitive) The generated client configuration 42 | 43 | 44 | ### Nested Schema for `client_configuration` 45 | 46 | Required: 47 | 48 | - `ca_certificate` (String) The client CA certificate 49 | - `client_certificate` (String) The client certificate 50 | - `client_key` (String, Sensitive) The client key 51 | -------------------------------------------------------------------------------- /docs/data-sources/cluster_health.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "talos_cluster_health Data Source - talos" 4 | subcategory: "" 5 | description: |- 6 | Waits for the Talos cluster to be healthy. Can be used as a dependency before running other operations on the cluster. 7 | --- 8 | 9 | # talos_cluster_health (Data Source) 10 | 11 | Waits for the Talos cluster to be healthy. Can be used as a dependency before running other operations on the cluster. 12 | 13 | 14 | 15 | 16 | ## Schema 17 | 18 | ### Required 19 | 20 | - `client_configuration` (Attributes) The client configuration data (see [below for nested schema](#nestedatt--client_configuration)) 21 | - `control_plane_nodes` (List of String) List of control plane nodes to check for health. 22 | - `endpoints` (List of String) endpoints to use for the health check client. Use at least one control plane endpoint. 23 | 24 | ### Optional 25 | 26 | - `skip_kubernetes_checks` (Boolean) Skip Kubernetes component checks, this is useful to check if the nodes has finished booting up and kubelet is running. Default is false. 27 | - `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) 28 | - `worker_nodes` (List of String) List of worker nodes to check for health. 29 | 30 | ### Read-Only 31 | 32 | - `id` (String) The ID of this resource. 33 | 34 | 35 | ### Nested Schema for `client_configuration` 36 | 37 | Required: 38 | 39 | - `ca_certificate` (String) The client CA certificate 40 | - `client_certificate` (String) The client certificate 41 | - `client_key` (String, Sensitive) The client key 42 | 43 | 44 | 45 | ### Nested Schema for `timeouts` 46 | 47 | Optional: 48 | 49 | - `read` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Read operations occur during any refresh or planning operation when refresh is enabled. 50 | -------------------------------------------------------------------------------- /docs/data-sources/cluster_kubeconfig.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "talos_cluster_kubeconfig Data Source - talos" 4 | subcategory: "" 5 | description: |- 6 | Retrieves the kubeconfig for a Talos cluster 7 | --- 8 | 9 | # talos_cluster_kubeconfig (Data Source) 10 | 11 | Retrieves the kubeconfig for a Talos cluster 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "talos_machine_secrets" "this" {} 17 | 18 | data "talos_machine_configuration" "this" { 19 | cluster_name = "example-cluster" 20 | machine_type = "controlplane" 21 | cluster_endpoint = "https://cluster.local:6443" 22 | machine_secrets = talos_machine_secrets.this.machine_secrets 23 | } 24 | 25 | data "talos_client_configuration" "this" { 26 | cluster_name = "example-cluster" 27 | client_configuration = talos_machine_secrets.this.client_configuration 28 | nodes = ["10.5.0.2"] 29 | } 30 | 31 | resource "talos_machine_configuration_apply" "this" { 32 | client_configuration = talos_machine_secrets.this.client_configuration 33 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 34 | node = "10.5.0.2" 35 | config_patches = [ 36 | yamlencode({ 37 | machine = { 38 | install = { 39 | disk = "/dev/sdd" 40 | } 41 | } 42 | }) 43 | ] 44 | } 45 | 46 | resource "talos_machine_bootstrap" "this" { 47 | depends_on = [ 48 | talos_machine_configuration_apply.this 49 | ] 50 | node = "10.5.0.2" 51 | client_configuration = talos_machine_secrets.this.client_configuration 52 | } 53 | 54 | 55 | data "talos_cluster_kubeconfig" "this" { 56 | depends_on = [ 57 | talos_machine_bootstrap.this 58 | ] 59 | client_configuration = talos_machine_secrets.this.client_configuration 60 | node = "10.5.0.2" 61 | } 62 | ``` 63 | 64 | 65 | ## Schema 66 | 67 | ### Required 68 | 69 | - `client_configuration` (Attributes) The client configuration data (see [below for nested schema](#nestedatt--client_configuration)) 70 | - `node` (String) controlplane node to retrieve the kubeconfig from 71 | 72 | ### Optional 73 | 74 | - `endpoint` (String) endpoint to use for the talosclient. If not set, the node value will be used 75 | - `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) 76 | - `wait` (Boolean, Deprecated) Wait for the kubernetes api to be available 77 | 78 | ### Read-Only 79 | 80 | - `id` (String) The ID of this resource. 81 | - `kubeconfig_raw` (String, Sensitive) The raw kubeconfig 82 | - `kubernetes_client_configuration` (Attributes) The kubernetes client configuration (see [below for nested schema](#nestedatt--kubernetes_client_configuration)) 83 | 84 | 85 | ### Nested Schema for `client_configuration` 86 | 87 | Required: 88 | 89 | - `ca_certificate` (String) The client CA certificate 90 | - `client_certificate` (String) The client certificate 91 | - `client_key` (String, Sensitive) The client key 92 | 93 | 94 | 95 | ### Nested Schema for `timeouts` 96 | 97 | Optional: 98 | 99 | - `read` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Read operations occur during any refresh or planning operation when refresh is enabled. 100 | 101 | 102 | 103 | ### Nested Schema for `kubernetes_client_configuration` 104 | 105 | Read-Only: 106 | 107 | - `ca_certificate` (String) The kubernetes CA certificate 108 | - `client_certificate` (String) The kubernetes client certificate 109 | - `client_key` (String, Sensitive) The kubernetes client key 110 | - `host` (String) The kubernetes host 111 | -------------------------------------------------------------------------------- /docs/data-sources/image_factory_extensions_versions.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "talos_image_factory_extensions_versions Data Source - talos" 4 | subcategory: "" 5 | description: |- 6 | The image factory extensions versions data source provides a list of available extensions for a specific talos version from the image factory. 7 | --- 8 | 9 | # talos_image_factory_extensions_versions (Data Source) 10 | 11 | The image factory extensions versions data source provides a list of available extensions for a specific talos version from the image factory. 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | provider "talos" {} 17 | 18 | data "talos_image_factory_extensions_versions" "this" { 19 | # get the latest talos version 20 | talos_version = "v1.7.5" 21 | filters = { 22 | names = [ 23 | "amdgpu", 24 | "tailscale", 25 | ] 26 | } 27 | } 28 | ``` 29 | 30 | 31 | ## Schema 32 | 33 | ### Required 34 | 35 | - `talos_version` (String) The talos version to get extensions for. 36 | 37 | ### Optional 38 | 39 | - `filters` (Attributes) The filter to apply to the extensions list. (see [below for nested schema](#nestedatt--filters)) 40 | 41 | ### Read-Only 42 | 43 | - `extensions_info` (List of Object) The list of available extensions for the specified talos version. (see [below for nested schema](#nestedatt--extensions_info)) 44 | - `id` (String) The ID of this resource. 45 | 46 | 47 | ### Nested Schema for `filters` 48 | 49 | Optional: 50 | 51 | - `names` (List of String) The name of the extension to filter by. 52 | 53 | 54 | 55 | ### Nested Schema for `extensions_info` 56 | 57 | Read-Only: 58 | 59 | - `author` (String) 60 | - `description` (String) 61 | - `digest` (String) 62 | - `name` (String) 63 | - `ref` (String) 64 | -------------------------------------------------------------------------------- /docs/data-sources/image_factory_overlays_versions.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "talos_image_factory_overlays_versions Data Source - talos" 4 | subcategory: "" 5 | description: |- 6 | The image factory overlays versions data source provides a list of available overlays for a specific talos version from the image factory. 7 | --- 8 | 9 | # talos_image_factory_overlays_versions (Data Source) 10 | 11 | The image factory overlays versions data source provides a list of available overlays for a specific talos version from the image factory. 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | provider "talos" {} 17 | 18 | data "talos_image_factory_overlays_versions" "this" { 19 | # get the latest talos version 20 | talos_version = "v1.7.5" 21 | filters = { 22 | name = "rock4cplus" 23 | } 24 | } 25 | ``` 26 | 27 | 28 | ## Schema 29 | 30 | ### Required 31 | 32 | - `talos_version` (String) The talos version to get overlays for. 33 | 34 | ### Optional 35 | 36 | - `filters` (Attributes) The filter to apply to the overlays list. (see [below for nested schema](#nestedatt--filters)) 37 | 38 | ### Read-Only 39 | 40 | - `id` (String) The ID of this resource. 41 | - `overlays_info` (List of Object) The list of available extensions for the specified talos version. (see [below for nested schema](#nestedatt--overlays_info)) 42 | 43 | 44 | ### Nested Schema for `filters` 45 | 46 | Optional: 47 | 48 | - `name` (String) The name of the overlay to filter by. 49 | 50 | 51 | 52 | ### Nested Schema for `overlays_info` 53 | 54 | Read-Only: 55 | 56 | - `digest` (String) 57 | - `image` (String) 58 | - `name` (String) 59 | - `ref` (String) 60 | -------------------------------------------------------------------------------- /docs/data-sources/image_factory_urls.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "talos_image_factory_urls Data Source - talos" 4 | subcategory: "" 5 | description: |- 6 | Generates URLs for different assets supported by the Talos image factory. 7 | --- 8 | 9 | # talos_image_factory_urls (Data Source) 10 | 11 | Generates URLs for different assets supported by the Talos image factory. 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | data "talos_image_factory_urls" "this" { 17 | talos_version = "v1.7.5" 18 | schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba" 19 | platform = "metal" 20 | } 21 | 22 | output "installer_image" { 23 | value = data.talos_image_factory_urls.this.urls.installer 24 | } 25 | ``` 26 | 27 | 28 | ## Schema 29 | 30 | ### Required 31 | 32 | - `schematic_id` (String) The schematic ID for which the URLs are generated. 33 | - `talos_version` (String) The Talos version for which the URLs are generated. 34 | 35 | ### Optional 36 | 37 | - `architecture` (String) The platform architecture for which the URLs are generated. Defaults to amd64. 38 | - `platform` (String) The platform for which the URLs are generated. 39 | 40 | #### Metal 41 | 42 | - metal 43 | 44 | #### Cloud Platforms 45 | - aws 46 | - gcp 47 | - equinixMetal 48 | - azure 49 | - digital-ocean 50 | - nocloud 51 | - openstack 52 | - vmware 53 | - akamai 54 | - cloudstack 55 | - hcloud 56 | - oracle 57 | - upcloud 58 | - vultr 59 | - exoscale 60 | - opennebula 61 | - scaleway 62 | - `sbc` (String) The SBC's (Single Board Copmuters) for which the url are generated. 63 | 64 | #### Single Board Computers 65 | - rpi_generic 66 | - revpi_generic 67 | - bananapi_m64 68 | - nanopi_r4s 69 | - nanopi_r5s 70 | - jetson_nano 71 | - libretech_all_h3_cc_h5 72 | - orangepi_r1_plus_lts 73 | - pine64 74 | - rock64 75 | - rock4cplus 76 | - rock4se 77 | - rock5a 78 | - rock5b 79 | - rockpi_4 80 | - rockpi_4c 81 | - helios64 82 | - turingrk1 83 | - orangepi-5 84 | - orangepi-5-plus 85 | - rockpro64 86 | 87 | ### Read-Only 88 | 89 | - `id` (String) The ID of this resource. 90 | - `urls` (Attributes) The URLs for different assets supported by the Talos image factory. If the URL is not available for a specific asset, it will be an empty string. (see [below for nested schema](#nestedatt--urls)) 91 | 92 | 93 | ### Nested Schema for `urls` 94 | 95 | Read-Only: 96 | 97 | - `disk_image` (String) The URL for the disk image. 98 | - `disk_image_secureboot` (String) The URL for the disk image with secure boot. 99 | - `initramfs` (String) The URL for the initramfs image. 100 | - `installer` (String) The URL for the installer image. 101 | - `installer_secureboot` (String) The URL for the installer image with secure boot. 102 | - `iso` (String) The URL for the ISO image. 103 | - `iso_secureboot` (String) The URL for the ISO image with secure boot. 104 | - `kernel` (String) The URL for the kernel image. 105 | - `kernel_command_line` (String) The URL for the kernel command line. 106 | - `pxe` (String) The URL for the PXE image. 107 | - `uki` (String) The URL for the UKI image. 108 | -------------------------------------------------------------------------------- /docs/data-sources/image_factory_versions.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "talos_image_factory_versions Data Source - talos" 4 | subcategory: "" 5 | description: |- 6 | The image factory versions data source provides a list of available talos versions from the image factory. 7 | --- 8 | 9 | # talos_image_factory_versions (Data Source) 10 | 11 | The image factory versions data source provides a list of available talos versions from the image factory. 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | provider "talos" {} 17 | 18 | data "talos_image_factory_versions" "this" {} 19 | 20 | output "latest" { 21 | value = element(data.talos_image_factory_versions.this.talos_versions, length(data.talos_image_factory_versions.this.talos_versions) - 1) 22 | } 23 | ``` 24 | 25 | 26 | ## Schema 27 | 28 | ### Optional 29 | 30 | - `filters` (Attributes) The filter to apply to the overlays list. (see [below for nested schema](#nestedatt--filters)) 31 | 32 | ### Read-Only 33 | 34 | - `id` (String) The ID of this resource. 35 | - `talos_versions` (List of String) The list of available talos versions. 36 | 37 | 38 | ### Nested Schema for `filters` 39 | 40 | Optional: 41 | 42 | - `stable_versions_only` (Boolean) If set to true, only stable versions will be returned. If set to false, all versions will be returned. 43 | -------------------------------------------------------------------------------- /docs/data-sources/machine_configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "talos_machine_configuration Data Source - talos" 3 | subcategory: "" 4 | description: |- 5 | Generate a machine configuration for a node type 6 | --- 7 | 8 | # talos_machine_configuration (Data Source) 9 | 10 | Generate a machine configuration for a node type 11 | 12 | -> **Note:** It is recommended to set the optional `talos_version` attribute. Otherwise when using a new version of the provider with a new major version of the Talos SDK, new machineconfig features will be enabled by default which could cause unexpected behavior. 13 | 14 | ## Example Usage 15 | 16 | ```terraform 17 | resource "talos_machine_secrets" "this" {} 18 | 19 | data "talos_machine_configuration" "this" { 20 | cluster_name = "example-cluster" 21 | machine_type = "controlplane" 22 | cluster_endpoint = "https://cluster.local:6443" 23 | machine_secrets = talos_machine_secrets.this.machine_secrets 24 | } 25 | ``` 26 | 27 | ## Schema 28 | 29 | ### Required 30 | 31 | - `cluster_endpoint` (String) The endpoint of the talos kubernetes cluster 32 | - `cluster_name` (String) The name of the talos kubernetes cluster 33 | - `machine_secrets` (Attributes) The secrets for the talos cluster (see [below for nested schema](#nestedatt--machine_secrets)) 34 | - `machine_type` (String) The type of machine to generate the configuration for 35 | 36 | ### Optional 37 | 38 | - `config_patches` (List of String) The list of config patches to apply to the generated configuration 39 | - `docs` (Boolean) Whether to generate documentation for the generated configuration. Defaults to false 40 | - `examples` (Boolean) Whether to generate examples for the generated configuration. Defaults to false 41 | - `kubernetes_version` (String) The version of kubernetes to use 42 | - `talos_version` (String) The version of talos features to use in generated machine configuration 43 | 44 | ### Read-Only 45 | 46 | - `id` (String) The ID of this resource. 47 | - `machine_configuration` (String, Sensitive) The generated machine configuration 48 | 49 | 50 | ### Nested Schema for `machine_secrets` 51 | 52 | Required: 53 | 54 | - `certs` (Attributes) The certs for the talos kubernetes cluster (see [below for nested schema](#nestedatt--machine_secrets--certs)) 55 | - `cluster` (Attributes) The cluster secrets (see [below for nested schema](#nestedatt--machine_secrets--cluster)) 56 | - `secrets` (Attributes) The secrets for the talos kubernetes cluster (see [below for nested schema](#nestedatt--machine_secrets--secrets)) 57 | - `trustdinfo` (Attributes) The trustd info for the talos kubernetes cluster (see [below for nested schema](#nestedatt--machine_secrets--trustdinfo)) 58 | 59 | 60 | ### Nested Schema for `machine_secrets.certs` 61 | 62 | Required: 63 | 64 | - `etcd` (Attributes) The certificate and key pair (see [below for nested schema](#nestedatt--machine_secrets--certs--etcd)) 65 | - `k8s` (Attributes) The certificate and key pair (see [below for nested schema](#nestedatt--machine_secrets--certs--k8s)) 66 | - `k8s_aggregator` (Attributes) The certificate and key pair (see [below for nested schema](#nestedatt--machine_secrets--certs--k8s_aggregator)) 67 | - `k8s_serviceaccount` (Attributes) (see [below for nested schema](#nestedatt--machine_secrets--certs--k8s_serviceaccount)) 68 | - `os` (Attributes) The certificate and key pair (see [below for nested schema](#nestedatt--machine_secrets--certs--os)) 69 | 70 | 71 | ### Nested Schema for `machine_secrets.certs.etcd` 72 | 73 | Required: 74 | 75 | - `cert` (String) certificate data 76 | - `key` (String, Sensitive) key data 77 | 78 | 79 | 80 | ### Nested Schema for `machine_secrets.certs.k8s` 81 | 82 | Required: 83 | 84 | - `cert` (String) certificate data 85 | - `key` (String, Sensitive) key data 86 | 87 | 88 | 89 | ### Nested Schema for `machine_secrets.certs.k8s_aggregator` 90 | 91 | Required: 92 | 93 | - `cert` (String) certificate data 94 | - `key` (String, Sensitive) key data 95 | 96 | 97 | 98 | ### Nested Schema for `machine_secrets.certs.k8s_serviceaccount` 99 | 100 | Required: 101 | 102 | - `key` (String, Sensitive) The key for the k8s service account 103 | 104 | 105 | 106 | ### Nested Schema for `machine_secrets.certs.os` 107 | 108 | Required: 109 | 110 | - `cert` (String) certificate data 111 | - `key` (String, Sensitive) key data 112 | 113 | 114 | 115 | 116 | ### Nested Schema for `machine_secrets.cluster` 117 | 118 | Required: 119 | 120 | - `id` (String) The cluster id 121 | - `secret` (String, Sensitive) The cluster secret 122 | 123 | 124 | 125 | ### Nested Schema for `machine_secrets.secrets` 126 | 127 | Required: 128 | 129 | - `bootstrap_token` (String, Sensitive) The bootstrap token for the talos kubernetes cluster 130 | - `secretbox_encryption_secret` (String, Sensitive) The secretbox encryption secret for the talos kubernetes cluster 131 | 132 | Optional: 133 | 134 | - `aescbc_encryption_secret` (String, Sensitive) The aescbc encryption secret for the talos kubernetes cluster 135 | 136 | 137 | 138 | ### Nested Schema for `machine_secrets.trustdinfo` 139 | 140 | Required: 141 | 142 | - `token` (String, Sensitive) The trustd token for the talos kubernetes cluster 143 | -------------------------------------------------------------------------------- /docs/data-sources/machine_disks.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "talos_machine_disks Data Source - talos" 3 | subcategory: "" 4 | description: |- 5 | Generate a machine configuration for a node type 6 | --- 7 | 8 | # talos_machine_disks (Data Source) 9 | 10 | Generate a machine configuration for a node type 11 | 12 | -> **Note:** Since Talos natively supports `.machine.install.diskSelector`, the `talos_machine_disks` data source maybe just used to query disk information that could be used elsewhere. It's recommended to use `machine.install.diskSelector` in Talos machine configuration. 13 | 14 | ## Example Usage 15 | 16 | ```terraform 17 | resource "talos_machine_secrets" "this" {} 18 | 19 | data "talos_machine_disks" "this" { 20 | client_configuration = talos_machine_secrets.this.client_configuration 21 | node = "10.5.0.2" 22 | selector = "disk.size > 6u * GB" 23 | } 24 | 25 | # for example, this could be used to pass in a list of disks to rook-ceph 26 | output "nvme_disks" { 27 | value = data.talos_machine_disks.this.disks.*.name 28 | } 29 | ``` 30 | 31 | ## Schema 32 | 33 | ### Required 34 | 35 | - `client_configuration` (Attributes) The client configuration data (see [below for nested schema](#nestedatt--client_configuration)) 36 | - `node` (String) controlplane node to retrieve the kubeconfig from 37 | 38 | ### Optional 39 | 40 | - `endpoint` (String) endpoint to use for the talosclient. If not set, the node value will be used 41 | - `selector` (String) The CEL expression to filter the disks. 42 | If not set, all disks will be returned. 43 | See [CEL documentation](https://www.talos.dev/latest/talos-guides/configuration/disk-management/#disk-selector). 44 | - `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) 45 | 46 | ### Read-Only 47 | 48 | - `disks` (Attributes List) The disks that match the filters (see [below for nested schema](#nestedatt--disks)) 49 | - `id` (String) The generated ID of this resource 50 | 51 | 52 | ### Nested Schema for `client_configuration` 53 | 54 | Required: 55 | 56 | - `ca_certificate` (String) The client CA certificate 57 | - `client_certificate` (String) The client certificate 58 | - `client_key` (String, Sensitive) The client key 59 | 60 | 61 | 62 | ### Nested Schema for `timeouts` 63 | 64 | Optional: 65 | 66 | - `read` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Read operations occur during any refresh or planning operation when refresh is enabled. 67 | 68 | 69 | 70 | ### Nested Schema for `disks` 71 | 72 | Read-Only: 73 | 74 | - `bus_path` (String) 75 | - `cdrom` (Boolean) 76 | - `dev_path` (String) 77 | - `io_size` (Number) 78 | - `modalias` (String) 79 | - `model` (String) 80 | - `pretty_size` (String) 81 | - `readonly` (Boolean) 82 | - `rotational` (Boolean) 83 | - `secondary_disks` (List of String) 84 | - `sector_size` (Number) 85 | - `serial` (String) 86 | - `size` (Number) 87 | - `sub_system` (String) 88 | - `symlinks` (List of String) 89 | - `transport` (String) 90 | - `uuid` (String) 91 | - `wwid` (String) 92 | -------------------------------------------------------------------------------- /docs/guides/version-0.2-upgrade.html.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "Terraform Talos Provider Version 0.2 Upgrade Guide" 3 | description: |- 4 | Terraform Talos Provider Version 0.2 Upgrade Guide 5 | --- 6 | 7 | # Terraform Talos Provider Version 0.2 Upgrade Guide 8 | 9 | Version 0.2 of the Talos Terraform provider is a major release and include some breaking chages. This guide will walk you through the changes and how to upgrade your Terraform configuration. 10 | 11 | ~> **NOTE:** Version 0.2 of the Talos Terraform provider drops support for the following resources: 12 | 13 | > * `talos_client_configuration` 14 | > * `talos_cluster_kubeconfig` 15 | > * `talos_machine_configuration_controlplane` 16 | > * `talos_machine_configuration_worker` 17 | 18 | The following table lists the resources that have been removed and the new resources that replace them. 19 | 20 | | Removed Resource | Type | New Resource | Type | 21 | | ------------------------------------------ | -------- | ----------------------------- | ------------- | 22 | | `talos_client_configuration` | Resource | `talos_client_configuration` | Data Source | 23 | | `talos_cluster_kubeconfig` | Resource | `talos_cluster_kubeconfig` | Data Source | 24 | | `talos_machine_configuration_controlplane` | Resource | `talos_machine_configuration` | Data Resource | 25 | | `talos_machine_configuration_worker` | Resource | `talos_machine_configuration` | Data Resource | 26 | 27 | ## Upgrade topics: 28 | 29 | - [Upgrading `talos_client_configuration` resource](#upgrading-talos_client_configuration-resource) 30 | - [Upgrading `talos_cluster_kubeconfig` resource](#upgrading-talos_cluster_kubeconfig-resource) 31 | - [Upgrading `talos_machine_configuration_controlplane` resource](#upgrading-talos_machine_configuration_controlplane-resource) 32 | - [Upgrading `talos_machine_configuration_worker` resource](#upgrading-talos_machine_configuration_worker-resource) 33 | 34 | ### Upgrading `talos_client_configuration` resource 35 | 36 | The `talos_client_configuration` resource has been removed. The `talos_client_configuration` data source should be used instead. 37 | 38 | For example if the following resource was used: 39 | 40 | ```hcl 41 | resource "talos_machine_secrets" "this" {} 42 | 43 | resource "talos_client_configuration" "talosconfig" { 44 | cluster_name = "example-cluster" 45 | machine_secrets = talos_machine_secrets.this.machine_secrets 46 | } 47 | ``` 48 | 49 | `talos_client_configuration` resource should be first removed from the state: 50 | 51 | ```bash 52 | terraform state rm talos_client_configuration.talosconfig 53 | ``` 54 | 55 | and the code should be updated to: 56 | 57 | ```hcl 58 | resource "talos_machine_secrets" "machine_secrets" {} 59 | 60 | data "talos_client_configuration" "this" { 61 | cluster_name = "example-cluster" 62 | client_configuration = talos_machine_secrets.this.client_configuration 63 | } 64 | ``` 65 | 66 | ### Upgrading `talos_cluster_kubeconfig` resource 67 | 68 | The `talos_cluster_kubeconfig` resource has been removed. The `talos_cluster_kubeconfig` data source should be used instead. 69 | 70 | For example if the following resource was used: 71 | 72 | ```hcl 73 | resource "talos_machine_secrets" "this" {} 74 | 75 | resource "talos_client_configuration" "this" { 76 | cluster_name = "example-cluster" 77 | machine_secrets = talos_machine_secrets.this.machine_secrets 78 | } 79 | 80 | resource "talos_cluster_kubeconfig" "kubeconfig" { 81 | talos_config = talos_client_configuration.this.talos_config 82 | endpoint = "10.5.0.2" 83 | node = "10.5.0.2" 84 | } 85 | ``` 86 | 87 | `talos_cluster_kubeconfig` resource should be first removed from the state: 88 | 89 | ```bash 90 | terraform state rm talos_cluster_kubeconfig.kubeconfig 91 | ``` 92 | 93 | and the code should be updated to: 94 | 95 | ```hcl 96 | resource "talos_machine_secrets" "machine_secrets" {} 97 | 98 | data "talos_cluster_kubeconfig" "this" { 99 | client_configuration = talos_machine_secrets.this.client_configuration 100 | node = "10.5.0.2" 101 | } 102 | ``` 103 | 104 | ### Upgrading `talos_machine_configuration_controlplane` resource 105 | 106 | The `talos_machine_configuration_controlplane` resource has been removed. The `talos_machine_configuration` data source should be used instead. 107 | 108 | For example if the following resource was used: 109 | 110 | ```hcl 111 | resource "talos_machine_secrets" "this" {} 112 | 113 | resource "talos_client_configuration" "this" { 114 | cluster_name = "example-cluster" 115 | machine_secrets = talos_machine_secrets.this.machine_secrets 116 | } 117 | 118 | resource "talos_machine_configuration_controlplane" "this" { 119 | cluster_name = "example-cluster" 120 | cluster_endpoint = "https://10.5.0.2:6443" 121 | machine_secrets = talos_machine_secrets.this.machine_secrets 122 | } 123 | 124 | resource "talos_machine_configuration_apply" "this" { 125 | talos_config = talos_client_configuration.this.talos_config 126 | machine_configuration = talos_machine_configuration_controlplane.this.machine_config 127 | node = "10.5.0.2" 128 | endpoint = "10.5.0.2" 129 | } 130 | ``` 131 | 132 | `talos_machine_configuration_controlplane` resource should be first removed from the state: 133 | 134 | ```bash 135 | terraform state rm talos_machine_configuration_controlplane.cp 136 | ``` 137 | 138 | and the code should be updated to: 139 | 140 | ```hcl 141 | resource "talos_machine_secrets" "machine_secrets" {} 142 | 143 | data "talos_machine_configuration" "this" { 144 | cluster_name = "example-cluster" 145 | cluster_endpoint = "https://10.5.0.2:6443" 146 | machine_type = "controlplane" 147 | talos_version = talos_machine_secrets.this.talos_version 148 | machine_secrets = talos_machine_secrets.this.machine_secrets 149 | } 150 | 151 | resource "talos_machine_configuration_apply" "this" { 152 | client_configuration = talos_machine_secrets.this.client_configuration 153 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 154 | node = "10.5.0.2" 155 | } 156 | ``` 157 | 158 | ### Upgrading `talos_machine_configuration_worker` resource 159 | 160 | The `talos_machine_configuration_worker` resource has been removed. The `talos_machine_configuration` data source should be used instead. 161 | 162 | For example if the following resource was used: 163 | 164 | ```hcl 165 | resource "talos_machine_secrets" "this" {} 166 | 167 | resource "talos_client_configuration" "this" { 168 | cluster_name = "example-cluster" 169 | machine_secrets = talos_machine_secrets.this.machine_secrets 170 | } 171 | 172 | resource "talos_machine_configuration_worker" "this" { 173 | cluster_name = "example-cluster" 174 | cluster_endpoint = "https://10.5.0.2:6443" 175 | machine_secrets = talos_machine_secrets.this.machine_secrets 176 | } 177 | 178 | resource "talos_machine_configuration_apply" "this" { 179 | talos_config = talos_client_configuration.this.talos_config 180 | machine_configuration = talos_machine_configuration_worker.this.machine_config 181 | node = "10.5.0.3" 182 | endpoint = "10.5.0.3" 183 | } 184 | ``` 185 | 186 | `talos_machine_configuration_worker` resource should be first removed from the state: 187 | 188 | ```bash 189 | terraform state rm talos_machine_configuration_worker.worker 190 | ``` 191 | 192 | and the code should be updated to: 193 | 194 | ```hcl 195 | resource "talos_machine_secrets" "machine_secrets" {} 196 | 197 | data "talos_machine_configuration" "this" { 198 | cluster_name = "example-cluster" 199 | cluster_endpoint = "https://10.5.0.2:6443" 200 | machine_type = "worker" 201 | talos_version = talos_machine_secrets.this.talos_version 202 | machine_secrets = talos_machine_secrets.this.machine_secrets 203 | } 204 | 205 | resource "talos_machine_configuration_apply" "this" { 206 | client_configuration = talos_machine_secrets.this.client_configuration 207 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 208 | node = "10.5.0.3" 209 | } 210 | ``` 211 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "Provider: Talos" 3 | description: |- 4 | The Talos provider is used to manage a Talos cluster config generation and initial setup. 5 | --- 6 | 7 | # Talos Provider 8 | 9 | Talos provider allows to generate configs for a Talos cluster and apply them to the nodes, bootstrap nodes, check cluster health, and retrieve `kubeconfig` and `talosconfig`. 10 | 11 | Complete usages for this provider across a variety of environments can be found [here](https://github.com/siderolabs/contrib/tree/main/examples/terraform). 12 | -------------------------------------------------------------------------------- /docs/resources/cluster_kubeconfig.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "talos_cluster_kubeconfig Resource - talos" 3 | subcategory: "" 4 | description: |- 5 | Retrieves the kubeconfig for a Talos cluster 6 | --- 7 | 8 | # talos_cluster_kubeconfig (Resource) 9 | 10 | Retrieves the kubeconfig for a Talos cluster 11 | 12 | ## Example Usage 13 | 14 | ```terraform 15 | resource "talos_machine_secrets" "this" {} 16 | 17 | data "talos_machine_configuration" "this" { 18 | cluster_name = "example-cluster" 19 | machine_type = "controlplane" 20 | cluster_endpoint = "https://cluster.local:6443" 21 | machine_secrets = talos_machine_secrets.this.machine_secrets 22 | } 23 | 24 | data "talos_client_configuration" "this" { 25 | cluster_name = "example-cluster" 26 | client_configuration = talos_machine_secrets.this.client_configuration 27 | nodes = ["10.5.0.2"] 28 | } 29 | 30 | resource "talos_machine_configuration_apply" "this" { 31 | client_configuration = talos_machine_secrets.this.client_configuration 32 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 33 | node = "10.5.0.2" 34 | config_patches = [ 35 | yamlencode({ 36 | machine = { 37 | install = { 38 | disk = "/dev/sdd" 39 | } 40 | } 41 | }) 42 | ] 43 | } 44 | 45 | resource "talos_machine_bootstrap" "this" { 46 | depends_on = [ 47 | talos_machine_configuration_apply.this 48 | ] 49 | node = "10.5.0.2" 50 | client_configuration = talos_machine_secrets.this.client_configuration 51 | } 52 | 53 | 54 | resource "talos_cluster_kubeconfig" "this" { 55 | depends_on = [ 56 | talos_machine_bootstrap.this 57 | ] 58 | client_configuration = talos_machine_secrets.this.client_configuration 59 | node = "10.5.0.2" 60 | } 61 | ``` 62 | 63 | ## Schema 64 | 65 | ### Required 66 | 67 | - `client_configuration` (Attributes) The client configuration data (see [below for nested schema](#nestedatt--client_configuration)) 68 | - `node` (String) controlplane node to retrieve the kubeconfig from 69 | 70 | ### Optional 71 | 72 | - `certificate_renewal_duration` (String) The duration in hours before the certificate is renewed, defaults to 720h. Must be a valid duration string 73 | - `endpoint` (String) endpoint to use for the talosclient. If not set, the node value will be used 74 | - `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) 75 | 76 | ### Read-Only 77 | 78 | - `id` (String) The ID of this resource. 79 | - `kubeconfig_raw` (String, Sensitive) The raw kubeconfig 80 | - `kubernetes_client_configuration` (Attributes) The kubernetes client configuration (see [below for nested schema](#nestedatt--kubernetes_client_configuration)) 81 | 82 | 83 | ### Nested Schema for `client_configuration` 84 | 85 | Required: 86 | 87 | - `ca_certificate` (String) The client CA certificate 88 | - `client_certificate` (String) The client certificate 89 | - `client_key` (String, Sensitive) The client key 90 | 91 | 92 | 93 | ### Nested Schema for `timeouts` 94 | 95 | Optional: 96 | 97 | - `create` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). 98 | - `update` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). 99 | 100 | 101 | 102 | ### Nested Schema for `kubernetes_client_configuration` 103 | 104 | Read-Only: 105 | 106 | - `ca_certificate` (String) The kubernetes CA certificate 107 | - `client_certificate` (String) The kubernetes client certificate 108 | - `client_key` (String, Sensitive) The kubernetes client key 109 | - `host` (String) The kubernetes host 110 | 111 | -------------------------------------------------------------------------------- /docs/resources/image_factory_schematic.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "talos_image_factory_schematic Resource - talos" 3 | subcategory: "" 4 | description: |- 5 | The image factory schematic resource allows you to create a schematic for a Talos image. 6 | --- 7 | 8 | # talos_image_factory_schematic (Resource) 9 | 10 | The image factory schematic resource allows you to create a schematic for a Talos image. 11 | 12 | ## Example Usage 13 | 14 | ```terraform 15 | provider "talos" {} 16 | 17 | data "talos_image_factory_extensions_versions" "this" { 18 | # get the latest talos version 19 | talos_version = "v1.7.5" 20 | filters = { 21 | names = [ 22 | "amdgpu", 23 | "tailscale", 24 | ] 25 | } 26 | } 27 | 28 | resource "talos_image_factory_schematic" "this" { 29 | schematic = yamlencode( 30 | { 31 | customization = { 32 | systemExtensions = { 33 | officialExtensions = data.talos_image_factory_extensions_versions.this.extensions_info.*.name 34 | } 35 | } 36 | } 37 | ) 38 | } 39 | 40 | output "schematic_id" { 41 | value = talos_image_factory_schematic.this.id 42 | } 43 | ``` 44 | 45 | ## Schema 46 | 47 | ### Optional 48 | 49 | - `schematic` (String) The schematic yaml respresentation to generate the image. 50 | 51 | If not set, a vanilla Talos image schematic will be generated. 52 | 53 | > Refer to [image-factory](https://github.com/siderolabs/image-factory?tab=readme-ov-file#post-schematics) for the schema. 54 | 55 | ### Read-Only 56 | 57 | - `id` (String) The unique ID of the schematic, returned from Image Factory. 58 | 59 | -------------------------------------------------------------------------------- /docs/resources/machine_bootstrap.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "talos_machine_bootstrap Resource - talos" 3 | subcategory: "" 4 | description: |- 5 | The machine bootstrap resource allows you to bootstrap a Talos node. 6 | --- 7 | 8 | # talos_machine_bootstrap (Resource) 9 | 10 | The machine bootstrap resource allows you to bootstrap a Talos node. 11 | 12 | ## Example Usage 13 | 14 | ```terraform 15 | resource "talos_machine_secrets" "this" {} 16 | 17 | data "talos_machine_configuration" "this" { 18 | cluster_name = "example-cluster" 19 | machine_type = "controlplane" 20 | cluster_endpoint = "https://cluster.local:6443" 21 | machine_secrets = talos_machine_secrets.this.machine_secrets 22 | } 23 | 24 | data "talos_client_configuration" "this" { 25 | cluster_name = "example-cluster" 26 | client_configuration = talos_machine_secrets.this.client_configuration 27 | nodes = ["10.5.0.2"] 28 | } 29 | 30 | resource "talos_machine_configuration_apply" "this" { 31 | client_configuration = talos_machine_secrets.this.client_configuration 32 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 33 | node = "10.5.0.2" 34 | config_patches = [ 35 | yamlencode({ 36 | machine = { 37 | install = { 38 | disk = "/dev/sdd" 39 | } 40 | } 41 | }) 42 | ] 43 | } 44 | 45 | resource "talos_machine_bootstrap" "this" { 46 | depends_on = [ 47 | talos_machine_configuration_apply.this 48 | ] 49 | node = "10.5.0.2" 50 | client_configuration = talos_machine_secrets.this.client_configuration 51 | } 52 | ``` 53 | 54 | ## Schema 55 | 56 | ### Required 57 | 58 | - `client_configuration` (Attributes) The client configuration data (see [below for nested schema](#nestedatt--client_configuration)) 59 | - `node` (String) The name of the node to bootstrap 60 | 61 | ### Optional 62 | 63 | - `endpoint` (String) The endpoint of the machine to bootstrap 64 | - `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) 65 | 66 | ### Read-Only 67 | 68 | - `id` (String) This is a unique identifier for the machine 69 | 70 | 71 | ### Nested Schema for `client_configuration` 72 | 73 | Required: 74 | 75 | - `ca_certificate` (String) The client CA certificate 76 | - `client_certificate` (String) The client certificate 77 | - `client_key` (String, Sensitive) The client key 78 | 79 | 80 | 81 | ### Nested Schema for `timeouts` 82 | 83 | Optional: 84 | 85 | - `create` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). 86 | ## Import 87 | 88 | Import is supported using the following syntax: 89 | 90 | ```terraform 91 | # machine bootstrap can be imported to let terraform know that the machine is already bootstrapped 92 | terraform import talos_machine_bootstrap.this 93 | ``` 94 | -------------------------------------------------------------------------------- /docs/resources/machine_configuration_apply.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "talos_machine_configuration_apply Resource - talos" 3 | subcategory: "" 4 | description: |- 5 | The machine configuration apply resource allows to apply machine configuration to a node 6 | --- 7 | 8 | # talos_machine_configuration_apply (Resource) 9 | 10 | The machine configuration apply resource allows to apply machine configuration to a node 11 | 12 | ## Example Usage 13 | 14 | ```terraform 15 | resource "talos_machine_secrets" "this" {} 16 | 17 | data "talos_machine_configuration" "this" { 18 | cluster_name = "example-cluster" 19 | machine_type = "controlplane" 20 | cluster_endpoint = "https://cluster.local:6443" 21 | machine_secrets = talos_machine_secrets.this.machine_secrets 22 | } 23 | 24 | data "talos_client_configuration" "this" { 25 | cluster_name = "example-cluster" 26 | client_configuration = talos_machine_secrets.this.client_configuration 27 | nodes = ["10.5.0.2"] 28 | } 29 | 30 | resource "talos_machine_configuration_apply" "this" { 31 | client_configuration = talos_machine_secrets.this.client_configuration 32 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 33 | node = "10.5.0.2" 34 | config_patches = [ 35 | yamlencode({ 36 | machine = { 37 | install = { 38 | disk = "/dev/sdd" 39 | } 40 | } 41 | }) 42 | ] 43 | } 44 | ``` 45 | 46 | ## Schema 47 | 48 | ### Required 49 | 50 | - `client_configuration` (Attributes) The client configuration data (see [below for nested schema](#nestedatt--client_configuration)) 51 | - `machine_configuration_input` (String, Sensitive) The machine configuration to apply 52 | - `node` (String) The name of the node to bootstrap 53 | 54 | ### Optional 55 | 56 | - `apply_mode` (String) The mode of the apply operation 57 | - `config_patches` (List of String) The list of config patches to apply 58 | - `endpoint` (String) The endpoint of the machine to bootstrap 59 | - `on_destroy` (Attributes) Actions to be taken on destroy, if *reset* is not set this is a no-op. 60 | 61 | > Note: Any changes to *on_destroy* block has to be applied first by running *terraform apply* first, 62 | then a subsequent *terraform destroy* for the changes to take effect due to limitations in Terraform provider framework. (see [below for nested schema](#nestedatt--on_destroy)) 63 | - `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) 64 | 65 | ### Read-Only 66 | 67 | - `id` (String) This is a unique identifier for the machine 68 | - `machine_configuration` (String, Sensitive) The generated machine configuration after applying patches 69 | 70 | 71 | ### Nested Schema for `client_configuration` 72 | 73 | Required: 74 | 75 | - `ca_certificate` (String) The client CA certificate 76 | - `client_certificate` (String) The client certificate 77 | - `client_key` (String, Sensitive) The client key 78 | 79 | 80 | 81 | ### Nested Schema for `on_destroy` 82 | 83 | Optional: 84 | 85 | - `graceful` (Boolean) Graceful indicates whether node should leave etcd before the upgrade, it also enforces etcd checks before leaving. Default true 86 | - `reboot` (Boolean) Reboot indicates whether node should reboot or halt after resetting. Default false 87 | - `reset` (Boolean) Reset the machine to the initial state (STATE and EPHEMERAL will be wiped). Default false 88 | 89 | 90 | 91 | ### Nested Schema for `timeouts` 92 | 93 | Optional: 94 | 95 | - `create` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). 96 | - `delete` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Setting a timeout for a Delete operation is only applicable if changes are saved into state before the destroy operation occurs. 97 | - `update` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). 98 | 99 | -------------------------------------------------------------------------------- /docs/resources/machine_secrets.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "talos_machine_secrets Resource - talos" 3 | subcategory: "" 4 | description: |- 5 | Generate machine secrets for Talos cluster. 6 | --- 7 | 8 | # talos_machine_secrets (Resource) 9 | 10 | Generate machine secrets for Talos cluster. 11 | 12 | ## Example Usage 13 | 14 | ```terraform 15 | resource "talos_machine_secrets" "machine_secrets" {} 16 | ``` 17 | 18 | ## Schema 19 | 20 | ### Optional 21 | 22 | - `talos_version` (String) The version of talos features to use in generated machine configuration 23 | 24 | ### Read-Only 25 | 26 | - `client_configuration` (Attributes) The generated client configuration data (see [below for nested schema](#nestedatt--client_configuration)) 27 | - `id` (String) The computed ID of the Talos cluster 28 | - `machine_secrets` (Attributes) The secrets for the talos cluster (see [below for nested schema](#nestedatt--machine_secrets)) 29 | 30 | 31 | ### Nested Schema for `client_configuration` 32 | 33 | Read-Only: 34 | 35 | - `ca_certificate` (String) The client CA certificate 36 | - `client_certificate` (String) The client certificate 37 | - `client_key` (String, Sensitive) The client key 38 | 39 | 40 | 41 | ### Nested Schema for `machine_secrets` 42 | 43 | Read-Only: 44 | 45 | - `certs` (Attributes) (see [below for nested schema](#nestedatt--machine_secrets--certs)) 46 | - `cluster` (Attributes) The cluster secrets (see [below for nested schema](#nestedatt--machine_secrets--cluster)) 47 | - `secrets` (Attributes) kubernetes cluster secrets (see [below for nested schema](#nestedatt--machine_secrets--secrets)) 48 | - `trustdinfo` (Attributes) trustd secrets (see [below for nested schema](#nestedatt--machine_secrets--trustdinfo)) 49 | 50 | 51 | ### Nested Schema for `machine_secrets.certs` 52 | 53 | Read-Only: 54 | 55 | - `etcd` (Attributes) The certificate and key pair (see [below for nested schema](#nestedatt--machine_secrets--certs--etcd)) 56 | - `k8s` (Attributes) The certificate and key pair (see [below for nested schema](#nestedatt--machine_secrets--certs--k8s)) 57 | - `k8s_aggregator` (Attributes) The certificate and key pair (see [below for nested schema](#nestedatt--machine_secrets--certs--k8s_aggregator)) 58 | - `k8s_serviceaccount` (Attributes) The service account secrets (see [below for nested schema](#nestedatt--machine_secrets--certs--k8s_serviceaccount)) 59 | - `os` (Attributes) The certificate and key pair (see [below for nested schema](#nestedatt--machine_secrets--certs--os)) 60 | 61 | 62 | ### Nested Schema for `machine_secrets.certs.etcd` 63 | 64 | Read-Only: 65 | 66 | - `cert` (String) certificate data 67 | - `key` (String, Sensitive) key data 68 | 69 | 70 | 71 | ### Nested Schema for `machine_secrets.certs.k8s` 72 | 73 | Read-Only: 74 | 75 | - `cert` (String) certificate data 76 | - `key` (String, Sensitive) key data 77 | 78 | 79 | 80 | ### Nested Schema for `machine_secrets.certs.k8s_aggregator` 81 | 82 | Read-Only: 83 | 84 | - `cert` (String) certificate data 85 | - `key` (String, Sensitive) key data 86 | 87 | 88 | 89 | ### Nested Schema for `machine_secrets.certs.k8s_serviceaccount` 90 | 91 | Read-Only: 92 | 93 | - `key` (String, Sensitive) The service account key 94 | 95 | 96 | 97 | ### Nested Schema for `machine_secrets.certs.os` 98 | 99 | Read-Only: 100 | 101 | - `cert` (String) certificate data 102 | - `key` (String, Sensitive) key data 103 | 104 | 105 | 106 | 107 | ### Nested Schema for `machine_secrets.cluster` 108 | 109 | Read-Only: 110 | 111 | - `id` (String) The cluster ID 112 | - `secret` (String, Sensitive) The cluster secret 113 | 114 | 115 | 116 | ### Nested Schema for `machine_secrets.secrets` 117 | 118 | Read-Only: 119 | 120 | - `aescbc_encryption_secret` (String, Sensitive) The AES-CBC encryption secret 121 | - `bootstrap_token` (String, Sensitive) The bootstrap token 122 | - `secretbox_encryption_secret` (String, Sensitive) The secretbox encryption secret 123 | 124 | 125 | 126 | ### Nested Schema for `machine_secrets.trustdinfo` 127 | 128 | Read-Only: 129 | 130 | - `token` (String, Sensitive) The trustd token 131 | ## Import 132 | 133 | Import is supported using the following syntax: 134 | 135 | ```terraform 136 | # machine secrets can be imported from an existing secrets file 137 | terraform import talos_machine_secrets.this 138 | ``` 139 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Talos provider examples 2 | 3 | This directory contains a set of examples on using the Talos provider. 4 | -------------------------------------------------------------------------------- /examples/data-sources/talos_client_configuration/data-source.tf: -------------------------------------------------------------------------------- 1 | resource "talos_machine_secrets" "this" {} 2 | 3 | data "talos_client_configuration" "this" { 4 | cluster_name = "example-cluster" 5 | client_configuration = talos_machine_secrets.this.client_configuration 6 | nodes = ["10.5.0.2"] 7 | } 8 | -------------------------------------------------------------------------------- /examples/data-sources/talos_cluster_kubeconfig/data-source.tf: -------------------------------------------------------------------------------- 1 | resource "talos_machine_secrets" "this" {} 2 | 3 | data "talos_machine_configuration" "this" { 4 | cluster_name = "example-cluster" 5 | machine_type = "controlplane" 6 | cluster_endpoint = "https://cluster.local:6443" 7 | machine_secrets = talos_machine_secrets.this.machine_secrets 8 | } 9 | 10 | data "talos_client_configuration" "this" { 11 | cluster_name = "example-cluster" 12 | client_configuration = talos_machine_secrets.this.client_configuration 13 | nodes = ["10.5.0.2"] 14 | } 15 | 16 | resource "talos_machine_configuration_apply" "this" { 17 | client_configuration = talos_machine_secrets.this.client_configuration 18 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 19 | node = "10.5.0.2" 20 | config_patches = [ 21 | yamlencode({ 22 | machine = { 23 | install = { 24 | disk = "/dev/sdd" 25 | } 26 | } 27 | }) 28 | ] 29 | } 30 | 31 | resource "talos_machine_bootstrap" "this" { 32 | depends_on = [ 33 | talos_machine_configuration_apply.this 34 | ] 35 | node = "10.5.0.2" 36 | client_configuration = talos_machine_secrets.this.client_configuration 37 | } 38 | 39 | 40 | data "talos_cluster_kubeconfig" "this" { 41 | depends_on = [ 42 | talos_machine_bootstrap.this 43 | ] 44 | client_configuration = talos_machine_secrets.this.client_configuration 45 | node = "10.5.0.2" 46 | } 47 | -------------------------------------------------------------------------------- /examples/data-sources/talos_image_factory_extensions_versions/data-source.tf: -------------------------------------------------------------------------------- 1 | provider "talos" {} 2 | 3 | data "talos_image_factory_extensions_versions" "this" { 4 | # get the latest talos version 5 | talos_version = "v1.7.5" 6 | filters = { 7 | names = [ 8 | "amdgpu", 9 | "tailscale", 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/data-sources/talos_image_factory_overlays_versions/data-source.tf: -------------------------------------------------------------------------------- 1 | provider "talos" {} 2 | 3 | data "talos_image_factory_overlays_versions" "this" { 4 | # get the latest talos version 5 | talos_version = "v1.7.5" 6 | filters = { 7 | name = "rock4cplus" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/data-sources/talos_image_factory_urls/data-source.tf: -------------------------------------------------------------------------------- 1 | data "talos_image_factory_urls" "this" { 2 | talos_version = "v1.7.5" 3 | schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba" 4 | platform = "metal" 5 | } 6 | 7 | output "installer_image" { 8 | value = data.talos_image_factory_urls.this.urls.installer 9 | } 10 | -------------------------------------------------------------------------------- /examples/data-sources/talos_image_factory_versions/data-source.tf: -------------------------------------------------------------------------------- 1 | provider "talos" {} 2 | 3 | data "talos_image_factory_versions" "this" {} 4 | 5 | output "latest" { 6 | value = element(data.talos_image_factory_versions.this.talos_versions, length(data.talos_image_factory_versions.this.talos_versions) - 1) 7 | } 8 | -------------------------------------------------------------------------------- /examples/data-sources/talos_machine_configuration/data-source.tf: -------------------------------------------------------------------------------- 1 | resource "talos_machine_secrets" "this" {} 2 | 3 | data "talos_machine_configuration" "this" { 4 | cluster_name = "example-cluster" 5 | machine_type = "controlplane" 6 | cluster_endpoint = "https://cluster.local:6443" 7 | machine_secrets = talos_machine_secrets.this.machine_secrets 8 | } 9 | -------------------------------------------------------------------------------- /examples/data-sources/talos_machine_disks/data-source.tf: -------------------------------------------------------------------------------- 1 | resource "talos_machine_secrets" "this" {} 2 | 3 | data "talos_machine_disks" "this" { 4 | client_configuration = talos_machine_secrets.this.client_configuration 5 | node = "10.5.0.2" 6 | selector = "disk.size > 6u * GB" 7 | } 8 | 9 | # for example, this could be used to pass in a list of disks to rook-ceph 10 | output "nvme_disks" { 11 | value = data.talos_machine_disks.this.disks.*.name 12 | } 13 | -------------------------------------------------------------------------------- /examples/resources/talos_cluster_kubeconfig/resource.tf: -------------------------------------------------------------------------------- 1 | resource "talos_machine_secrets" "this" {} 2 | 3 | data "talos_machine_configuration" "this" { 4 | cluster_name = "example-cluster" 5 | machine_type = "controlplane" 6 | cluster_endpoint = "https://cluster.local:6443" 7 | machine_secrets = talos_machine_secrets.this.machine_secrets 8 | } 9 | 10 | data "talos_client_configuration" "this" { 11 | cluster_name = "example-cluster" 12 | client_configuration = talos_machine_secrets.this.client_configuration 13 | nodes = ["10.5.0.2"] 14 | } 15 | 16 | resource "talos_machine_configuration_apply" "this" { 17 | client_configuration = talos_machine_secrets.this.client_configuration 18 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 19 | node = "10.5.0.2" 20 | config_patches = [ 21 | yamlencode({ 22 | machine = { 23 | install = { 24 | disk = "/dev/sdd" 25 | } 26 | } 27 | }) 28 | ] 29 | } 30 | 31 | resource "talos_machine_bootstrap" "this" { 32 | depends_on = [ 33 | talos_machine_configuration_apply.this 34 | ] 35 | node = "10.5.0.2" 36 | client_configuration = talos_machine_secrets.this.client_configuration 37 | } 38 | 39 | 40 | resource "talos_cluster_kubeconfig" "this" { 41 | depends_on = [ 42 | talos_machine_bootstrap.this 43 | ] 44 | client_configuration = talos_machine_secrets.this.client_configuration 45 | node = "10.5.0.2" 46 | } 47 | -------------------------------------------------------------------------------- /examples/resources/talos_image_factory_schematic/resource.tf: -------------------------------------------------------------------------------- 1 | provider "talos" {} 2 | 3 | data "talos_image_factory_extensions_versions" "this" { 4 | # get the latest talos version 5 | talos_version = "v1.7.5" 6 | filters = { 7 | names = [ 8 | "amdgpu", 9 | "tailscale", 10 | ] 11 | } 12 | } 13 | 14 | resource "talos_image_factory_schematic" "this" { 15 | schematic = yamlencode( 16 | { 17 | customization = { 18 | systemExtensions = { 19 | officialExtensions = data.talos_image_factory_extensions_versions.this.extensions_info.*.name 20 | } 21 | } 22 | } 23 | ) 24 | } 25 | 26 | output "schematic_id" { 27 | value = talos_image_factory_schematic.this.id 28 | } 29 | -------------------------------------------------------------------------------- /examples/resources/talos_machine_bootstrap/import.sh: -------------------------------------------------------------------------------- 1 | # machine bootstrap can be imported to let terraform know that the machine is already bootstrapped 2 | terraform import talos_machine_bootstrap.this 3 | -------------------------------------------------------------------------------- /examples/resources/talos_machine_bootstrap/resource.tf: -------------------------------------------------------------------------------- 1 | resource "talos_machine_secrets" "this" {} 2 | 3 | data "talos_machine_configuration" "this" { 4 | cluster_name = "example-cluster" 5 | machine_type = "controlplane" 6 | cluster_endpoint = "https://cluster.local:6443" 7 | machine_secrets = talos_machine_secrets.this.machine_secrets 8 | } 9 | 10 | data "talos_client_configuration" "this" { 11 | cluster_name = "example-cluster" 12 | client_configuration = talos_machine_secrets.this.client_configuration 13 | nodes = ["10.5.0.2"] 14 | } 15 | 16 | resource "talos_machine_configuration_apply" "this" { 17 | client_configuration = talos_machine_secrets.this.client_configuration 18 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 19 | node = "10.5.0.2" 20 | config_patches = [ 21 | yamlencode({ 22 | machine = { 23 | install = { 24 | disk = "/dev/sdd" 25 | } 26 | } 27 | }) 28 | ] 29 | } 30 | 31 | resource "talos_machine_bootstrap" "this" { 32 | depends_on = [ 33 | talos_machine_configuration_apply.this 34 | ] 35 | node = "10.5.0.2" 36 | client_configuration = talos_machine_secrets.this.client_configuration 37 | } 38 | -------------------------------------------------------------------------------- /examples/resources/talos_machine_configuration_apply/resource.tf: -------------------------------------------------------------------------------- 1 | resource "talos_machine_secrets" "this" {} 2 | 3 | data "talos_machine_configuration" "this" { 4 | cluster_name = "example-cluster" 5 | machine_type = "controlplane" 6 | cluster_endpoint = "https://cluster.local:6443" 7 | machine_secrets = talos_machine_secrets.this.machine_secrets 8 | } 9 | 10 | data "talos_client_configuration" "this" { 11 | cluster_name = "example-cluster" 12 | client_configuration = talos_machine_secrets.this.client_configuration 13 | nodes = ["10.5.0.2"] 14 | } 15 | 16 | resource "talos_machine_configuration_apply" "this" { 17 | client_configuration = talos_machine_secrets.this.client_configuration 18 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 19 | node = "10.5.0.2" 20 | config_patches = [ 21 | yamlencode({ 22 | machine = { 23 | install = { 24 | disk = "/dev/sdd" 25 | } 26 | } 27 | }) 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /examples/resources/talos_machine_secrets/import.sh: -------------------------------------------------------------------------------- 1 | # machine secrets can be imported from an existing secrets file 2 | terraform import talos_machine_secrets.this 3 | -------------------------------------------------------------------------------- /examples/resources/talos_machine_secrets/resource.tf: -------------------------------------------------------------------------------- 1 | resource "talos_machine_secrets" "machine_secrets" {} 2 | -------------------------------------------------------------------------------- /hack/release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. 4 | # 5 | # Generated on 2024-08-29T12:20:48Z by kres b5ca957. 6 | 7 | set -e 8 | 9 | RELEASE_TOOL_IMAGE="ghcr.io/siderolabs/release-tool:latest" 10 | 11 | function release-tool { 12 | docker pull "${RELEASE_TOOL_IMAGE}" >/dev/null 13 | docker run --rm -w /src -v "${PWD}":/src:ro "${RELEASE_TOOL_IMAGE}" -l -d -n -t "${1}" ./hack/release.toml 14 | } 15 | 16 | function changelog { 17 | if [ "$#" -eq 1 ]; then 18 | (release-tool ${1}; echo; cat CHANGELOG.md) > CHANGELOG.md- && mv CHANGELOG.md- CHANGELOG.md 19 | else 20 | echo 1>&2 "Usage: $0 changelog [tag]" 21 | exit 1 22 | fi 23 | } 24 | 25 | function release-notes { 26 | release-tool "${2}" > "${1}" 27 | } 28 | 29 | function cherry-pick { 30 | if [ $# -ne 2 ]; then 31 | echo 1>&2 "Usage: $0 cherry-pick " 32 | exit 1 33 | fi 34 | 35 | git checkout $2 36 | git fetch 37 | git rebase upstream/$2 38 | git cherry-pick -x $1 39 | } 40 | 41 | function commit { 42 | if [ $# -ne 1 ]; then 43 | echo 1>&2 "Usage: $0 commit " 44 | exit 1 45 | fi 46 | 47 | if is_on_main_branch; then 48 | update_license_files 49 | fi 50 | 51 | git commit -s -m "release($1): prepare release" -m "This is the official $1 release." 52 | } 53 | 54 | function is_on_main_branch { 55 | main_remotes=("upstream" "origin") 56 | branch_names=("main" "master") 57 | current_branch=$(git rev-parse --abbrev-ref HEAD) 58 | 59 | echo "Check current branch: $current_branch" 60 | 61 | for remote in "${main_remotes[@]}"; do 62 | echo "Fetch remote $remote..." 63 | 64 | if ! git fetch --quiet "$remote" &>/dev/null; then 65 | echo "Failed to fetch $remote, skip..." 66 | 67 | continue 68 | fi 69 | 70 | for branch_name in "${branch_names[@]}"; do 71 | if ! git rev-parse --verify "$branch_name" &>/dev/null; then 72 | echo "Branch $branch_name does not exist, skip..." 73 | 74 | continue 75 | fi 76 | 77 | echo "Branch $remote/$branch_name exists, comparing..." 78 | 79 | merge_base=$(git merge-base "$current_branch" "$remote/$branch_name") 80 | latest_main=$(git rev-parse "$remote/$branch_name") 81 | 82 | if [ "$merge_base" = "$latest_main" ]; then 83 | echo "Current branch is up-to-date with $remote/$branch_name" 84 | 85 | return 0 86 | else 87 | echo "Current branch is not on $remote/$branch_name" 88 | 89 | return 1 90 | fi 91 | done 92 | done 93 | 94 | echo "No main or master branch found on any remote" 95 | 96 | return 1 97 | } 98 | 99 | function update_license_files { 100 | script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 101 | parent_dir="$(dirname "$script_dir")" 102 | current_year=$(date +"%Y") 103 | change_date=$(date -v+4y +"%Y-%m-%d" 2>/dev/null || date -d "+4 years" +"%Y-%m-%d" 2>/dev/null || date --date="+4 years" +"%Y-%m-%d") 104 | 105 | # Find LICENSE and .kres.yaml files recursively in the parent directory (project root) 106 | find "$parent_dir" \( -name "LICENSE" -o -name ".kres.yaml" \) -type f | while read -r file; do 107 | temp_file="${file}.tmp" 108 | 109 | if [[ $file == *"LICENSE" ]]; then 110 | if grep -q "^Business Source License" "$file"; then 111 | sed -e "s/The Licensed Work is (c) [0-9]\{4\}/The Licensed Work is (c) $current_year/" \ 112 | -e "s/Change Date: [0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}/Change Date: $change_date/" \ 113 | "$file" >"$temp_file" 114 | else 115 | continue # Not a Business Source License file 116 | fi 117 | elif [[ $file == *".kres.yaml" ]]; then 118 | sed -E 's/^([[:space:]]*)ChangeDate:.*$/\1ChangeDate: "'"$change_date"'"/' "$file" >"$temp_file" 119 | fi 120 | 121 | # Check if the file has changed 122 | if ! cmp -s "$file" "$temp_file"; then 123 | mv "$temp_file" "$file" 124 | echo "Updated: $file" 125 | git add "$file" 126 | else 127 | echo "No changes: $file" 128 | rm "$temp_file" 129 | fi 130 | done 131 | } 132 | 133 | if declare -f "$1" > /dev/null 134 | then 135 | cmd="$1" 136 | shift 137 | $cmd "$@" 138 | else 139 | cat < ", os.Args[0]) 49 | } 50 | 51 | resourceType := os.Args[1] 52 | resourceName := strings.ToLower(strings.Split(resourceType, ".")[1]) 53 | 54 | resource, ok := resourceMaps()[resourceType] 55 | if !ok { 56 | log.Fatalf("unknown type: %s", resourceType) 57 | } 58 | 59 | blockDiskSpecStruct := reflect.TypeOf(resource) 60 | 61 | g.Printf("type %s struct {\n", resourceName) 62 | for i := range blockDiskSpecStruct.NumField() { 63 | tfType, err := mapGoTypesToTFTypes(blockDiskSpecStruct.Field(i).Type) 64 | if err != nil { 65 | log.Fatalf("failed to map type %s: %v", blockDiskSpecStruct.Field(i).Type.Name(), err) 66 | } 67 | 68 | g.Printf("\t%s %s `tfsdk:\"%s\"`\n", 69 | blockDiskSpecStruct.Field(i).Name, 70 | tfType, 71 | strings.ReplaceAll(blockDiskSpecStruct.Field(i).Tag.Get("yaml"), ",omitempty", ""), 72 | ) 73 | 74 | } 75 | g.Printf("}\n") 76 | g.Printf("\n") 77 | 78 | g.Printf("var %sAttributes = map[string]schema.Attribute{\n", resourceName) 79 | for i := 0; i < blockDiskSpecStruct.NumField(); i++ { 80 | attributeType, err := mapGoTypesToTFAttributeSpec(blockDiskSpecStruct.Field(i).Type) 81 | if err != nil { 82 | log.Fatalf("failed to map type %s: %v", blockDiskSpecStruct.Field(i).Type.Name(), err) 83 | } 84 | 85 | g.Printf("\t\"%s\": %s,\n", 86 | strings.ReplaceAll(blockDiskSpecStruct.Field(i).Tag.Get("yaml"), ",omitempty", ""), 87 | attributeType, 88 | ) 89 | } 90 | g.Printf("}\n") 91 | 92 | g.Printf("func %sToTFTypes(%sSpec %s) %s {\n", resourceName, resourceName, resourceType, resourceName) 93 | g.Printf("\treturn %s{\n", resourceName) 94 | 95 | for i := 0; i < blockDiskSpecStruct.NumField(); i++ { 96 | tfType, err := mapStructTypeToTFType(blockDiskSpecStruct.Field(i), resourceName) 97 | if err != nil { 98 | log.Fatalf("failed to map type %s: %v", blockDiskSpecStruct.Field(i).Type.Name(), err) 99 | } 100 | 101 | g.Printf("\t\t%s: %s,\n", 102 | blockDiskSpecStruct.Field(i).Name, 103 | tfType, 104 | ) 105 | } 106 | 107 | g.Printf("\t}\n") 108 | g.Printf("}\n") 109 | 110 | src := g.format() 111 | 112 | if err := os.WriteFile(fmt.Sprintf("%s_types.go", os.Args[2]), src, 0o644); err != nil { 113 | log.Fatalf("failed to write file: %v", err) 114 | } 115 | } 116 | 117 | type Generator struct { 118 | buf bytes.Buffer 119 | } 120 | 121 | func (g *Generator) Printf(format string, args ...interface{}) { 122 | fmt.Fprintf(&g.buf, format, args...) 123 | } 124 | 125 | // format returns the gofmt-ed contents of the Generator's buffer. 126 | func (g *Generator) format() []byte { 127 | src, err := format.Source(g.buf.Bytes()) 128 | if err != nil { 129 | // Should never happen, but can arise when developing this code. 130 | // The user can compile the output to see the error. 131 | log.Printf("warning: internal error: invalid Go generated: %s", err) 132 | log.Printf("warning: compile the package to analyze the error") 133 | return g.buf.Bytes() 134 | } 135 | 136 | return src 137 | } 138 | 139 | func mapGoTypesToTFTypes(goType reflect.Type) (string, error) { 140 | // handle the case where the field is a slice 141 | if goType.Kind() == reflect.Slice { 142 | switch goType.Elem().Kind() { 143 | case reflect.String: 144 | return "types.List", nil 145 | default: 146 | return "", fmt.Errorf("unsupported slice type: %s", goType.Elem().Name()) 147 | } 148 | } 149 | 150 | switch goType.Name() { 151 | case "string": 152 | return "types.String", nil 153 | case "uint", "uint64", "int", "int64": 154 | return "types.Int64", nil 155 | case "bool": 156 | return "types.Bool", nil 157 | default: 158 | return "", fmt.Errorf("unsupported type: %s", goType.Name()) 159 | } 160 | } 161 | 162 | func mapGoTypesToTFAttributeSpec(goType reflect.Type) (string, error) { 163 | // handle the case where the field is a slice 164 | if goType.Kind() == reflect.Slice { 165 | switch goType.Elem().Kind() { 166 | case reflect.String: 167 | return `schema.ListAttribute{ 168 | ElementType: types.StringType, 169 | Computed: true, 170 | }`, nil 171 | default: 172 | return "", fmt.Errorf("unsupported slice type: %s", goType.Elem().Name()) 173 | } 174 | } 175 | 176 | switch goType.Name() { 177 | case "string": 178 | return `schema.StringAttribute{ 179 | Computed: true, 180 | }`, nil 181 | case "uint", "uint64", "int", "int64": 182 | return `schema.Int64Attribute{ 183 | Computed: true, 184 | }`, nil 185 | case "bool": 186 | return `schema.BoolAttribute{ 187 | Computed: true, 188 | }`, nil 189 | default: 190 | return "", fmt.Errorf("unsupported type: %s", goType.Name()) 191 | } 192 | } 193 | 194 | func mapStructTypeToTFType(structField reflect.StructField, resourceName string) (string, error) { 195 | // handle the case where the field is a slice 196 | if structField.Type.Kind() == reflect.Slice { 197 | switch structField.Type.Elem().Kind() { 198 | case reflect.String: 199 | return fmt.Sprintf(`types.ListValueMust(types.StringType, xslices.Map(%sSpec.%s, func(s string) attr.Value { 200 | return types.StringValue(s) 201 | }))`, resourceName, structField.Name), nil 202 | default: 203 | return "", fmt.Errorf("unsupported slice type: %s", structField.Type.Elem().Name()) 204 | } 205 | } 206 | 207 | switch structField.Type.Name() { 208 | case "string": 209 | return fmt.Sprintf("types.StringValue(%sSpec.%s)", resourceName, structField.Name), nil 210 | case "uint", "uint64", "int", "int64": 211 | return fmt.Sprintf("types.Int64Value(int64(%sSpec.%s))", resourceName, structField.Name), nil 212 | case "bool": 213 | return fmt.Sprintf("types.BoolValue(%sSpec.%s)", resourceName, structField.Name), nil 214 | default: 215 | return "", fmt.Errorf("unsupported type: %s", structField.Type.Name()) 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /pkg/talos/provider.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | // Package talos is a Terraform provider for Talos. 6 | package talos 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/hashicorp/terraform-plugin-framework/datasource" 12 | "github.com/hashicorp/terraform-plugin-framework/provider" 13 | "github.com/hashicorp/terraform-plugin-framework/provider/schema" 14 | "github.com/hashicorp/terraform-plugin-framework/resource" 15 | "github.com/hashicorp/terraform-plugin-framework/types" 16 | "github.com/siderolabs/image-factory/pkg/client" 17 | ) 18 | 19 | const ( 20 | // ImageFactoryURL is the default URL of Image Factory. 21 | ImageFactoryURL = "https://factory.talos.dev" 22 | ) 23 | 24 | // talosProvider is the provider implementation. 25 | type talosProvider struct{} 26 | 27 | type talosProviderModelV0 struct { 28 | ImageFactoryURL types.String `tfsdk:"image_factory_url"` 29 | } 30 | 31 | // New is a helper function to simplify provider server and testing implementation. 32 | func New() provider.Provider { 33 | return &talosProvider{} 34 | } 35 | 36 | // Metadata returns the provider type name. 37 | func (p *talosProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) { 38 | resp.TypeName = "talos" 39 | } 40 | 41 | // Schema defines the provider-level schema for configuration data. 42 | func (p *talosProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) { 43 | resp.Schema = schema.Schema{ 44 | Attributes: map[string]schema.Attribute{ 45 | "image_factory_url": schema.StringAttribute{ 46 | Optional: true, 47 | Description: "The URL of Image Factory to generate schematics. If not set defaults to https://factory.talos.dev.", 48 | }, 49 | }, 50 | } 51 | } 52 | 53 | // Configure prepares a Talos client for data sources and resources. 54 | func (p *talosProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { 55 | var config talosProviderModelV0 56 | 57 | resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) 58 | 59 | if resp.Diagnostics.HasError() { 60 | return 61 | } 62 | 63 | imageFactoryURL := config.ImageFactoryURL.ValueString() 64 | 65 | if imageFactoryURL == "" && !config.ImageFactoryURL.IsUnknown() { 66 | imageFactoryURL = ImageFactoryURL 67 | } 68 | 69 | imageFactoryClient, err := client.New(imageFactoryURL) 70 | if err != nil { 71 | resp.Diagnostics.AddError("failed to create Image Factory client", err.Error()) 72 | 73 | return 74 | } 75 | 76 | resp.DataSourceData = imageFactoryClient 77 | resp.ResourceData = imageFactoryClient 78 | } 79 | 80 | // DataSources defines the data sources implemented in the provider. 81 | func (p *talosProvider) DataSources(_ context.Context) []func() datasource.DataSource { 82 | return []func() datasource.DataSource{ 83 | NewTalosMachineDisksDataSource, 84 | NewTalosMachineConfigurationDataSource, 85 | NewTalosClientConfigurationDataSource, 86 | NewTalosClusterHealthDataSource, 87 | NewTalosClusterKubeConfigDataSource, 88 | NewTalosImageFactoryVersionsDataSource, 89 | NewTalosImageFactoryExtensionsVersionsDataSource, 90 | NewTalosImageFactoryOverlaysVersionsDataSource, 91 | NewTalosImageFactoryURLSDataSource, 92 | } 93 | } 94 | 95 | // Resources defines the resources implemented in the provider. 96 | func (p *talosProvider) Resources(_ context.Context) []func() resource.Resource { 97 | return []func() resource.Resource{ 98 | NewTalosMachineSecretsResource, 99 | NewTalosMachineConfigurationApplyResource, 100 | NewTalosMachineBootstrapResource, 101 | NewTalosClusterKubeConfigResource, 102 | NewTalosImageFactorySchematicResource, 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /pkg/talos/provider_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos_test 6 | 7 | import ( 8 | "fmt" 9 | "os" 10 | "strings" 11 | "text/template" 12 | 13 | "github.com/hashicorp/terraform-plugin-framework/providerserver" 14 | "github.com/hashicorp/terraform-plugin-go/tfprotov6" 15 | "github.com/siderolabs/talos/pkg/machinery/gendata" 16 | 17 | "github.com/siderolabs/terraform-provider-talos/pkg/talos" 18 | ) 19 | 20 | // testAccProtoV6ProviderFactories are used to instantiate a provider during 21 | // acceptance testing. The factory function will be invoked for every Terraform 22 | // CLI command executed to create a provider server to which the CLI can 23 | // reattach. 24 | var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){ 25 | "talos": providerserver.NewProtocol6WithError(talos.New()), 26 | } 27 | 28 | type dynamicConfig struct { 29 | Provider string 30 | ResourceName string 31 | IsoURL string 32 | CPUMode string 33 | WithApplyConfig bool 34 | WithBootstrap bool 35 | WithRetrieveKubeConfig bool 36 | WithClusterHealth bool 37 | } 38 | 39 | func (c *dynamicConfig) render() string { 40 | cpuMode := "host-passthrough" 41 | if os.Getenv("CI") != "" { 42 | cpuMode = "host-model" 43 | } 44 | 45 | c.CPUMode = cpuMode 46 | 47 | c.IsoURL = fmt.Sprintf("https://github.com/siderolabs/talos/releases/download/%s/metal-amd64.iso", gendata.VersionTag) 48 | 49 | configTemplate := ` 50 | resource "talos_machine_secrets" "this" {} 51 | 52 | resource "libvirt_volume" "cp" { 53 | name = "{{ .ResourceName }}" 54 | size = 6442450944 55 | } 56 | 57 | resource "libvirt_domain" "cp" { 58 | name = "{{ .ResourceName }}" 59 | firmware = "/usr/share/OVMF/OVMF_CODE.fd" 60 | lifecycle { 61 | ignore_changes = [ 62 | cpu, 63 | nvram, 64 | disk["url"], 65 | ] 66 | } 67 | cpu { 68 | mode = "{{ .CPUMode }}" 69 | } 70 | console { 71 | type = "pty" 72 | target_port = "0" 73 | } 74 | graphics { 75 | type = "vnc" 76 | listen_type = "address" 77 | } 78 | disk { 79 | url = "{{ .IsoURL }}" 80 | } 81 | disk { 82 | volume_id = libvirt_volume.cp.id 83 | } 84 | boot_device { 85 | dev = ["cdrom"] 86 | } 87 | network_interface { 88 | network_name = "default" 89 | wait_for_lease = true 90 | } 91 | vcpu = "2" 92 | memory = "4096" 93 | } 94 | 95 | {{ if eq .Provider "talosv1"}} 96 | resource "talos_client_configuration" "this" { 97 | cluster_name = "example-cluster" 98 | machine_secrets = talos_machine_secrets.this.machine_secrets 99 | } 100 | 101 | resource "talos_machine_configuration_controlplane" "this" { 102 | cluster_name = "example-cluster" 103 | cluster_endpoint = "https://${libvirt_domain.cp.network_interface[0].addresses[0]}:6443" 104 | machine_secrets = talos_machine_secrets.this.machine_secrets 105 | } 106 | 107 | {{ if .WithApplyConfig }} 108 | resource "talos_machine_configuration_apply" "this" { 109 | talos_config = talos_client_configuration.this.talos_config 110 | machine_configuration = talos_machine_configuration_controlplane.this.machine_config 111 | node = libvirt_domain.cp.network_interface[0].addresses[0] 112 | endpoint = libvirt_domain.cp.network_interface[0].addresses[0] 113 | config_patches = [ 114 | yamlencode({ 115 | machine = { 116 | install = { 117 | disk = "/dev/vda" 118 | } 119 | } 120 | }), 121 | ] 122 | } 123 | {{ end }} 124 | 125 | {{ if .WithBootstrap }} 126 | resource "talos_machine_bootstrap" "this" { 127 | depends_on = [ 128 | talos_machine_configuration_apply.this 129 | ] 130 | node = libvirt_domain.cp.network_interface[0].addresses[0] 131 | endpoint = libvirt_domain.cp.network_interface[0].addresses[0] 132 | talos_config = talos_client_configuration.this.talos_config 133 | } 134 | {{ end }} 135 | {{ else }} 136 | data "talos_machine_configuration" "this" { 137 | cluster_name = "example-cluster" 138 | cluster_endpoint = "https://${libvirt_domain.cp.network_interface[0].addresses[0]}:6443" 139 | machine_type = "controlplane" 140 | machine_secrets = talos_machine_secrets.this.machine_secrets 141 | docs = false 142 | examples = false 143 | } 144 | 145 | data "talos_machine_disks" "this" { 146 | client_configuration = talos_machine_secrets.this.client_configuration 147 | node = libvirt_domain.cp.network_interface[0].addresses[0] 148 | selector = "disk.size > 6u * GB" 149 | } 150 | 151 | {{ if .WithApplyConfig }} 152 | resource "talos_machine_configuration_apply" "this" { 153 | client_configuration = talos_machine_secrets.this.client_configuration 154 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 155 | node = libvirt_domain.cp.network_interface[0].addresses[0] 156 | config_patches = [ 157 | yamlencode({ 158 | machine = { 159 | install = { 160 | disk = data.talos_machine_disks.this.disks[0].dev_path 161 | } 162 | } 163 | }), 164 | ] 165 | } 166 | {{ end }} 167 | 168 | {{ if .WithBootstrap }} 169 | resource "talos_machine_bootstrap" "this" { 170 | depends_on = [ 171 | talos_machine_configuration_apply.this 172 | ] 173 | node = libvirt_domain.cp.network_interface[0].addresses[0] 174 | client_configuration = talos_machine_secrets.this.client_configuration 175 | } 176 | {{ end }} 177 | 178 | {{ if .WithRetrieveKubeConfig }} 179 | resource "talos_cluster_kubeconfig" "this" { 180 | depends_on = [ 181 | talos_machine_bootstrap.this 182 | ] 183 | client_configuration = talos_machine_secrets.this.client_configuration 184 | node = libvirt_domain.cp.network_interface[0].addresses[0] 185 | } 186 | {{ end }} 187 | 188 | {{ if .WithClusterHealth }} 189 | data "talos_cluster_health" "this" { 190 | depends_on = [ 191 | talos_cluster_kubeconfig.this 192 | ] 193 | 194 | timeouts = { 195 | read = "25m" 196 | } 197 | 198 | client_configuration = talos_machine_secrets.this.client_configuration 199 | endpoints = libvirt_domain.cp.network_interface[0].addresses 200 | control_plane_nodes = libvirt_domain.cp.network_interface[0].addresses 201 | } 202 | {{ end }} 203 | {{ end }} 204 | ` 205 | 206 | var config strings.Builder 207 | 208 | template.Must(template.New("tf_config").Parse(configTemplate)).Execute(&config, c) //nolint:errcheck 209 | 210 | return config.String() 211 | } 212 | -------------------------------------------------------------------------------- /pkg/talos/talos_client_configuration_data_source.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos 6 | 7 | import ( 8 | "context" 9 | 10 | "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" 11 | "github.com/hashicorp/terraform-plugin-framework/datasource" 12 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 13 | "github.com/hashicorp/terraform-plugin-framework/schema/validator" 14 | "github.com/hashicorp/terraform-plugin-framework/types" 15 | "github.com/hashicorp/terraform-plugin-framework/types/basetypes" 16 | ) 17 | 18 | type talosClientConfigurationDataSource struct{} 19 | 20 | type talosClientConfigurationDataSourceModelV0 struct { 21 | ID types.String `tfsdk:"id"` 22 | ClusterName types.String `tfsdk:"cluster_name"` 23 | ClientConfiguration clientConfiguration `tfsdk:"client_configuration"` 24 | Endpoints types.List `tfsdk:"endpoints"` 25 | Nodes types.List `tfsdk:"nodes"` 26 | TalosConfig types.String `tfsdk:"talos_config"` 27 | } 28 | 29 | var _ datasource.DataSource = &talosClientConfigurationDataSource{} 30 | 31 | // NewTalosClientConfigurationDataSource implements the datasource.DataSource interface. 32 | func NewTalosClientConfigurationDataSource() datasource.DataSource { 33 | return &talosClientConfigurationDataSource{} 34 | } 35 | 36 | func (d *talosClientConfigurationDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 37 | resp.TypeName = req.ProviderTypeName + "_client_configuration" 38 | } 39 | 40 | func (d *talosClientConfigurationDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { 41 | resp.Schema = schema.Schema{ 42 | Description: "Generate client configuration for a Talos cluster", 43 | Attributes: map[string]schema.Attribute{ 44 | "id": schema.StringAttribute{ 45 | Description: "The ID of this resource", 46 | Computed: true, 47 | }, 48 | "cluster_name": schema.StringAttribute{ 49 | Required: true, 50 | Description: "The name of the cluster in the generated config", 51 | Validators: []validator.String{ 52 | stringvalidator.LengthAtLeast(1), 53 | }, 54 | }, 55 | "client_configuration": schema.SingleNestedAttribute{ 56 | Attributes: map[string]schema.Attribute{ 57 | "ca_certificate": schema.StringAttribute{ 58 | Required: true, 59 | Description: "The client CA certificate", 60 | }, 61 | "client_certificate": schema.StringAttribute{ 62 | Required: true, 63 | Description: "The client certificate", 64 | }, 65 | "client_key": schema.StringAttribute{ 66 | Required: true, 67 | Sensitive: true, 68 | Description: "The client key", 69 | }, 70 | }, 71 | Required: true, 72 | Description: "The client configuration data", 73 | }, 74 | "endpoints": schema.ListAttribute{ 75 | ElementType: types.StringType, 76 | Optional: true, 77 | Description: "endpoints to set in the generated config", 78 | }, 79 | "nodes": schema.ListAttribute{ 80 | ElementType: types.StringType, 81 | Optional: true, 82 | Description: "nodes to set in the generated config", 83 | }, 84 | "talos_config": schema.StringAttribute{ 85 | Computed: true, 86 | Description: "The generated client configuration", 87 | Sensitive: true, 88 | }, 89 | }, 90 | } 91 | } 92 | 93 | func (d *talosClientConfigurationDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 94 | var state talosClientConfigurationDataSourceModelV0 95 | 96 | diags := req.Config.Get(ctx, &state) 97 | resp.Diagnostics.Append(diags...) 98 | 99 | if resp.Diagnostics.HasError() { 100 | return 101 | } 102 | 103 | var endpoints []string 104 | 105 | var nodes []string 106 | 107 | resp.Diagnostics.Append(state.Endpoints.ElementsAs(ctx, &endpoints, true)...) 108 | 109 | if resp.Diagnostics.HasError() { 110 | return 111 | } 112 | 113 | resp.Diagnostics.Append(state.Nodes.ElementsAs(ctx, &nodes, true)...) 114 | 115 | if resp.Diagnostics.HasError() { 116 | return 117 | } 118 | 119 | talosConfig, err := talosClientTFConfigToTalosClientConfig( 120 | state.ClusterName.ValueString(), 121 | state.ClientConfiguration.CA.ValueString(), 122 | state.ClientConfiguration.Cert.ValueString(), 123 | state.ClientConfiguration.Key.ValueString(), 124 | ) 125 | if err != nil { 126 | resp.Diagnostics.AddError("failed to generate talos config", err.Error()) 127 | 128 | return 129 | } 130 | 131 | if len(endpoints) > 0 { 132 | talosConfig.Contexts[state.ClusterName.ValueString()].Endpoints = endpoints 133 | } 134 | 135 | if len(nodes) > 0 { 136 | talosConfig.Contexts[state.ClusterName.ValueString()].Nodes = nodes 137 | } 138 | 139 | talosConfigStringBytes, err := talosConfig.Bytes() 140 | if err != nil { 141 | resp.Diagnostics.AddError("failed to generate talos config", err.Error()) 142 | 143 | return 144 | } 145 | 146 | state.TalosConfig = basetypes.NewStringValue(string(talosConfigStringBytes)) 147 | state.ID = state.ClusterName 148 | 149 | diags = resp.State.Set(ctx, &state) 150 | resp.Diagnostics.Append(diags...) 151 | 152 | if resp.Diagnostics.HasError() { 153 | return 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /pkg/talos/talos_client_configuration_data_source_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos_test 6 | 7 | import ( 8 | "strings" 9 | "testing" 10 | "text/template" 11 | 12 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 13 | "github.com/siderolabs/talos/pkg/machinery/client/config" 14 | "github.com/stretchr/testify/assert" 15 | "gopkg.in/yaml.v3" 16 | ) 17 | 18 | func TestAccTalosClientConfigurationDataSource(t *testing.T) { 19 | resource.ParallelTest(t, resource.TestCase{ 20 | IsUnitTest: true, // this is a local only resource, so can be unit tested 21 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 22 | Steps: []resource.TestStep{ 23 | // test data source with default values 24 | { 25 | Config: testAccTalosClientConfigurationDataSourceConfig("test-cluster", nil, nil), 26 | Check: resource.ComposeAggregateTestCheckFunc( 27 | resource.TestCheckResourceAttr("data.talos_client_configuration.this", "id", "test-cluster"), 28 | resource.TestCheckResourceAttr("data.talos_client_configuration.this", "cluster_name", "test-cluster"), 29 | resource.TestCheckResourceAttrSet("data.talos_client_configuration.this", "client_configuration.%"), 30 | resource.TestCheckResourceAttr("data.talos_client_configuration.this", "endpoints.#", "0"), 31 | resource.TestCheckResourceAttr("data.talos_client_configuration.this", "nodes.#", "0"), 32 | resource.TestCheckResourceAttrSet("data.talos_client_configuration.this", "talos_config"), 33 | resource.TestCheckResourceAttrWith("data.talos_client_configuration.this", "talos_config", func(value string) error { 34 | return validateTalosClientConfigContext(t, value, "test-cluster", nil, nil) 35 | }), 36 | ), 37 | }, 38 | // test data source with overrides 39 | { 40 | Config: testAccTalosClientConfigurationDataSourceConfig("test-cluster-1", []string{"10.5.0.2", "10.5.0.3"}, []string{"10.5.0.4"}), 41 | Check: resource.ComposeAggregateTestCheckFunc( 42 | resource.TestCheckResourceAttr("data.talos_client_configuration.this", "id", "test-cluster-1"), 43 | resource.TestCheckResourceAttr("data.talos_client_configuration.this", "cluster_name", "test-cluster-1"), 44 | resource.TestCheckResourceAttrSet("data.talos_client_configuration.this", "client_configuration.%"), 45 | resource.TestCheckResourceAttr("data.talos_client_configuration.this", "endpoints.0", "10.5.0.2"), 46 | resource.TestCheckResourceAttr("data.talos_client_configuration.this", "endpoints.1", "10.5.0.3"), 47 | resource.TestCheckResourceAttr("data.talos_client_configuration.this", "nodes.0", "10.5.0.4"), 48 | resource.TestCheckResourceAttrSet("data.talos_client_configuration.this", "talos_config"), 49 | resource.TestCheckResourceAttrWith("data.talos_client_configuration.this", "talos_config", func(value string) error { 50 | return validateTalosClientConfigContext(t, value, "test-cluster-1", []string{"10.5.0.2", "10.5.0.3"}, []string{"10.5.0.4"}) 51 | }), 52 | ), 53 | }, 54 | }, 55 | }) 56 | } 57 | 58 | func testAccTalosClientConfigurationDataSourceConfig(clusterName string, endpoints, nodes []string) string { 59 | configTemplate := ` 60 | resource "talos_machine_secrets" "this" {} 61 | 62 | data "talos_client_configuration" "this" { 63 | cluster_name = "{{ .ClusterName }}" 64 | client_configuration = talos_machine_secrets.this.client_configuration 65 | {{if .Endpoints }}endpoints = [{{- range .Endpoints }} 66 | "{{ . }}", 67 | {{- end }} 68 | ]{{end }} 69 | {{if .Nodes }}nodes = [{{- range .Nodes }} 70 | "{{ . }}", 71 | {{- end }} 72 | ]{{end }} 73 | } 74 | ` 75 | 76 | var config strings.Builder 77 | 78 | template.Must(template.New("tf_config").Parse(configTemplate)).Execute(&config, struct { //nolint:errcheck 79 | ClusterName string 80 | Endpoints []string 81 | Nodes []string 82 | }{ 83 | ClusterName: clusterName, 84 | Endpoints: endpoints, 85 | Nodes: nodes, 86 | }) 87 | 88 | return config.String() 89 | } 90 | 91 | func validateTalosClientConfigContext(t *testing.T, tc, contextName string, endpoints, nodes []string) error { 92 | var talosConfig config.Config 93 | 94 | if err := yaml.Unmarshal([]byte(tc), &talosConfig); err != nil { 95 | return err 96 | } 97 | 98 | assert.Equal(t, contextName, talosConfig.Context) 99 | 100 | if endpoints != nil { 101 | assert.Equal(t, endpoints, talosConfig.Contexts[contextName].Endpoints) 102 | } 103 | 104 | if nodes != nil { 105 | assert.Equal(t, nodes, talosConfig.Contexts[contextName].Nodes) 106 | } 107 | 108 | return nil 109 | } 110 | -------------------------------------------------------------------------------- /pkg/talos/talos_cluster_health_data_source.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "slices" 11 | "strings" 12 | "time" 13 | 14 | "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" 15 | "github.com/hashicorp/terraform-plugin-framework/datasource" 16 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 17 | "github.com/hashicorp/terraform-plugin-framework/types" 18 | "github.com/hashicorp/terraform-plugin-framework/types/basetypes" 19 | "github.com/siderolabs/talos/pkg/cluster" 20 | "github.com/siderolabs/talos/pkg/cluster/check" 21 | "github.com/siderolabs/talos/pkg/conditions" 22 | "github.com/siderolabs/talos/pkg/machinery/client" 23 | "github.com/siderolabs/talos/pkg/machinery/config/machine" 24 | ) 25 | 26 | type talosClusterHealthDataSource struct{} 27 | 28 | var _ datasource.DataSource = &talosClusterHealthDataSource{} 29 | 30 | type talosClusterHealthDataSourceModelV0 struct { 31 | ID types.String `tfsdk:"id"` 32 | Endpoints types.List `tfsdk:"endpoints"` 33 | ControlPlaneNodes types.List `tfsdk:"control_plane_nodes"` 34 | WorkerNodes types.List `tfsdk:"worker_nodes"` 35 | ClientConfiguration clientConfiguration `tfsdk:"client_configuration"` 36 | Timeouts timeouts.Value `tfsdk:"timeouts"` 37 | SkipKubernetesChecks types.Bool `tfsdk:"skip_kubernetes_checks"` 38 | } 39 | 40 | type clusterNodes struct { 41 | nodesByType map[machine.Type][]cluster.NodeInfo 42 | nodes []cluster.NodeInfo 43 | } 44 | 45 | func newClusterNodes(controlPlaneNodes, workerNodes []string) (*clusterNodes, error) { 46 | controlPlaneNodeInfos, err := cluster.IPsToNodeInfos(controlPlaneNodes) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | workerNodeInfos, err := cluster.IPsToNodeInfos(workerNodes) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | nodesByType := make(map[machine.Type][]cluster.NodeInfo) 57 | nodesByType[machine.TypeControlPlane] = controlPlaneNodeInfos 58 | nodesByType[machine.TypeWorker] = workerNodeInfos 59 | 60 | return &clusterNodes{ 61 | nodes: slices.Concat(controlPlaneNodeInfos, workerNodeInfos), 62 | nodesByType: nodesByType, 63 | }, nil 64 | } 65 | 66 | // Nodes returns cluster nodeinfos. 67 | func (c *clusterNodes) Nodes() []cluster.NodeInfo { 68 | return c.nodes 69 | } 70 | 71 | // NodesByType returns cluster nodeinfos by type. 72 | func (c *clusterNodes) NodesByType(t machine.Type) []cluster.NodeInfo { 73 | return c.nodesByType[t] 74 | } 75 | 76 | type reporter struct { 77 | lastLine string 78 | s strings.Builder 79 | } 80 | 81 | func newReporter() *reporter { 82 | return &reporter{} 83 | } 84 | 85 | // Update implements the conditions.Reporter interface. 86 | func (r *reporter) Update(condition conditions.Condition) { 87 | if condition.String() != r.lastLine { 88 | r.s.WriteString(fmt.Sprintf("waiting for %s\n", condition.String())) 89 | r.lastLine = condition.String() 90 | } 91 | } 92 | 93 | // String returns the string representation of the reporter. 94 | func (r *reporter) String() string { 95 | return r.s.String() 96 | } 97 | 98 | // NewTalosClusterHealthDataSource implements the datasource.DataSource interface. 99 | func NewTalosClusterHealthDataSource() datasource.DataSource { 100 | return &talosClusterHealthDataSource{} 101 | } 102 | 103 | func (d *talosClusterHealthDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 104 | resp.TypeName = req.ProviderTypeName + "_cluster_health" 105 | } 106 | 107 | func (d *talosClusterHealthDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { 108 | resp.Schema = schema.Schema{ 109 | Description: "Checks the health of a Talos cluster", 110 | MarkdownDescription: "Waits for the Talos cluster to be healthy. Can be used as a dependency before running other operations on the cluster.", 111 | Attributes: map[string]schema.Attribute{ 112 | "id": schema.StringAttribute{ 113 | Computed: true, 114 | }, 115 | "endpoints": schema.ListAttribute{ 116 | Required: true, 117 | ElementType: types.StringType, 118 | Description: "endpoints to use for the health check client. Use at least one control plane endpoint.", 119 | }, 120 | "control_plane_nodes": schema.ListAttribute{ 121 | Required: true, 122 | ElementType: types.StringType, 123 | Description: "List of control plane nodes to check for health.", 124 | }, 125 | "worker_nodes": schema.ListAttribute{ 126 | Optional: true, 127 | ElementType: types.StringType, 128 | Description: "List of worker nodes to check for health.", 129 | }, 130 | "skip_kubernetes_checks": schema.BoolAttribute{ 131 | Optional: true, 132 | Description: "Skip Kubernetes component checks, this is useful to check if the nodes has finished booting up and kubelet is running. Default is false.", 133 | }, 134 | "client_configuration": schema.SingleNestedAttribute{ 135 | Attributes: map[string]schema.Attribute{ 136 | "ca_certificate": schema.StringAttribute{ 137 | Required: true, 138 | Description: "The client CA certificate", 139 | }, 140 | "client_certificate": schema.StringAttribute{ 141 | Required: true, 142 | Description: "The client certificate", 143 | }, 144 | "client_key": schema.StringAttribute{ 145 | Required: true, 146 | Sensitive: true, 147 | Description: "The client key", 148 | }, 149 | }, 150 | Required: true, 151 | Description: "The client configuration data", 152 | }, 153 | "timeouts": timeouts.Attributes(ctx, timeouts.Opts{ 154 | Read: true, 155 | }), 156 | }, 157 | } 158 | } 159 | 160 | func (d *talosClusterHealthDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 161 | var state talosClusterHealthDataSourceModelV0 162 | 163 | diags := req.Config.Get(ctx, &state) 164 | resp.Diagnostics.Append(diags...) 165 | 166 | if resp.Diagnostics.HasError() { 167 | return 168 | } 169 | 170 | var ( 171 | endpoints []string 172 | controlPlaneNodes []string 173 | workerNodes []string 174 | ) 175 | 176 | resp.Diagnostics.Append(state.Endpoints.ElementsAs(ctx, &endpoints, true)...) 177 | 178 | if resp.Diagnostics.HasError() { 179 | return 180 | } 181 | 182 | resp.Diagnostics.Append(state.ControlPlaneNodes.ElementsAs(ctx, &controlPlaneNodes, true)...) 183 | 184 | if resp.Diagnostics.HasError() { 185 | return 186 | } 187 | 188 | resp.Diagnostics.Append(state.WorkerNodes.ElementsAs(ctx, &workerNodes, true)...) 189 | 190 | if resp.Diagnostics.HasError() { 191 | return 192 | } 193 | 194 | readTimeout, diags := state.Timeouts.Read(ctx, 10*time.Minute) 195 | resp.Diagnostics.Append(diags...) 196 | 197 | if resp.Diagnostics.HasError() { 198 | return 199 | } 200 | 201 | talosConfig, err := talosClientTFConfigToTalosClientConfig( 202 | "dynamic", 203 | state.ClientConfiguration.CA.ValueString(), 204 | state.ClientConfiguration.Cert.ValueString(), 205 | state.ClientConfiguration.Key.ValueString(), 206 | ) 207 | if err != nil { 208 | resp.Diagnostics.AddError("failed to generate talos config", err.Error()) 209 | 210 | return 211 | } 212 | 213 | c, err := client.New(ctx, client.WithConfig(talosConfig), client.WithEndpoints(endpoints...)) 214 | if err != nil { 215 | resp.Diagnostics.AddError("failed to create talos client", err.Error()) 216 | 217 | return 218 | } 219 | 220 | defer c.Close() //nolint:errcheck 221 | 222 | clientProvider := &cluster.ConfigClientProvider{ 223 | DefaultClient: c, 224 | } 225 | defer clientProvider.Close() //nolint:errcheck 226 | 227 | nodeInfos, err := newClusterNodes(controlPlaneNodes, workerNodes) 228 | if err != nil { 229 | resp.Diagnostics.AddError("failed to generate node infos", err.Error()) 230 | 231 | return 232 | } 233 | 234 | clusterState := struct { 235 | cluster.ClientProvider 236 | cluster.K8sProvider 237 | cluster.Info 238 | }{ 239 | ClientProvider: clientProvider, 240 | K8sProvider: &cluster.KubernetesClient{ 241 | ClientProvider: clientProvider, 242 | }, 243 | Info: nodeInfos, 244 | } 245 | 246 | // Run cluster readiness checks 247 | checkCtx, checkCtxCancel := context.WithTimeout(ctx, readTimeout) 248 | defer checkCtxCancel() 249 | 250 | reporter := newReporter() 251 | 252 | checks := slices.Concat(check.PreBootSequenceChecks(), check.K8sComponentsReadinessChecks()) 253 | 254 | if !state.SkipKubernetesChecks.ValueBool() { 255 | checks = check.DefaultClusterChecks() 256 | } 257 | 258 | if err := check.Wait(checkCtx, &clusterState, checks, reporter); err != nil { 259 | resp.Diagnostics.AddWarning("failed checks", reporter.String()) 260 | resp.Diagnostics.AddError("cluster health check failed", err.Error()) 261 | 262 | return 263 | } 264 | 265 | state.ID = basetypes.NewStringValue("cluster_health") 266 | 267 | resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) 268 | 269 | if resp.Diagnostics.HasError() { 270 | return 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /pkg/talos/talos_cluster_health_data_source_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/hashicorp/terraform-plugin-testing/helper/acctest" 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | func TestAccTalosClusterHealthDataSource(t *testing.T) { 15 | rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) 16 | 17 | resource.ParallelTest(t, resource.TestCase{ 18 | ExternalProviders: map[string]resource.ExternalProvider{ 19 | "libvirt": { 20 | Source: "dmacvicar/libvirt", 21 | }, 22 | }, 23 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 24 | Steps: []resource.TestStep{ 25 | { 26 | Config: testAccTalosClusterHealthDataSourceConfig("talos", rName), 27 | Check: resource.ComposeAggregateTestCheckFunc( 28 | resource.TestCheckResourceAttr("data.talos_cluster_health.this", "id", "cluster_health"), 29 | ), 30 | }, 31 | // make sure there are no changes 32 | { 33 | Config: testAccTalosClusterHealthDataSourceConfig("talos", rName), 34 | PlanOnly: true, 35 | }, 36 | }, 37 | }) 38 | } 39 | 40 | func testAccTalosClusterHealthDataSourceConfig(providerName, rName string) string { 41 | config := dynamicConfig{ 42 | Provider: providerName, 43 | ResourceName: rName, 44 | WithApplyConfig: true, 45 | WithBootstrap: true, 46 | WithRetrieveKubeConfig: true, 47 | WithClusterHealth: true, 48 | } 49 | 50 | return config.render() 51 | } 52 | -------------------------------------------------------------------------------- /pkg/talos/talos_cluster_kubeconfig_data_source.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos 6 | 7 | import ( 8 | "context" 9 | "time" 10 | 11 | "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" 12 | "github.com/hashicorp/terraform-plugin-framework/datasource" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 14 | "github.com/hashicorp/terraform-plugin-framework/types" 15 | "github.com/hashicorp/terraform-plugin-framework/types/basetypes" 16 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" 17 | "github.com/siderolabs/talos/pkg/machinery/client" 18 | "google.golang.org/grpc/codes" 19 | "google.golang.org/grpc/status" 20 | "k8s.io/client-go/tools/clientcmd" 21 | ) 22 | 23 | type talosClusterKubeConfigDataSource struct{} 24 | 25 | type talosClusterKubeConfigDataSourceModelV0 struct { //nolint:govet 26 | ID types.String `tfsdk:"id"` 27 | Node types.String `tfsdk:"node"` 28 | Endpoint types.String `tfsdk:"endpoint"` 29 | ClientConfiguration clientConfiguration `tfsdk:"client_configuration"` 30 | KubeConfigRaw types.String `tfsdk:"kubeconfig_raw"` 31 | KubernetesClientConfiguration kubernetesClientConfiguration `tfsdk:"kubernetes_client_configuration"` 32 | Wait types.Bool `tfsdk:"wait"` 33 | Timeouts timeouts.Value `tfsdk:"timeouts"` 34 | } 35 | 36 | var _ datasource.DataSource = &talosClusterKubeConfigDataSource{} 37 | 38 | // NewTalosClusterKubeConfigDataSource implements the datasource.DataSource interface. 39 | func NewTalosClusterKubeConfigDataSource() datasource.DataSource { 40 | return &talosClusterKubeConfigDataSource{} 41 | } 42 | 43 | func (d *talosClusterKubeConfigDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 44 | resp.TypeName = req.ProviderTypeName + "_cluster_kubeconfig" 45 | } 46 | 47 | func (d *talosClusterKubeConfigDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { 48 | resp.Schema = schema.Schema{ 49 | DeprecationMessage: "Use `talos_cluster_kubeconfig` resource instead. This data source will be removed in the next minor version of the provider.", 50 | Description: "Retrieves the kubeconfig for a Talos cluster", 51 | Attributes: map[string]schema.Attribute{ 52 | "id": schema.StringAttribute{ 53 | Computed: true, 54 | }, 55 | "node": schema.StringAttribute{ 56 | Required: true, 57 | Description: "controlplane node to retrieve the kubeconfig from", 58 | }, 59 | "endpoint": schema.StringAttribute{ 60 | Optional: true, 61 | Computed: true, 62 | Description: "endpoint to use for the talosclient. If not set, the node value will be used", 63 | }, 64 | "client_configuration": schema.SingleNestedAttribute{ 65 | Attributes: map[string]schema.Attribute{ 66 | "ca_certificate": schema.StringAttribute{ 67 | Required: true, 68 | Description: "The client CA certificate", 69 | }, 70 | "client_certificate": schema.StringAttribute{ 71 | Required: true, 72 | Description: "The client certificate", 73 | }, 74 | "client_key": schema.StringAttribute{ 75 | Required: true, 76 | Sensitive: true, 77 | Description: "The client key", 78 | }, 79 | }, 80 | Required: true, 81 | Description: "The client configuration data", 82 | }, 83 | "wait": schema.BoolAttribute{ 84 | Optional: true, 85 | Description: "Wait for the kubernetes api to be available", 86 | DeprecationMessage: "This attribute is deprecated and no-op. Will be removed in a future version. Use talos_cluster_health instead.", 87 | }, 88 | "kubeconfig_raw": schema.StringAttribute{ 89 | Computed: true, 90 | Description: "The raw kubeconfig", 91 | Sensitive: true, 92 | }, 93 | "kubernetes_client_configuration": schema.SingleNestedAttribute{ 94 | Attributes: map[string]schema.Attribute{ 95 | "host": schema.StringAttribute{ 96 | Computed: true, 97 | Description: "The kubernetes host", 98 | }, 99 | "ca_certificate": schema.StringAttribute{ 100 | Computed: true, 101 | Description: "The kubernetes CA certificate", 102 | }, 103 | "client_certificate": schema.StringAttribute{ 104 | Computed: true, 105 | Description: "The kubernetes client certificate", 106 | }, 107 | "client_key": schema.StringAttribute{ 108 | Computed: true, 109 | Sensitive: true, 110 | Description: "The kubernetes client key", 111 | }, 112 | }, 113 | Computed: true, 114 | Description: "The kubernetes client configuration", 115 | }, 116 | "timeouts": timeouts.Attributes(ctx, timeouts.Opts{ 117 | Read: true, 118 | }), 119 | }, 120 | } 121 | } 122 | 123 | // Read implements the datasource.DataSource interface. 124 | func (d *talosClusterKubeConfigDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 125 | var obj types.Object 126 | 127 | diags := req.Config.Get(ctx, &obj) 128 | resp.Diagnostics.Append(diags...) 129 | 130 | if resp.Diagnostics.HasError() { 131 | return 132 | } 133 | 134 | var state talosClusterKubeConfigDataSourceModelV0 135 | diags = obj.As(ctx, &state, basetypes.ObjectAsOptions{ 136 | UnhandledNullAsEmpty: true, 137 | UnhandledUnknownAsEmpty: true, 138 | }) 139 | resp.Diagnostics.Append(diags...) 140 | 141 | if resp.Diagnostics.HasError() { 142 | return 143 | } 144 | 145 | talosConfig, err := talosClientTFConfigToTalosClientConfig( 146 | "dynamic", 147 | state.ClientConfiguration.CA.ValueString(), 148 | state.ClientConfiguration.Cert.ValueString(), 149 | state.ClientConfiguration.Key.ValueString(), 150 | ) 151 | if err != nil { 152 | resp.Diagnostics.AddError("failed to generate talos config", err.Error()) 153 | 154 | return 155 | } 156 | 157 | if state.Endpoint.IsNull() { 158 | state.Endpoint = state.Node 159 | } 160 | 161 | readTimeout, diags := state.Timeouts.Read(ctx, 10*time.Minute) 162 | resp.Diagnostics.Append(diags...) 163 | 164 | if resp.Diagnostics.HasError() { 165 | return 166 | } 167 | 168 | ctxDeadline, cancel := context.WithTimeout(ctx, readTimeout) 169 | defer cancel() 170 | 171 | if retryErr := retry.RetryContext(ctxDeadline, readTimeout, func() *retry.RetryError { 172 | if clientOpErr := talosClientOp(ctx, state.Endpoint.ValueString(), state.Node.ValueString(), talosConfig, func(nodeCtx context.Context, c *client.Client) error { 173 | kubeConfigBytes, clientErr := c.Kubeconfig(nodeCtx) 174 | if clientErr != nil { 175 | return clientErr 176 | } 177 | 178 | state.KubeConfigRaw = basetypes.NewStringValue(string(kubeConfigBytes)) 179 | 180 | return nil 181 | }); clientOpErr != nil { 182 | if s := status.Code(clientOpErr); s == codes.InvalidArgument { 183 | return retry.NonRetryableError(clientOpErr) 184 | } 185 | 186 | return retry.RetryableError(clientOpErr) 187 | } 188 | 189 | return nil 190 | }); retryErr != nil { 191 | resp.Diagnostics.AddError("failed to retrieve kubeconfig", retryErr.Error()) 192 | 193 | return 194 | } 195 | 196 | kubeConfig, err := clientcmd.Load([]byte(state.KubeConfigRaw.ValueString())) 197 | if err != nil { 198 | resp.Diagnostics.AddError("failed to parse kubeconfig", err.Error()) 199 | 200 | return 201 | } 202 | 203 | clusterName := kubeConfig.Contexts[kubeConfig.CurrentContext].Cluster 204 | authName := kubeConfig.Contexts[kubeConfig.CurrentContext].AuthInfo 205 | 206 | state.KubernetesClientConfiguration = kubernetesClientConfiguration{ 207 | Host: basetypes.NewStringValue(kubeConfig.Clusters[clusterName].Server), 208 | CACertificate: basetypes.NewStringValue(bytesToBase64(kubeConfig.Clusters[clusterName].CertificateAuthorityData)), 209 | ClientCertificate: basetypes.NewStringValue(bytesToBase64(kubeConfig.AuthInfos[authName].ClientCertificateData)), 210 | ClientKey: basetypes.NewStringValue(bytesToBase64(kubeConfig.AuthInfos[authName].ClientKeyData)), 211 | } 212 | 213 | state.ID = basetypes.NewStringValue(clusterName) 214 | 215 | diags = resp.State.Set(ctx, &state) 216 | resp.Diagnostics.Append(diags...) 217 | 218 | if resp.Diagnostics.HasError() { 219 | return 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /pkg/talos/talos_cluster_kubeconfig_resource_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos_test 6 | 7 | import ( 8 | "testing" 9 | "time" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/acctest" 12 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 13 | 14 | "github.com/siderolabs/terraform-provider-talos/pkg/talos" 15 | ) 16 | 17 | func TestAccTalosClusterKubeconfigResource(t *testing.T) { 18 | testTime := time.Now() 19 | 20 | rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) 21 | 22 | resource.Test(t, resource.TestCase{ 23 | ExternalProviders: map[string]resource.ExternalProvider{ 24 | "libvirt": { 25 | Source: "dmacvicar/libvirt", 26 | }, 27 | }, 28 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 29 | Steps: []resource.TestStep{ 30 | { 31 | Config: testAccTalosClusterKubeconfigResourceConfig(rName), 32 | Check: resource.ComposeAggregateTestCheckFunc( 33 | resource.TestCheckResourceAttr("talos_cluster_kubeconfig.this", "id", "example-cluster"), 34 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "node"), 35 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "endpoint"), 36 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "client_configuration.ca_certificate"), 37 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "client_configuration.client_certificate"), 38 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "client_configuration.client_key"), 39 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "kubeconfig_raw"), 40 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "kubernetes_client_configuration.host"), 41 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "kubernetes_client_configuration.ca_certificate"), 42 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "kubernetes_client_configuration.client_certificate"), 43 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "kubernetes_client_configuration.client_key"), 44 | ), 45 | }, 46 | // test kubeconfig regeneration 47 | { 48 | PreConfig: func() { 49 | talos.OverridableTimeFunc = func() time.Time { 50 | return testTime.AddDate(0, 12, 5) 51 | } 52 | }, 53 | Config: testAccTalosClusterKubeconfigResourceConfig(rName), 54 | PlanOnly: true, 55 | ExpectNonEmptyPlan: true, 56 | }, 57 | }, 58 | }) 59 | 60 | talos.OverridableTimeFunc = func() time.Time { 61 | return testTime 62 | } 63 | 64 | resource.ParallelTest(t, resource.TestCase{ 65 | ExternalProviders: map[string]resource.ExternalProvider{ 66 | "libvirt": { 67 | Source: "dmacvicar/libvirt", 68 | }, 69 | }, 70 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 71 | Steps: []resource.TestStep{ 72 | { 73 | Config: testAccTalosClusterKubeconfigResourceConfig(rName), 74 | Check: resource.ComposeAggregateTestCheckFunc( 75 | resource.TestCheckResourceAttr("talos_cluster_kubeconfig.this", "id", "example-cluster"), 76 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "node"), 77 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "endpoint"), 78 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "client_configuration.ca_certificate"), 79 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "client_configuration.client_certificate"), 80 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "client_configuration.client_key"), 81 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "kubeconfig_raw"), 82 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "kubernetes_client_configuration.host"), 83 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "kubernetes_client_configuration.ca_certificate"), 84 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "kubernetes_client_configuration.client_certificate"), 85 | resource.TestCheckResourceAttrSet("talos_cluster_kubeconfig.this", "kubernetes_client_configuration.client_key"), 86 | ), 87 | }, 88 | // make sure there are no changes 89 | { 90 | Config: testAccTalosClusterKubeconfigResourceConfig(rName), 91 | PlanOnly: true, 92 | }, 93 | }, 94 | }) 95 | } 96 | 97 | func testAccTalosClusterKubeconfigResourceConfig(rName string) string { 98 | config := dynamicConfig{ 99 | Provider: "talos", 100 | ResourceName: rName, 101 | WithApplyConfig: true, 102 | WithBootstrap: true, 103 | WithRetrieveKubeConfig: true, 104 | } 105 | 106 | return config.render() 107 | } 108 | -------------------------------------------------------------------------------- /pkg/talos/talos_image_factory_extensions_versions_data_source.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "strings" 11 | 12 | "github.com/hashicorp/terraform-plugin-framework/attr" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource" 14 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 15 | "github.com/hashicorp/terraform-plugin-framework/path" 16 | "github.com/hashicorp/terraform-plugin-framework/types" 17 | "github.com/siderolabs/gen/xslices" 18 | "github.com/siderolabs/image-factory/pkg/client" 19 | ) 20 | 21 | type talosImageFactoryExtensionsVersionsDataSource struct { 22 | imageFactoryClient *client.Client 23 | } 24 | 25 | type talosImageFactoryExtensionsVersionsDataSourceModelV0 struct { 26 | ID types.String `tfsdk:"id"` 27 | TalosVersion types.String `tfsdk:"talos_version"` 28 | Filters *talosImageFactoryExtensionsVersionsFilter `tfsdk:"filters"` 29 | ExtensionsInfo []extensionInfo `tfsdk:"extensions_info"` 30 | } 31 | 32 | type talosImageFactoryExtensionsVersionsFilter struct { 33 | Names types.List `tfsdk:"names"` 34 | } 35 | 36 | type extensionInfo struct { 37 | Name types.String `tfsdk:"name"` 38 | Ref types.String `tfsdk:"ref"` 39 | Digest types.String `tfsdk:"digest"` 40 | Author types.String `tfsdk:"author"` 41 | Description types.String `tfsdk:"description"` 42 | } 43 | 44 | var _ datasource.DataSourceWithConfigure = &talosImageFactoryExtensionsVersionsDataSource{} 45 | 46 | // NewTalosImageFactoryExtensionsVersionsDataSource implements the datasource.DataSource interface. 47 | func NewTalosImageFactoryExtensionsVersionsDataSource() datasource.DataSource { 48 | return &talosImageFactoryExtensionsVersionsDataSource{} 49 | } 50 | 51 | func (d *talosImageFactoryExtensionsVersionsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 52 | resp.TypeName = req.ProviderTypeName + "_image_factory_extensions_versions" 53 | } 54 | 55 | func (d *talosImageFactoryExtensionsVersionsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { 56 | resp.Schema = schema.Schema{ 57 | Description: "The image factory extensions versions data source provides a list of available extensions for a specific talos version from the image factory.", 58 | Attributes: map[string]schema.Attribute{ 59 | "id": schema.StringAttribute{ 60 | Computed: true, 61 | }, 62 | "talos_version": schema.StringAttribute{ 63 | Required: true, 64 | Description: "The talos version to get extensions for.", 65 | }, 66 | "filters": schema.SingleNestedAttribute{ 67 | Optional: true, 68 | Description: "The filter to apply to the extensions list.", 69 | Attributes: map[string]schema.Attribute{ 70 | "names": schema.ListAttribute{ 71 | ElementType: types.StringType, 72 | Optional: true, 73 | Description: "The name of the extension to filter by.", 74 | }, 75 | }, 76 | }, 77 | "extensions_info": schema.ListAttribute{ 78 | ElementType: types.ObjectType{ 79 | AttrTypes: map[string]attr.Type{ 80 | "name": types.StringType, 81 | "ref": types.StringType, 82 | "digest": types.StringType, 83 | "author": types.StringType, 84 | "description": types.StringType, 85 | }, 86 | }, 87 | Computed: true, 88 | Description: "The list of available extensions for the specified talos version.", 89 | }, 90 | }, 91 | } 92 | } 93 | 94 | func (d *talosImageFactoryExtensionsVersionsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { 95 | if req.ProviderData == nil { 96 | return 97 | } 98 | 99 | imageFactoryClient, ok := req.ProviderData.(*client.Client) 100 | if !ok { 101 | resp.Diagnostics.AddError( 102 | "failed to get image factory client", 103 | fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), 104 | ) 105 | 106 | return 107 | } 108 | 109 | d.imageFactoryClient = imageFactoryClient 110 | } 111 | 112 | func (d *talosImageFactoryExtensionsVersionsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 113 | if d.imageFactoryClient == nil { 114 | resp.Diagnostics.AddError("image factory client is not configured", "Please report this issue to the provider developers.") 115 | 116 | return 117 | } 118 | 119 | var config talosImageFactoryExtensionsVersionsDataSourceModelV0 120 | 121 | resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) 122 | 123 | if resp.Diagnostics.HasError() { 124 | return 125 | } 126 | 127 | if config.TalosVersion.IsNull() || config.TalosVersion.IsUnknown() { 128 | return 129 | } 130 | 131 | extensionsInfo, err := d.imageFactoryClient.ExtensionsVersions(ctx, config.TalosVersion.ValueString()) 132 | if err != nil { 133 | resp.Diagnostics.AddError("failed to get talos extensions versions", err.Error()) 134 | 135 | return 136 | } 137 | 138 | if config.Filters != nil && !config.Filters.Names.IsNull() && !config.Filters.Names.IsUnknown() { 139 | var names []string 140 | 141 | resp.Diagnostics.Append(config.Filters.Names.ElementsAs(ctx, &names, true)...) 142 | 143 | if resp.Diagnostics.HasError() { 144 | return 145 | } 146 | 147 | extensionsInfo = xslices.Filter(extensionsInfo, func(e client.ExtensionInfo) bool { 148 | for _, n := range names { 149 | if strings.Contains(e.Name, n) { 150 | return true 151 | } 152 | } 153 | 154 | return false 155 | }) 156 | } 157 | 158 | tfExtensionsInfo := xslices.Map(extensionsInfo, func(e client.ExtensionInfo) extensionInfo { 159 | return extensionInfo{ 160 | Name: types.StringValue(e.Name), 161 | Ref: types.StringValue(e.Ref), 162 | Digest: types.StringValue(e.Digest), 163 | Author: types.StringValue(e.Author), 164 | Description: types.StringValue(e.Description), 165 | } 166 | }) 167 | 168 | resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), "extensions_info")...) 169 | 170 | if resp.Diagnostics.HasError() { 171 | return 172 | } 173 | 174 | resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("extensions_info"), &tfExtensionsInfo)...) 175 | 176 | if resp.Diagnostics.HasError() { 177 | return 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /pkg/talos/talos_image_factory_extensions_versions_data_source_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 11 | ) 12 | 13 | func TestAccTalosImageFactoryExtensionsVersionsDataSource(t *testing.T) { 14 | resource.ParallelTest(t, resource.TestCase{ 15 | IsUnitTest: true, // this is a local only resource, so can be unit tested 16 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 17 | Steps: []resource.TestStep{ 18 | { 19 | Config: testAccTalosImageFactoryExtensionsVersionsDataSourceConfig(), 20 | Check: resource.ComposeAggregateTestCheckFunc( 21 | resource.TestCheckResourceAttr("data.talos_image_factory_extensions_versions.this", "extensions_info.0.name", "siderolabs/amdgpu-firmware"), 22 | ), 23 | }, 24 | { 25 | Config: testAccTalosImageFactoryExtensionsVersionsDataSourceConfigWithFilters(), 26 | Check: resource.ComposeAggregateTestCheckFunc( 27 | resource.TestCheckResourceAttr("data.talos_image_factory_extensions_versions.this", "extensions_info.#", "5"), 28 | resource.TestCheckResourceAttr("data.talos_image_factory_extensions_versions.this", "extensions_info.0.name", "siderolabs/nvidia-container-toolkit"), 29 | ), 30 | }, 31 | }, 32 | }) 33 | } 34 | 35 | func testAccTalosImageFactoryExtensionsVersionsDataSourceConfig() string { 36 | return ` 37 | provider "talos" {} 38 | 39 | data "talos_image_factory_extensions_versions" "this" { 40 | talos_version = "v1.7.0" 41 | } 42 | ` 43 | } 44 | 45 | func testAccTalosImageFactoryExtensionsVersionsDataSourceConfigWithFilters() string { 46 | return ` 47 | provider "talos" {} 48 | 49 | data "talos_image_factory_extensions_versions" "this" { 50 | talos_version = "v1.7.0" 51 | filters = { 52 | names = [ 53 | "nvidia", 54 | "tailscale" 55 | ] 56 | } 57 | } 58 | ` 59 | } 60 | -------------------------------------------------------------------------------- /pkg/talos/talos_image_factory_overlays_versions_data_source.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "strings" 11 | 12 | "github.com/hashicorp/terraform-plugin-framework/attr" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource" 14 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 15 | "github.com/hashicorp/terraform-plugin-framework/path" 16 | "github.com/hashicorp/terraform-plugin-framework/types" 17 | "github.com/siderolabs/gen/xslices" 18 | "github.com/siderolabs/image-factory/pkg/client" 19 | ) 20 | 21 | type talosImageFactoryOverlaysVersionsDataSource struct { 22 | imageFactoryClient *client.Client 23 | } 24 | 25 | type talosImageFactoryOverlaysVersionsDataSourceModelV0 struct { 26 | ID types.String `tfsdk:"id"` 27 | TalosVersion types.String `tfsdk:"talos_version"` 28 | Filters *talosImageFactoryOverlaysVersionsFilter `tfsdk:"filters"` 29 | OverlaysInfo []overlayInfo `tfsdk:"overlays_info"` 30 | } 31 | 32 | type talosImageFactoryOverlaysVersionsFilter struct { 33 | Name types.String `tfsdk:"name"` 34 | } 35 | 36 | type overlayInfo struct { 37 | Name types.String `tfsdk:"name"` 38 | Image types.String `tfsdk:"image"` 39 | Ref types.String `tfsdk:"ref"` 40 | Digest types.String `tfsdk:"digest"` 41 | } 42 | 43 | var _ datasource.DataSourceWithConfigure = &talosImageFactoryOverlaysVersionsDataSource{} 44 | 45 | // NewTalosImageFactoryOverlaysVersionsDataSource implements the datasource.DataSource interface. 46 | func NewTalosImageFactoryOverlaysVersionsDataSource() datasource.DataSource { 47 | return &talosImageFactoryOverlaysVersionsDataSource{} 48 | } 49 | 50 | func (d *talosImageFactoryOverlaysVersionsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 51 | resp.TypeName = req.ProviderTypeName + "_image_factory_overlays_versions" 52 | } 53 | 54 | func (d *talosImageFactoryOverlaysVersionsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { 55 | resp.Schema = schema.Schema{ 56 | Description: "The image factory overlays versions data source provides a list of available overlays for a specific talos version from the image factory.", 57 | Attributes: map[string]schema.Attribute{ 58 | "id": schema.StringAttribute{ 59 | Computed: true, 60 | }, 61 | "talos_version": schema.StringAttribute{ 62 | Required: true, 63 | Description: "The talos version to get overlays for.", 64 | }, 65 | "filters": schema.SingleNestedAttribute{ 66 | Optional: true, 67 | Description: "The filter to apply to the overlays list.", 68 | Attributes: map[string]schema.Attribute{ 69 | "name": schema.StringAttribute{ 70 | Optional: true, 71 | Description: "The name of the overlay to filter by.", 72 | }, 73 | }, 74 | }, 75 | "overlays_info": schema.ListAttribute{ 76 | ElementType: types.ObjectType{ 77 | AttrTypes: map[string]attr.Type{ 78 | "name": types.StringType, 79 | "image": types.StringType, 80 | "ref": types.StringType, 81 | "digest": types.StringType, 82 | }, 83 | }, 84 | Computed: true, 85 | Description: "The list of available extensions for the specified talos version.", 86 | }, 87 | }, 88 | } 89 | } 90 | 91 | func (d *talosImageFactoryOverlaysVersionsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { 92 | if req.ProviderData == nil { 93 | return 94 | } 95 | 96 | imageFactoryClient, ok := req.ProviderData.(*client.Client) 97 | if !ok { 98 | resp.Diagnostics.AddError( 99 | "failed to get image factory client", 100 | fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), 101 | ) 102 | 103 | return 104 | } 105 | 106 | d.imageFactoryClient = imageFactoryClient 107 | } 108 | 109 | func (d *talosImageFactoryOverlaysVersionsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 110 | if d.imageFactoryClient == nil { 111 | resp.Diagnostics.AddError("image factory client is not configured", "Please report this issue to the provider developers.") 112 | 113 | return 114 | } 115 | 116 | var config talosImageFactoryOverlaysVersionsDataSourceModelV0 117 | 118 | resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) 119 | 120 | if resp.Diagnostics.HasError() { 121 | return 122 | } 123 | 124 | if config.TalosVersion.IsNull() || config.TalosVersion.IsUnknown() { 125 | return 126 | } 127 | 128 | overlaysInfo, err := d.imageFactoryClient.OverlaysVersions(ctx, config.TalosVersion.ValueString()) 129 | if err != nil { 130 | resp.Diagnostics.AddError("failed to get talos overlays versions", err.Error()) 131 | 132 | return 133 | } 134 | 135 | if config.Filters != nil && !config.Filters.Name.IsNull() && !config.Filters.Name.IsUnknown() { 136 | overlaysInfo = xslices.Filter(overlaysInfo, func(e client.OverlayInfo) bool { 137 | return strings.Contains(e.Name, config.Filters.Name.ValueString()) 138 | }) 139 | } 140 | 141 | tfOverlaysInfo := xslices.Map(overlaysInfo, func(e client.OverlayInfo) overlayInfo { 142 | return overlayInfo{ 143 | Name: types.StringValue(e.Name), 144 | Image: types.StringValue(e.Image), 145 | Ref: types.StringValue(e.Ref), 146 | Digest: types.StringValue(e.Digest), 147 | } 148 | }) 149 | 150 | resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), "overlays_info")...) 151 | 152 | if resp.Diagnostics.HasError() { 153 | return 154 | } 155 | 156 | resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("overlays_info"), &tfOverlaysInfo)...) 157 | 158 | if resp.Diagnostics.HasError() { 159 | return 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /pkg/talos/talos_image_factory_overlays_versions_data_source_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 11 | ) 12 | 13 | func TestAccTalosImageFactoryOverlaysVersionsDataSource(t *testing.T) { 14 | resource.ParallelTest(t, resource.TestCase{ 15 | IsUnitTest: true, // this is a local only resource, so can be unit tested 16 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 17 | Steps: []resource.TestStep{ 18 | { 19 | Config: testAccTalosImageFactoryOverlaysVersionsDataSourceConfig(), 20 | Check: resource.ComposeAggregateTestCheckFunc( 21 | resource.TestCheckResourceAttr("data.talos_image_factory_overlays_versions.this", "overlays_info.0.name", "rpi_generic"), 22 | ), 23 | }, 24 | { 25 | Config: testAccTalosImageFactoryOverlaysVersionsDataSourceConfigWithFilters(), 26 | Check: resource.ComposeAggregateTestCheckFunc( 27 | resource.TestCheckResourceAttr("data.talos_image_factory_overlays_versions.this", "overlays_info.#", "1"), 28 | resource.TestCheckResourceAttr("data.talos_image_factory_overlays_versions.this", "overlays_info.0.name", "rock4cplus"), 29 | ), 30 | }, 31 | }, 32 | }) 33 | } 34 | 35 | func testAccTalosImageFactoryOverlaysVersionsDataSourceConfig() string { 36 | return ` 37 | provider "talos" {} 38 | 39 | data "talos_image_factory_overlays_versions" "this" { 40 | talos_version = "v1.7.0" 41 | } 42 | ` 43 | } 44 | 45 | func testAccTalosImageFactoryOverlaysVersionsDataSourceConfigWithFilters() string { 46 | return ` 47 | provider "talos" {} 48 | 49 | data "talos_image_factory_overlays_versions" "this" { 50 | talos_version = "v1.7.0" 51 | filters = { 52 | name = "rock4cplus" 53 | } 54 | } 55 | ` 56 | } 57 | -------------------------------------------------------------------------------- /pkg/talos/talos_image_factory_schematic_resource.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | // Package talos is a Terraform provider for Talos. 6 | package talos 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/hashicorp/terraform-plugin-framework/resource" 12 | "github.com/hashicorp/terraform-plugin-framework/resource/schema" 13 | "github.com/hashicorp/terraform-plugin-framework/types" 14 | "github.com/hashicorp/terraform-plugin-framework/types/basetypes" 15 | "github.com/siderolabs/image-factory/pkg/client" 16 | "github.com/siderolabs/image-factory/pkg/schematic" 17 | "gopkg.in/yaml.v3" 18 | ) 19 | 20 | type talosImageFactorySchematicResource struct { 21 | imageFactoryClient *client.Client 22 | } 23 | 24 | var ( 25 | _ resource.Resource = &talosImageFactorySchematicResource{} 26 | _ resource.ResourceWithConfigure = &talosImageFactorySchematicResource{} 27 | ) 28 | 29 | var schematicAttributeMarkdownDescription = ` 30 | The schematic yaml respresentation to generate the image. 31 | 32 | If not set, a vanilla Talos image schematic will be generated. 33 | 34 | > Refer to [image-factory](https://github.com/siderolabs/image-factory?tab=readme-ov-file#post-schematics) for the schema. 35 | ` 36 | 37 | type talosImageFactorySchematicResourceModelV0 struct { 38 | ID types.String `tfsdk:"id"` 39 | Schematic types.String `tfsdk:"schematic"` 40 | } 41 | 42 | // NewTalosImageFactorySchematicResource implements the resource.Resource interface. 43 | func NewTalosImageFactorySchematicResource() resource.Resource { 44 | return &talosImageFactorySchematicResource{} 45 | } 46 | 47 | func (r *talosImageFactorySchematicResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { 48 | resp.TypeName = req.ProviderTypeName + "_image_factory_schematic" 49 | } 50 | 51 | func (r *talosImageFactorySchematicResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { 52 | resp.Schema = schema.Schema{ 53 | Description: "The image factory schematic resource allows you to create a schematic for a Talos image.", 54 | Attributes: map[string]schema.Attribute{ 55 | "id": schema.StringAttribute{ 56 | Computed: true, 57 | Description: "The unique ID of the schematic, returned from Image Factory.", 58 | }, 59 | "schematic": schema.StringAttribute{ 60 | Optional: true, 61 | MarkdownDescription: schematicAttributeMarkdownDescription, 62 | }, 63 | }, 64 | } 65 | } 66 | 67 | func (r *talosImageFactorySchematicResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { 68 | if req.ProviderData == nil { 69 | return 70 | } 71 | 72 | imageFactoryClient, ok := req.ProviderData.(*client.Client) 73 | if !ok { 74 | resp.Diagnostics.AddError( 75 | "failed to get image factory client", 76 | "Expected *client.Client, got: %T. Please report this issue to the provider developers.", 77 | ) 78 | 79 | return 80 | } 81 | 82 | r.imageFactoryClient = imageFactoryClient 83 | } 84 | 85 | func (r *talosImageFactorySchematicResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { 86 | var config talosImageFactorySchematicResourceModelV0 87 | 88 | resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) 89 | 90 | if resp.Diagnostics.HasError() { 91 | return 92 | } 93 | 94 | var schematic schematic.Schematic 95 | 96 | if err := yaml.Unmarshal([]byte(config.Schematic.ValueString()), &schematic); err != nil { 97 | resp.Diagnostics.AddError("failed to unmarshal schematic", err.Error()) 98 | 99 | return 100 | } 101 | 102 | schematicID, err := r.imageFactoryClient.SchematicCreate(ctx, schematic) 103 | if err != nil { 104 | resp.Diagnostics.AddError("failed to create schematic", err.Error()) 105 | 106 | return 107 | } 108 | 109 | config.ID = basetypes.NewStringValue(schematicID) 110 | 111 | resp.Diagnostics.Append(resp.State.Set(ctx, &config)...) 112 | 113 | if resp.Diagnostics.HasError() { 114 | return 115 | } 116 | } 117 | 118 | func (r *talosImageFactorySchematicResource) Delete(_ context.Context, _ resource.DeleteRequest, _ *resource.DeleteResponse) { 119 | } 120 | 121 | func (r *talosImageFactorySchematicResource) Read(_ context.Context, _ resource.ReadRequest, _ *resource.ReadResponse) { 122 | } 123 | 124 | func (r *talosImageFactorySchematicResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { 125 | var plan talosImageFactorySchematicResourceModelV0 126 | 127 | diags := req.Plan.Get(ctx, &plan) 128 | resp.Diagnostics.Append(diags...) 129 | 130 | if resp.Diagnostics.HasError() { 131 | return 132 | } 133 | 134 | var schematic schematic.Schematic 135 | 136 | if err := yaml.Unmarshal([]byte(plan.Schematic.ValueString()), &schematic); err != nil { 137 | resp.Diagnostics.AddError("failed to unmarshal schematic", err.Error()) 138 | 139 | return 140 | } 141 | 142 | schematicID, err := r.imageFactoryClient.SchematicCreate(ctx, schematic) 143 | if err != nil { 144 | resp.Diagnostics.AddError("failed to update schematic", err.Error()) 145 | 146 | return 147 | } 148 | 149 | plan.ID = basetypes.NewStringValue(schematicID) 150 | 151 | // Set state to fully populated data 152 | resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) 153 | 154 | if resp.Diagnostics.HasError() { 155 | return 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /pkg/talos/talos_image_factory_schematic_resource_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 11 | ) 12 | 13 | func TestAccTalosImageFactorySchematicResource(t *testing.T) { 14 | resource.ParallelTest(t, resource.TestCase{ 15 | IsUnitTest: true, // this is a local only resource, so can be unit tested 16 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 17 | Steps: []resource.TestStep{ 18 | // vanilla image 19 | { 20 | Config: testAccTalosTalosImageFactorySchematicConfig(), 21 | Check: resource.ComposeAggregateTestCheckFunc( 22 | resource.TestCheckResourceAttr("talos_image_factory_schematic.this", "id", "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"), 23 | ), 24 | }, 25 | // empty schematic 26 | { 27 | Config: testAccTalosTalosImageFactorySchematicEmptySchematicConfig(), 28 | Check: resource.ComposeAggregateTestCheckFunc( 29 | resource.TestCheckResourceAttr("talos_image_factory_schematic.this", "id", "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"), 30 | ), 31 | }, 32 | // empty customization 33 | { 34 | Config: testAccTalosTalosImageFactorySchematicEmptyCustomizationConfig(), 35 | Check: resource.ComposeAggregateTestCheckFunc( 36 | resource.TestCheckResourceAttr("talos_image_factory_schematic.this", "id", "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"), 37 | ), 38 | }, 39 | // vanilla image 40 | { 41 | Config: testAccTalosTalosImageFactorySchematicConfig(), 42 | Check: resource.ComposeAggregateTestCheckFunc( 43 | resource.TestCheckResourceAttr("talos_image_factory_schematic.this", "id", "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"), 44 | ), 45 | }, 46 | // known extension 47 | { 48 | Config: testAccTalosTalosImageFactorySchematicKnownExtensionConfig(), 49 | Check: resource.ComposeAggregateTestCheckFunc( 50 | resource.TestCheckResourceAttr("talos_image_factory_schematic.this", "id", "d01dbf04a51b44a41d62b7c9692da0a74889277651600da6b602582654e4b402"), 51 | ), 52 | }, 53 | }, 54 | }) 55 | } 56 | 57 | func testAccTalosTalosImageFactorySchematicConfig() string { 58 | return ` 59 | provider "talos" {} 60 | 61 | resource "talos_image_factory_schematic" "this" {} 62 | ` 63 | } 64 | 65 | func testAccTalosTalosImageFactorySchematicEmptySchematicConfig() string { 66 | return ` 67 | provider "talos" {} 68 | 69 | resource "talos_image_factory_schematic" "this" { 70 | schematic = yamlencode({}) 71 | } 72 | ` 73 | } 74 | 75 | func testAccTalosTalosImageFactorySchematicEmptyCustomizationConfig() string { 76 | return ` 77 | provider "talos" {} 78 | 79 | resource "talos_image_factory_schematic" "this" { 80 | schematic = yamlencode( 81 | { 82 | customization = {} 83 | } 84 | ) 85 | } 86 | ` 87 | } 88 | 89 | func testAccTalosTalosImageFactorySchematicKnownExtensionConfig() string { 90 | return ` 91 | provider "talos" {} 92 | 93 | resource "talos_image_factory_schematic" "this" { 94 | schematic = yamlencode( 95 | { 96 | customization = { 97 | systemExtensions = { 98 | officialExtensions = ["siderolabs/amdgpu-firmware"] 99 | } 100 | } 101 | } 102 | ) 103 | } 104 | ` 105 | } 106 | -------------------------------------------------------------------------------- /pkg/talos/talos_image_factory_versions_data_source.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "strings" 11 | 12 | "github.com/blang/semver/v4" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource" 14 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 15 | "github.com/hashicorp/terraform-plugin-framework/types" 16 | "github.com/hashicorp/terraform-plugin-framework/types/basetypes" 17 | "github.com/siderolabs/image-factory/pkg/client" 18 | ) 19 | 20 | type talosImageFactoryVersionsDataSource struct { 21 | imageFactoryClient *client.Client 22 | } 23 | 24 | type talosImageFactoryVersionsDataSourceModelV0 struct { 25 | ID types.String `tfsdk:"id"` 26 | Filters *talosImageFactoryVersionsFilter `tfsdk:"filters"` 27 | TalosVersions []string `tfsdk:"talos_versions"` 28 | } 29 | 30 | type talosImageFactoryVersionsFilter struct { 31 | StableVersionOnly types.Bool `tfsdk:"stable_versions_only"` 32 | } 33 | 34 | var _ datasource.DataSourceWithConfigure = &talosImageFactoryVersionsDataSource{} 35 | 36 | // NewTalosImageFactoryVersionsDataSource implements the datasource.DataSource interface. 37 | func NewTalosImageFactoryVersionsDataSource() datasource.DataSource { 38 | return &talosImageFactoryVersionsDataSource{} 39 | } 40 | 41 | func (d *talosImageFactoryVersionsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 42 | resp.TypeName = req.ProviderTypeName + "_image_factory_versions" 43 | } 44 | 45 | func (d *talosImageFactoryVersionsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { 46 | resp.Schema = schema.Schema{ 47 | Description: "The image factory versions data source provides a list of available talos versions from the image factory.", 48 | Attributes: map[string]schema.Attribute{ 49 | "id": schema.StringAttribute{ 50 | Computed: true, 51 | }, 52 | "talos_versions": schema.ListAttribute{ 53 | ElementType: types.StringType, 54 | Computed: true, 55 | Description: "The list of available talos versions.", 56 | }, 57 | "filters": schema.SingleNestedAttribute{ 58 | Optional: true, 59 | Description: "The filter to apply to the overlays list.", 60 | Attributes: map[string]schema.Attribute{ 61 | "stable_versions_only": schema.BoolAttribute{ 62 | Optional: true, 63 | Description: "If set to true, only stable versions will be returned. If set to false, all versions will be returned.", 64 | }, 65 | }, 66 | }, 67 | }, 68 | } 69 | } 70 | 71 | func (d *talosImageFactoryVersionsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { 72 | if req.ProviderData == nil { 73 | return 74 | } 75 | 76 | imageFactoryClient, ok := req.ProviderData.(*client.Client) 77 | if !ok { 78 | resp.Diagnostics.AddError( 79 | "failed to get image factory client", 80 | fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), 81 | ) 82 | 83 | return 84 | } 85 | 86 | d.imageFactoryClient = imageFactoryClient 87 | } 88 | 89 | func (d *talosImageFactoryVersionsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { 90 | if d.imageFactoryClient == nil { 91 | resp.Diagnostics.AddError("image factory client is not configured", "Please report this issue to the provider developers.") 92 | 93 | return 94 | } 95 | 96 | versions, err := d.imageFactoryClient.Versions(ctx) 97 | if err != nil { 98 | resp.Diagnostics.AddError("failed to get talos versions", err.Error()) 99 | 100 | return 101 | } 102 | 103 | var config talosImageFactoryVersionsDataSourceModelV0 104 | 105 | resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) 106 | 107 | if resp.Diagnostics.HasError() { 108 | return 109 | } 110 | 111 | if config.Filters != nil && config.Filters.StableVersionOnly.ValueBool() { 112 | var filteredVersions []string 113 | 114 | for _, version := range versions { 115 | semVer, err := semver.Parse(strings.TrimPrefix(version, "v")) 116 | if err != nil { 117 | resp.Diagnostics.AddError("failed to parse talos version", err.Error()) 118 | 119 | return 120 | } 121 | 122 | if len(semVer.Pre) > 0 { 123 | continue 124 | } 125 | 126 | filteredVersions = append(filteredVersions, version) 127 | } 128 | 129 | if resp.Diagnostics.HasError() { 130 | return 131 | } 132 | 133 | versions = filteredVersions 134 | } 135 | 136 | state := talosImageFactoryVersionsDataSourceModelV0{ 137 | ID: basetypes.NewStringValue("talos_versions"), 138 | TalosVersions: versions, 139 | } 140 | 141 | resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) 142 | 143 | if resp.Diagnostics.HasError() { 144 | return 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /pkg/talos/talos_image_factory_versions_data_source_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 11 | "github.com/hashicorp/terraform-plugin-testing/knownvalue" 12 | "github.com/hashicorp/terraform-plugin-testing/statecheck" 13 | ) 14 | 15 | func TestAccTalosImageFactoryVersionsDataSource(t *testing.T) { 16 | resource.ParallelTest(t, resource.TestCase{ 17 | IsUnitTest: true, // this is a local only resource, so can be unit tested 18 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 19 | Steps: []resource.TestStep{ 20 | { 21 | Config: testAccTalosImageFactoryVersionsDataSourceConfig(), 22 | Check: resource.ComposeAggregateTestCheckFunc( 23 | resource.TestCheckResourceAttr("data.talos_image_factory_versions.this", "talos_versions.0", "v1.2.0"), 24 | ), 25 | }, 26 | { 27 | Config: testAccTalosImageFactoryVersionsDataSourceWithFilterConfig(), 28 | ConfigStateChecks: []statecheck.StateCheck{ 29 | statecheck.ExpectKnownOutputValue("talos_version", knownvalue.StringExact("v1.10.2")), 30 | }, 31 | }, 32 | }, 33 | }) 34 | } 35 | 36 | func testAccTalosImageFactoryVersionsDataSourceConfig() string { 37 | return ` 38 | provider "talos" {} 39 | 40 | data "talos_image_factory_versions" "this" {} 41 | ` 42 | } 43 | 44 | func testAccTalosImageFactoryVersionsDataSourceWithFilterConfig() string { 45 | return ` 46 | provider "talos" {} 47 | 48 | data "talos_image_factory_versions" "this" { 49 | filters = { 50 | stable_versions_only = true 51 | } 52 | } 53 | 54 | output "talos_version" { 55 | value = data.talos_image_factory_versions.this.talos_versions[length(data.talos_image_factory_versions.this.talos_versions) - 1] 56 | } 57 | ` 58 | } 59 | -------------------------------------------------------------------------------- /pkg/talos/talos_machine_bootstrap_resource_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos_test 6 | 7 | import ( 8 | "fmt" 9 | "testing" 10 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/acctest" 12 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 13 | ) 14 | 15 | func TestAccTalosMachineBootstrapResource(t *testing.T) { 16 | resource.ParallelTest(t, resource.TestCase{ 17 | IsUnitTest: true, // import can be unit tested 18 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 19 | Steps: []resource.TestStep{ 20 | { 21 | // import the resource 22 | Config: testAccTalosMachineBootstrapResourceConfigImport("10.5.0.2"), 23 | ResourceName: "talos_machine_bootstrap.this", 24 | ImportStateId: "this", 25 | ImportState: true, 26 | ImportStatePersist: true, 27 | }, 28 | // verify state is correct after import 29 | { 30 | Config: testAccTalosMachineBootstrapResourceConfigImport("10.5.0.2"), 31 | Check: resource.ComposeAggregateTestCheckFunc( 32 | resource.TestCheckResourceAttr("talos_machine_bootstrap.this", "id", "machine_bootstrap"), 33 | resource.TestCheckResourceAttr("talos_machine_bootstrap.this", "node", "10.5.0.2"), 34 | resource.TestCheckResourceAttr("talos_machine_bootstrap.this", "endpoint", "10.5.0.2"), 35 | resource.TestCheckResourceAttrSet("talos_machine_bootstrap.this", "client_configuration.ca_certificate"), 36 | resource.TestCheckResourceAttrSet("talos_machine_bootstrap.this", "client_configuration.client_certificate"), 37 | resource.TestCheckResourceAttrSet("talos_machine_bootstrap.this", "client_configuration.client_key"), 38 | ), 39 | }, 40 | }, 41 | }) 42 | } 43 | 44 | func TestAccTalosMachineBootstrapResourceUpgrade(t *testing.T) { 45 | // ref: https://github.com/hashicorp/terraform-plugin-testing/pull/118 46 | t.Skip("skipping until TF test framework has a way to remove state resource") 47 | 48 | rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) 49 | 50 | resource.ParallelTest(t, resource.TestCase{ 51 | Steps: []resource.TestStep{ 52 | // create TF config with v0.1.2 of the talos provider 53 | { 54 | ExternalProviders: map[string]resource.ExternalProvider{ 55 | "talos": { 56 | VersionConstraint: "=0.1.2", 57 | Source: "siderolabs/talos", 58 | }, 59 | "libvirt": { 60 | Source: "dmacvicar/libvirt", 61 | }, 62 | }, 63 | Config: testAccTalosMachineBootstrapResourceConfigV0("talosv1", rName), 64 | Check: resource.ComposeAggregateTestCheckFunc( 65 | resource.TestCheckNoResourceAttr("talos_client_configuration", "this"), 66 | resource.TestCheckNoResourceAttr("talos_machine_configuration_controlplane", "this"), 67 | resource.TestCheckResourceAttr("talos_machine_configuration_apply", "id", "this"), 68 | ), 69 | }, 70 | // now test state migration with the latest version of the provider 71 | { 72 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 73 | ExternalProviders: map[string]resource.ExternalProvider{ 74 | "libvirt": { 75 | Source: "dmacvicar/libvirt", 76 | }, 77 | }, 78 | Config: testAccTalosMachineBootstrapResourceConfigV1("talos", rName), 79 | Check: resource.ComposeAggregateTestCheckFunc( 80 | resource.TestCheckResourceAttr("talos_machine_bootstrap.this", "id", "machine_bootstrap"), 81 | resource.TestCheckResourceAttrSet("talos_machine_bootstrap.this", "node"), 82 | resource.TestCheckResourceAttrSet("talos_machine_bootstrap.this", "endpoint"), 83 | resource.TestCheckResourceAttrSet("talos_machine_bootstrap.this", "client_configuration.ca_certificate"), 84 | resource.TestCheckResourceAttrSet("talos_machine_bootstrap.this", "client_configuration.client_certificate"), 85 | resource.TestCheckResourceAttrSet("talos_machine_bootstrap.this", "client_configuration.client_key"), 86 | ), 87 | }, 88 | // ensure there is no diff 89 | { 90 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 91 | ExternalProviders: map[string]resource.ExternalProvider{ 92 | "libvirt": { 93 | Source: "dmacvicar/libvirt", 94 | }, 95 | }, 96 | Config: testAccTalosMachineBootstrapResourceConfigV1("talos", rName), 97 | PlanOnly: true, 98 | }, 99 | }, 100 | }) 101 | } 102 | 103 | func testAccTalosMachineBootstrapResourceConfigV0(providerName, rName string) string { 104 | config := dynamicConfig{ 105 | Provider: providerName, 106 | ResourceName: rName, 107 | WithApplyConfig: true, 108 | WithBootstrap: true, 109 | } 110 | 111 | return config.render() 112 | } 113 | 114 | func testAccTalosMachineBootstrapResourceConfigV1(providerName, rName string) string { 115 | config := dynamicConfig{ 116 | Provider: providerName, 117 | ResourceName: rName, 118 | WithApplyConfig: true, 119 | WithBootstrap: true, 120 | } 121 | 122 | return config.render() 123 | } 124 | 125 | func testAccTalosMachineBootstrapResourceConfigImport(node string) string { 126 | return fmt.Sprintf(` 127 | resource "talos_machine_secrets" "this" {} 128 | 129 | resource "talos_machine_bootstrap" "this" { 130 | node = "%s" 131 | client_configuration = talos_machine_secrets.this.client_configuration 132 | } 133 | `, node) 134 | } 135 | -------------------------------------------------------------------------------- /pkg/talos/talos_machine_configuration_apply_resource_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/hashicorp/terraform-plugin-testing/helper/acctest" 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | func TestAccTalosMachineConfigurationApplyResource(t *testing.T) { 15 | rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) 16 | 17 | resource.ParallelTest(t, resource.TestCase{ 18 | ExternalProviders: map[string]resource.ExternalProvider{ 19 | "libvirt": { 20 | Source: "dmacvicar/libvirt", 21 | }, 22 | }, 23 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 24 | Steps: []resource.TestStep{ 25 | { 26 | Config: testAccTalosMachineConfigurationApplyResourceConfig("talos", rName), 27 | Check: resource.ComposeAggregateTestCheckFunc( 28 | resource.TestCheckResourceAttr("talos_machine_configuration_apply.this", "id", "machine_configuration_apply"), 29 | resource.TestCheckResourceAttr("talos_machine_configuration_apply.this", "apply_mode", "auto"), 30 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "node"), 31 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "endpoint"), 32 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "client_configuration.ca_certificate"), 33 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "client_configuration.client_certificate"), 34 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "client_configuration.client_key"), 35 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "machine_configuration_input"), 36 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "machine_configuration"), 37 | resource.TestCheckResourceAttr("talos_machine_configuration_apply.this", "config_patches.#", "1"), 38 | resource.TestCheckResourceAttr("talos_machine_configuration_apply.this", "config_patches.0", "\"machine\":\n \"install\":\n \"disk\": \"/dev/vda\"\n"), 39 | ), 40 | }, 41 | // ensure there is no diff 42 | { 43 | Config: testAccTalosMachineConfigurationApplyResourceConfig("talos", rName), 44 | PlanOnly: true, 45 | }, 46 | }, 47 | }) 48 | } 49 | 50 | func TestAccTalosMachineConfigurationApplyResourceUpgrade(t *testing.T) { 51 | // ref: https://github.com/hashicorp/terraform-plugin-testing/pull/118 52 | t.Skip("skipping until TF test framework has a way to remove state resource") 53 | 54 | rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) 55 | 56 | resource.ParallelTest(t, resource.TestCase{ 57 | Steps: []resource.TestStep{ 58 | // create TF config with v0.1.2 of the talos provider 59 | { 60 | ExternalProviders: map[string]resource.ExternalProvider{ 61 | "talos": { 62 | VersionConstraint: "=0.1.2", 63 | Source: "siderolabs/talos", 64 | }, 65 | "libvirt": { 66 | Source: "dmacvicar/libvirt", 67 | }, 68 | }, 69 | Config: testAccTalosMachineConfigurationApplyResourceConfigV0("talosv1", rName), 70 | Check: resource.ComposeAggregateTestCheckFunc( 71 | resource.TestCheckNoResourceAttr("talos_client_configuration", "this"), 72 | resource.TestCheckNoResourceAttr("talos_machine_configuration_controlplane", "this"), 73 | ), 74 | }, 75 | // now test state migration with the latest version of the provider 76 | { 77 | ExternalProviders: map[string]resource.ExternalProvider{ 78 | "libvirt": { 79 | Source: "dmacvicar/libvirt", 80 | }, 81 | }, 82 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 83 | Config: testAccTalosMachineConfigurationApplyResourceConfigV1("talos", rName), 84 | Check: resource.ComposeAggregateTestCheckFunc( 85 | resource.TestCheckResourceAttr("talos_machine_configuration_apply.this", "id", "machine_configuration_apply"), 86 | resource.TestCheckResourceAttr("talos_machine_configuration_apply.this", "apply_mode", "auto"), 87 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "node"), 88 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "endpoint"), 89 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "client_configuration.ca_certificate"), 90 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "client_configuration.client_certificate"), 91 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "client_configuration.client_key"), 92 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "machine_configuration_input"), 93 | resource.TestCheckResourceAttrSet("talos_machine_configuration_apply.this", "machine_configuration"), 94 | resource.TestCheckResourceAttr("talos_machine_configuration_apply.this", "config_patches.#", "1"), 95 | resource.TestCheckResourceAttr("talos_machine_configuration_apply.this", "config_patches.0", "\"machine\":\n \"install\":\n \"disk\": \"/dev/vda\"\n"), 96 | ), 97 | }, 98 | // ensure there is no diff 99 | { 100 | ExternalProviders: map[string]resource.ExternalProvider{ 101 | "libvirt": { 102 | Source: "dmacvicar/libvirt", 103 | }, 104 | }, 105 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 106 | Config: testAccTalosMachineConfigurationApplyResourceConfigV1("talos", rName), 107 | PlanOnly: true, 108 | }, 109 | }, 110 | }) 111 | } 112 | 113 | func testAccTalosMachineConfigurationApplyResourceConfig(providerName, rName string) string { 114 | config := dynamicConfig{ 115 | Provider: providerName, 116 | ResourceName: rName, 117 | WithApplyConfig: true, 118 | WithBootstrap: false, 119 | } 120 | 121 | return config.render() 122 | } 123 | 124 | func testAccTalosMachineConfigurationApplyResourceConfigV0(providerName, rName string) string { 125 | config := dynamicConfig{ 126 | Provider: providerName, 127 | ResourceName: rName, 128 | WithApplyConfig: true, 129 | WithBootstrap: false, 130 | } 131 | 132 | return config.render() 133 | } 134 | 135 | func testAccTalosMachineConfigurationApplyResourceConfigV1(providerName, rName string) string { 136 | config := dynamicConfig{ 137 | Provider: providerName, 138 | ResourceName: rName, 139 | WithApplyConfig: true, 140 | WithBootstrap: false, 141 | } 142 | 143 | return config.render() 144 | } 145 | -------------------------------------------------------------------------------- /pkg/talos/talos_machine_disks_data_source.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos 6 | 7 | import ( 8 | "context" 9 | "errors" 10 | "time" 11 | 12 | "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" 13 | "github.com/hashicorp/terraform-plugin-framework/datasource" 14 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 15 | "github.com/hashicorp/terraform-plugin-framework/types" 16 | "github.com/hashicorp/terraform-plugin-framework/types/basetypes" 17 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" 18 | "github.com/siderolabs/talos/pkg/machinery/cel" 19 | "github.com/siderolabs/talos/pkg/machinery/cel/celenv" 20 | "github.com/siderolabs/talos/pkg/machinery/client" 21 | "github.com/siderolabs/talos/pkg/machinery/config/types/block/blockhelpers" 22 | "google.golang.org/grpc/codes" 23 | "google.golang.org/grpc/status" 24 | ) 25 | 26 | //go:generate go run internal/gen/diskspec.go block.DiskSpec talos_machine_disks_data_source 27 | 28 | func (e nodiskFoundError) Error() string { 29 | return "no disk matching the filter found" 30 | } 31 | 32 | type nodiskFoundError struct{} 33 | 34 | type talosMachineDisksDataSource struct{} 35 | 36 | type talosMachineDisksDataSourceModelV1 struct { //nolint:govet 37 | ID types.String `tfsdk:"id"` 38 | Node types.String `tfsdk:"node"` 39 | Endpoint types.String `tfsdk:"endpoint"` 40 | Selector types.String `tfsdk:"selector"` 41 | ClientConfiguration clientConfiguration `tfsdk:"client_configuration"` 42 | Disks []diskspec `tfsdk:"disks"` 43 | Timeouts timeouts.Value `tfsdk:"timeouts"` 44 | } 45 | 46 | var _ datasource.DataSource = &talosMachineDisksDataSource{} 47 | 48 | // NewTalosMachineDisksDataSource implements the datasource.DataSource interface. 49 | func NewTalosMachineDisksDataSource() datasource.DataSource { 50 | return &talosMachineDisksDataSource{} 51 | } 52 | 53 | func (d *talosMachineDisksDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { 54 | resp.TypeName = req.ProviderTypeName + "_machine_disks" 55 | } 56 | 57 | func (d *talosMachineDisksDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { 58 | resp.Schema = schema.Schema{ 59 | Description: "Generate a machine configuration for a node type", 60 | Attributes: map[string]schema.Attribute{ 61 | "id": schema.StringAttribute{ 62 | Description: "The generated ID of this resource", 63 | Computed: true, 64 | }, 65 | "node": schema.StringAttribute{ 66 | Required: true, 67 | Description: "controlplane node to retrieve the kubeconfig from", 68 | }, 69 | "endpoint": schema.StringAttribute{ 70 | Optional: true, 71 | Computed: true, 72 | Description: "endpoint to use for the talosclient. If not set, the node value will be used", 73 | }, 74 | "client_configuration": schema.SingleNestedAttribute{ 75 | Attributes: map[string]schema.Attribute{ 76 | "ca_certificate": schema.StringAttribute{ 77 | Required: true, 78 | Description: "The client CA certificate", 79 | }, 80 | "client_certificate": schema.StringAttribute{ 81 | Required: true, 82 | Description: "The client certificate", 83 | }, 84 | "client_key": schema.StringAttribute{ 85 | Required: true, 86 | Sensitive: true, 87 | Description: "The client key", 88 | }, 89 | }, 90 | Required: true, 91 | Description: "The client configuration data", 92 | }, 93 | "selector": schema.StringAttribute{ 94 | Optional: true, 95 | MarkdownDescription: `The CEL expression to filter the disks. 96 | If not set, all disks will be returned. 97 | See [CEL documentation](https://www.talos.dev/latest/talos-guides/configuration/disk-management/#disk-selector).`, 98 | }, 99 | "disks": schema.ListNestedAttribute{ 100 | Description: "The disks that match the filters", 101 | NestedObject: schema.NestedAttributeObject{ 102 | Attributes: diskspecAttributes, 103 | }, 104 | Computed: true, 105 | }, 106 | "timeouts": timeouts.Attributes(ctx, timeouts.Opts{ 107 | Read: true, 108 | }), 109 | }, 110 | } 111 | } 112 | 113 | func (d *talosMachineDisksDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { //nolint:gocognit,gocyclo,cyclop 114 | var obj types.Object 115 | 116 | diags := req.Config.Get(ctx, &obj) 117 | resp.Diagnostics.Append(diags...) 118 | 119 | if resp.Diagnostics.HasError() { 120 | return 121 | } 122 | 123 | var state talosMachineDisksDataSourceModelV1 124 | diags = obj.As(ctx, &state, basetypes.ObjectAsOptions{ 125 | UnhandledNullAsEmpty: true, 126 | UnhandledUnknownAsEmpty: true, 127 | }) 128 | resp.Diagnostics.Append(diags...) 129 | 130 | if resp.Diagnostics.HasError() { 131 | return 132 | } 133 | 134 | talosConfig, err := talosClientTFConfigToTalosClientConfig( 135 | "dynamic", 136 | state.ClientConfiguration.CA.ValueString(), 137 | state.ClientConfiguration.Cert.ValueString(), 138 | state.ClientConfiguration.Key.ValueString(), 139 | ) 140 | if err != nil { 141 | resp.Diagnostics.AddError("failed to generate talos config", err.Error()) 142 | 143 | return 144 | } 145 | 146 | if state.Endpoint.IsNull() { 147 | state.Endpoint = state.Node 148 | } 149 | 150 | readTimeout, diags := state.Timeouts.Read(ctx, 10*time.Minute) 151 | resp.Diagnostics.Append(diags...) 152 | 153 | if resp.Diagnostics.HasError() { 154 | return 155 | } 156 | 157 | ctxDeadline, cancel := context.WithTimeout(ctx, readTimeout) 158 | defer cancel() 159 | 160 | selector := state.Selector.ValueString() 161 | 162 | if selector == "" { 163 | // if there is no selector, we can return all disks 164 | selector = "true" 165 | } 166 | 167 | exp, err := cel.ParseBooleanExpression(selector, celenv.DiskLocator()) 168 | if err != nil { 169 | resp.Diagnostics.AddError("failed to parse celenv selector", err.Error()) 170 | 171 | return 172 | } 173 | 174 | if err := retry.RetryContext(ctxDeadline, readTimeout, func() *retry.RetryError { 175 | if err := talosClientOp(ctx, state.Endpoint.ValueString(), state.Node.ValueString(), talosConfig, func(nodeCtx context.Context, c *client.Client) error { 176 | disks, err := blockhelpers.MatchDisks(nodeCtx, c.COSI, &exp) 177 | if err != nil { 178 | return err 179 | } 180 | 181 | for _, disk := range disks { 182 | state.Disks = append(state.Disks, diskspecToTFTypes(*disk.TypedSpec())) 183 | } 184 | 185 | return nil 186 | }); err != nil { 187 | if s := status.Code(err); s == codes.InvalidArgument { 188 | return retry.NonRetryableError(err) 189 | } 190 | 191 | if errors.Is(err, nodiskFoundError{}) { 192 | return retry.NonRetryableError(err) 193 | } 194 | 195 | return retry.RetryableError(err) 196 | } 197 | 198 | return nil 199 | }); err != nil { 200 | resp.Diagnostics.AddError("failed to get list of disks", err.Error()) 201 | 202 | return 203 | } 204 | 205 | state.ID = basetypes.NewStringValue("machine_disks") 206 | 207 | diags = resp.State.Set(ctx, &state) 208 | resp.Diagnostics.Append(diags...) 209 | 210 | if resp.Diagnostics.HasError() { 211 | return 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /pkg/talos/talos_machine_disks_data_source_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package talos_test 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/hashicorp/terraform-plugin-testing/helper/acctest" 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" 12 | ) 13 | 14 | func TestAccTalosMachineDisksDataSource(t *testing.T) { 15 | rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) 16 | 17 | resource.ParallelTest(t, resource.TestCase{ 18 | ExternalProviders: map[string]resource.ExternalProvider{ 19 | "libvirt": { 20 | Source: "dmacvicar/libvirt", 21 | }, 22 | }, 23 | ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, 24 | Steps: []resource.TestStep{ 25 | // test default config 26 | { 27 | Config: testAccTalosMachineDisksDataSourceConfigV0("talos", rName), 28 | Check: resource.ComposeAggregateTestCheckFunc( 29 | resource.TestCheckResourceAttr("data.talos_machine_disks.this", "id", "machine_disks"), 30 | resource.TestCheckResourceAttrSet("data.talos_machine_disks.this", "node"), 31 | resource.TestCheckResourceAttrSet("data.talos_machine_disks.this", "endpoint"), 32 | resource.TestCheckResourceAttrSet("data.talos_machine_disks.this", "client_configuration.ca_certificate"), 33 | resource.TestCheckResourceAttrSet("data.talos_machine_disks.this", "client_configuration.client_certificate"), 34 | resource.TestCheckResourceAttrSet("data.talos_machine_disks.this", "client_configuration.client_key"), 35 | resource.TestCheckResourceAttr("data.talos_machine_disks.this", "selector", "disk.size > 6u * GB"), 36 | resource.TestCheckResourceAttr("data.talos_machine_disks.this", "disks.#", "1"), 37 | resource.TestCheckResourceAttr("data.talos_machine_disks.this", "disks.0.dev_path", "/dev/vda"), 38 | ), 39 | }, 40 | }, 41 | }) 42 | } 43 | 44 | func testAccTalosMachineDisksDataSourceConfigV0(providerName, rName string) string { 45 | config := dynamicConfig{ 46 | Provider: providerName, 47 | ResourceName: rName, 48 | WithApplyConfig: false, 49 | WithBootstrap: false, 50 | } 51 | 52 | return config.render() 53 | } 54 | -------------------------------------------------------------------------------- /pkg/talos/talos_machine_disks_data_source_types.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | // Code generated by "diskspec.go"; DO NOT EDIT. 6 | 7 | package talos 8 | 9 | import ( 10 | "github.com/hashicorp/terraform-plugin-framework/attr" 11 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema" 12 | "github.com/hashicorp/terraform-plugin-framework/types" 13 | "github.com/siderolabs/gen/xslices" 14 | "github.com/siderolabs/talos/pkg/machinery/resources/block" 15 | ) 16 | 17 | type diskspec struct { 18 | DevPath types.String `tfsdk:"dev_path"` 19 | Size types.Int64 `tfsdk:"size"` 20 | PrettySize types.String `tfsdk:"pretty_size"` 21 | IOSize types.Int64 `tfsdk:"io_size"` 22 | SectorSize types.Int64 `tfsdk:"sector_size"` 23 | Readonly types.Bool `tfsdk:"readonly"` 24 | CDROM types.Bool `tfsdk:"cdrom"` 25 | Model types.String `tfsdk:"model"` 26 | Serial types.String `tfsdk:"serial"` 27 | Modalias types.String `tfsdk:"modalias"` 28 | WWID types.String `tfsdk:"wwid"` 29 | UUID types.String `tfsdk:"uuid"` 30 | BusPath types.String `tfsdk:"bus_path"` 31 | SubSystem types.String `tfsdk:"sub_system"` 32 | Transport types.String `tfsdk:"transport"` 33 | Rotational types.Bool `tfsdk:"rotational"` 34 | SecondaryDisks types.List `tfsdk:"secondary_disks"` 35 | Symlinks types.List `tfsdk:"symlinks"` 36 | } 37 | 38 | var diskspecAttributes = map[string]schema.Attribute{ 39 | "dev_path": schema.StringAttribute{ 40 | Computed: true, 41 | }, 42 | "size": schema.Int64Attribute{ 43 | Computed: true, 44 | }, 45 | "pretty_size": schema.StringAttribute{ 46 | Computed: true, 47 | }, 48 | "io_size": schema.Int64Attribute{ 49 | Computed: true, 50 | }, 51 | "sector_size": schema.Int64Attribute{ 52 | Computed: true, 53 | }, 54 | "readonly": schema.BoolAttribute{ 55 | Computed: true, 56 | }, 57 | "cdrom": schema.BoolAttribute{ 58 | Computed: true, 59 | }, 60 | "model": schema.StringAttribute{ 61 | Computed: true, 62 | }, 63 | "serial": schema.StringAttribute{ 64 | Computed: true, 65 | }, 66 | "modalias": schema.StringAttribute{ 67 | Computed: true, 68 | }, 69 | "wwid": schema.StringAttribute{ 70 | Computed: true, 71 | }, 72 | "uuid": schema.StringAttribute{ 73 | Computed: true, 74 | }, 75 | "bus_path": schema.StringAttribute{ 76 | Computed: true, 77 | }, 78 | "sub_system": schema.StringAttribute{ 79 | Computed: true, 80 | }, 81 | "transport": schema.StringAttribute{ 82 | Computed: true, 83 | }, 84 | "rotational": schema.BoolAttribute{ 85 | Computed: true, 86 | }, 87 | "secondary_disks": schema.ListAttribute{ 88 | ElementType: types.StringType, 89 | Computed: true, 90 | }, 91 | "symlinks": schema.ListAttribute{ 92 | ElementType: types.StringType, 93 | Computed: true, 94 | }, 95 | } 96 | 97 | func diskspecToTFTypes(diskspecSpec block.DiskSpec) diskspec { 98 | return diskspec{ 99 | DevPath: types.StringValue(diskspecSpec.DevPath), 100 | Size: types.Int64Value(int64(diskspecSpec.Size)), 101 | PrettySize: types.StringValue(diskspecSpec.PrettySize), 102 | IOSize: types.Int64Value(int64(diskspecSpec.IOSize)), 103 | SectorSize: types.Int64Value(int64(diskspecSpec.SectorSize)), 104 | Readonly: types.BoolValue(diskspecSpec.Readonly), 105 | CDROM: types.BoolValue(diskspecSpec.CDROM), 106 | Model: types.StringValue(diskspecSpec.Model), 107 | Serial: types.StringValue(diskspecSpec.Serial), 108 | Modalias: types.StringValue(diskspecSpec.Modalias), 109 | WWID: types.StringValue(diskspecSpec.WWID), 110 | UUID: types.StringValue(diskspecSpec.UUID), 111 | BusPath: types.StringValue(diskspecSpec.BusPath), 112 | SubSystem: types.StringValue(diskspecSpec.SubSystem), 113 | Transport: types.StringValue(diskspecSpec.Transport), 114 | Rotational: types.BoolValue(diskspecSpec.Rotational), 115 | SecondaryDisks: types.ListValueMust(types.StringType, xslices.Map(diskspecSpec.SecondaryDisks, func(s string) attr.Value { 116 | return types.StringValue(s) 117 | })), 118 | Symlinks: types.ListValueMust(types.StringType, xslices.Map(diskspecSpec.Symlinks, func(s string) attr.Value { 119 | return types.StringValue(s) 120 | })), 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /pkg/talos/testdata/patch-invalid.yaml: -------------------------------------------------------------------------------- 1 | machine: 2 | sysctl: 3 | foo: bar 4 | -------------------------------------------------------------------------------- /pkg/talos/testdata/patch-json6502.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "add", 4 | "path": "/cluster/allowSchedulingOnControlPlanes", 5 | "value": true 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /pkg/talos/testdata/patch-strategic.yaml: -------------------------------------------------------------------------------- 1 | machine: 2 | sysfs: 3 | foo: bar 4 | cluster: 5 | apiServer: 6 | extraArgs: 7 | foo: bar 8 | -------------------------------------------------------------------------------- /pkg/talos/testdata/secrets.yaml: -------------------------------------------------------------------------------- 1 | cluster: 2 | id: _u8NZvwQ9ObtEN7iTzc-OEpk20K-rnO3FNcjvVEQ84Q= 3 | secret: UnZE8oq6qPNI8tuw+WF3PGi2Zba0RQuit/aJTflOau8= 4 | secrets: 5 | bootstraptoken: m2wfba.pcyzhp6rf6pubqtk 6 | secretboxencryptionsecret: avDR6jwn4iYS6sTOH689P2UcNUlh3UsuO+FaOKI2hls= 7 | trustdinfo: 8 | token: s5lcto.f2ythdlx6avcsny9 9 | certs: 10 | etcd: 11 | crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmakNDQVNTZ0F3SUJBZ0lSQUt6KzNQbkZYWHNTdXNQb3RLTnVabG93Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TXpBME1ERXhORE01TURaYUZ3MHpNekF6TWpreE5ETTVNRFphTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFTbGFaU0p1UnhMCit4NDdYelY5OWIwaEd1dmdybGZrUnFEdStVUWlrSFJlRCtFL3VZUXprc1ArZTFLMVBUcFJVTG45ZEJYY21jd1AKazY2UXRCN09mQ0pEbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5kVHVVdmduZXcwCkJSa0dZRnJueWNpWFZjUTdNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUURJZGVqQ3ppL25xb3h0eUp3QnROTEYKTDE3UWdqQjNzMFoySUV5ZDZPTE51UUlnY0lHcWRWemJKQ3dXSkZXSWxnWWVyUGZvZzdzUjFxMWdKV25ST3p4UApBakE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K 12 | key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUoxWVI2ck9pd3N2TmRWZFErVnpiQ1hlRlBEbGJ1cDVUM1ZidnJrVDM2M1NvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFcFdtVWlia2NTL3NlTzE4MWZmVzlJUnJyNEs1WDVFYWc3dmxFSXBCMFhnL2hQN21FTTVMRAovbnRTdFQwNlVWQzUvWFFWM0puTUQ1T3VrTFFlem53aVF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= 13 | k8s: 14 | crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpakNDQVMrZ0F3SUJBZ0lRSE5COFFlVjRtazlUR3k4amtTUGtYVEFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNRFF3TVRFME16a3dObG9YRFRNek1ETXlPVEUwTXprdwpObG93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCQVBKQjEwL3RnVFlkdVhrS0h6SVFEZDNLbW54MithbmFXcGN3RUlhWlhMbnNsRHRycGU3ancwaXRVK1oKa2w2eEd5STk4M0FpRkxWc004cHhra3RoZ2tTallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU1K0hGd29PbTdURWhpcm1DTGt2SllyRmRQc293Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQU1WZFNVUEUKcGlNWkpkNHNYV1pvdzdLb0djWWhPb1NtcDJkaUZEdUEzMjcyQWlFQTRuamcwN2ZhVEFGck1SUGF4SmFIMVhsdQpKTHBPMTh0bHZhVlVFMW5XY2xnPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== 15 | key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUZJQ0crOUR1Wm9YU0xiVjRWK1VoZkdRUWV5OUJ3dWEwZUx6M0hTU1hyMmhvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQThrSFhUKzJCTmgyNWVRb2ZNaEFOM2NxYWZIYjVxZHBhbHpBUWhwbGN1ZXlVTzJ1bDd1UApEU0sxVDVtU1hyRWJJajN6Y0NJVXRXd3p5bkdTUzJHQ1JBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= 16 | k8saggregator: 17 | crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUtDY3hEVUM4UG9GK3pSajJWVlJLWTR3Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU16QTBNREV4TkRNNU1EWmFGdzB6TXpBek1qa3hORE01TURaYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVFPUjZKcTl1ekp3RWNFZnowc1dKdERVejhwNUpseHRJZkJjTTMzRFJ5cDhCSDZGQTFCCjJiUkx5ZTBsU3p6TXFmdVpFblhxOE9qazdobklGSUdsNlVNaW8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGQUpPaUFGNTRhUXRPaUpzdFU2U2Z1QWpGOFJwTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRREdPOUhXVXNaZlozRUdJTEdGRjJwUDIwUGNjSDZMV2hZSjg1eHB2RDBOSGdJaEFOOHFpVElXYVF2dUs3M1cKVENwT2g5TU1PS2o1YmFNcEh6M2FJOGVMZHBiVAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== 18 | key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU4rRDdGWGJoUTg4c1d6eEJPSXZtMVJVVVBtT25VeFBCRGlvR21mL1dnMjlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFRGtlaWF2YnN5Y0JIQkg4OUxGaWJRMU0vS2VTWmNiU0h3WEROOXcwY3FmQVIraFFOUWRtMApTOG50SlVzOHpLbjdtUkoxNnZEbzVPNFp5QlNCcGVsRElnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= 19 | k8sserviceaccount: 20 | key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVabmsrN2djSXBLdC8vM2lrQ1dLZm5SNnFjeWY5bHVyK1lGbzQyTlhVVVlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeG9rOTBEbnI2MGRYQ3BhQmxUMnVJUnRjdUJPLytCVjZEajVPaWYvTGVwSS95NktlQ2lRTApwRGZxenNHQW5zQXkrVHI3SWNxSUlROGZGaXRtK0t5emJBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= 21 | os: 22 | crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBM0E0TEZ3cDVTZG5wTXVmYlp3NHVpekFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qTXdOREF4TVRRek9UQTJXaGNOTXpNd016STVNVFF6T1RBMldqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUZ2TWUyeHFzSk9WemkvY0xLNXVXVzU2VmZZK29nWlYvQVowCmxlTFdtTWl1bzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkxqK3VablllVFFUdEdmUgpOeVVQYWh6dzNkdkhNQVVHQXl0bGNBTkJBQVg4cVhJNm4ydlk3ZGxnZGtxckUvN25ua2kwTzFtVERDL3dBamlwCmpaemY5QmhocEdRUXFYSkxHdlhJTnRDaXN5KzQrcTVtOUVjUUpMMXF4UWdOdndnPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== 23 | key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJSlVlQmxic3hhMW0vR1B0NTZCeVIvZ1Z3YWRzVmdkc3pXZEh4MWZiZ0c4VwotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K 24 | -------------------------------------------------------------------------------- /pkg/talos/testdata/secretsv1.2.yaml: -------------------------------------------------------------------------------- 1 | cluster: 2 | id: q_I385nl7MWqU1UpW224rQyZW4TWd_WmnxsA2MQLsl8= 3 | secret: 1szT7qMuensSCcSVRtnFsG0pbXMLMSZ8r5wu/41aJBc= 4 | secrets: 5 | bootstraptoken: 5co9z6.qnnjtotc5ffntt62 6 | aescbcencryptionsecret: hLrjDIpZ8gSGwejFfnUnjOrn9PQ7Bj3yq/ggAgD9AHA= 7 | trustdinfo: 8 | token: o2q4ek.ofdeihu3li44x7lr 9 | certs: 10 | etcd: 11 | crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmakNDQVNTZ0F3SUJBZ0lSQU8rYmlXSlFJdHZXZUZ0UUNEVDhwRXd3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TXpBME1ERXhOVFF4TURSYUZ3MHpNekF6TWpreE5UUXhNRFJhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFReHRnaFlZV1AvCngzWGFBM1RPVXd4Y1AySlh2QVYzdllaS2I1SENKK0E2M2dieE50dW5Gcm03NW8rK0ZQQndYdUtZUmMrU09pTXEKdWY5bjdkZmY4cUJKbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkU2VUVneitoOSsvCnZYdnNod1d2bHJvQkh6SlFNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUUQ3YTFzMy91cmRybFlxaXJxTmN6aTIKTm5qNVFCdFVmczFNYkNqNTdkYXR3d0lnZlJYdEIyWVZMUy9OMFVQTDkxekhITCtLM09EaEZ2M1dsc0gwMlpmdgpMNHc9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K 12 | key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUJDNUpZQmgzWWQ2NnJwWkcvTHZEMWt4SFRvWTA4QnZsQkpMcy9aZXR4NldvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFTWJZSVdHRmovOGQxMmdOMHpsTU1YRDlpVjd3RmQ3MkdTbStSd2lmZ090NEc4VGJicHhhNQp1K2FQdmhUd2NGN2ltRVhQa2pvaktybi9aKzNYMy9LZ1NRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= 13 | k8s: 14 | crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVW9hWGkyZGxUWHk1alNBUVdvSUZOVEFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNRFF3TVRFMU5ERXdORm9YRFRNek1ETXlPVEUxTkRFdwpORm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCRWJieTQreTdIWmZUcVNNaDRtMWx3a3E3THE5WUtWdVhmV3BJLzZ4K1orZC9uUFJFNFA0eGhNUklKL3oKZHl4TDJxTGNSOUcxV3pjVWJBRVYrMjliUWNDallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVUzRG8xb2MzM054dWhYRTJ4M2NvbHM3a2dWWmN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQU9pb3RHR1MKNnJLdWFoT2twMlQ5NjRzSUhhdmx3bUJqZ0ljVkI1dTFPV2RsQWlBRXZKUUVTRGNBZWlmVm1seG1pdWVDMHl4SQowODBqY2FxUjdUVWNjaHhrSnc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== 15 | key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUx5bm9FaURjeG1NL3ZlL1B1R0YwWFNjeEgydG10SGZSdVU0SkVvejBGRmtvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUnR2TGo3THNkbDlPcEl5SGliV1hDU3JzdXIxZ3BXNWQ5YWtqL3JINW41MytjOUVUZy9qRwpFeEVnbi9OM0xFdmFvdHhIMGJWYk54UnNBUlg3YjF0QndBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= 16 | k8saggregator: 17 | crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZRENDQVFhZ0F3SUJBZ0lSQUp5THJmLzk5aE00a1ZNWTJraFd4TjR3Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU16QTBNREV4TlRReE1EUmFGdzB6TXpBek1qa3hOVFF4TURSYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVFZTTBWWUVZWTVOaURlNHp6Z21mYlJSdDRNalRmOUlyeUVVcms1SjNPRFQzYkFpanVDCmd6eWpmTkZIbFlXbm9PcWZBeGpjVVVsQkU2L2xuRmdiMzNwUW8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGTHBKUEhhRGw1UjY4NjlDNEVyVXF5WHhBeUpWTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDCklFc0VlOElSNEwvK3phMC9CbzlUNGRKbERpQ3VDK1BSd1JueXE4OEE5dFUvQWlFQTBGUXNJcGk5V1ZiU2krODQKQkVCaGRWTkpmQUVUYTZVQ2UrTWFsNUJRUjlrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== 18 | key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUMxSDViQUY5RkJWQzVIQjZ2dzJwL1FRUFkvWEVjdzhaTUJ0ZDZFTmw3cXFvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFR0RORldCR0dPVFlnM3VNODRKbjIwVWJlREkwMy9TSzhoRks1T1NkemcwOTJ3SW83Z29NOApvM3pSUjVXRnA2RHFud01ZM0ZGSlFST3Y1WnhZRzk5NlVBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= 19 | k8sserviceaccount: 20 | key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxHRjlhcmp4SEdyMExMbTdMTjg0Ympjbml2RWpGSkxlUFNvVGhZUS9maWdvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNjRuQVlld3hqeVkrVkY4MDZ5WU5iU3pnNEl4cFh6TW1hMW93b3FjbDc5elZtMkRsbHcxUApYR3FTZ0hpWUxwcjZ1ZU5OeSswcXdOdklCU3RKSXZLVzNnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo= 21 | os: 22 | crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEIzcXY0bDNhTStSaGFsWmdHOGowdDNNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16QTBNREV4TlRReE1EUmFGdzB6TXpBek1qa3hOVFF4TURSYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBWk1TT1d4aHF4UThEbHdUVmszM2xRN09ydDAvOTE5b0JXTVpUCmRSU3Q4SGFqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVYkhDeHcyOTd4RHc3Tjh0SQpDQTJTUDc2K3Q5OHdCUVlESzJWd0EwRUFrcnQ1UEVnZ2JZNFFlYnNIa2lDTmZlMFpZNlE1UmZhVm52TVRxOE1lCnRhSktTQ1NPYTljczh2dXVDMnl2QmNSU0hPWldocG9WaW05bXhEaVc3TDZTQXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== 23 | key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJRjdtNmJKWHNOd3F4ejFMaXRnVlFJSEx5WDJab1hadW85UTNEZjRGSThWaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K 24 | -------------------------------------------------------------------------------- /templates/data-sources/machine_configuration.md.tmpl: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}" 3 | subcategory: "" 4 | description: |- 5 | {{ .Description | plainmarkdown | trimspace | prefixlines " " }} 6 | --- 7 | 8 | # {{.Name}} ({{.Type}}) 9 | 10 | {{ .Description | trimspace }} 11 | 12 | -> **Note:** It is recommended to set the optional `talos_version` attribute. Otherwise when using a new version of the provider with a new major version of the Talos SDK, new machineconfig features will be enabled by default which could cause unexpected behavior. 13 | 14 | {{ if .HasExample -}} 15 | ## Example Usage 16 | 17 | {{ tffile (printf .ExampleFile) }} 18 | {{- end }} 19 | {{ .SchemaMarkdown | trimspace }} 20 | -------------------------------------------------------------------------------- /templates/data-sources/machine_disks.md.tmpl: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}" 3 | subcategory: "" 4 | description: |- 5 | {{ .Description | plainmarkdown | trimspace | prefixlines " " }} 6 | --- 7 | 8 | # {{.Name}} ({{.Type}}) 9 | 10 | {{ .Description | trimspace }} 11 | 12 | -> **Note:** Since Talos natively supports `.machine.install.diskSelector`, the `talos_machine_disks` data source maybe just used to query disk information that could be used elsewhere. It's recommended to use `machine.install.diskSelector` in Talos machine configuration. 13 | 14 | {{ if .HasExample -}} 15 | ## Example Usage 16 | 17 | {{ tffile (printf .ExampleFile) }} 18 | {{- end }} 19 | {{ .SchemaMarkdown | trimspace }} 20 | -------------------------------------------------------------------------------- /templates/guides/version-0.2-upgrade.html.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "Terraform Talos Provider Version 0.2 Upgrade Guide" 3 | description: |- 4 | Terraform Talos Provider Version 0.2 Upgrade Guide 5 | --- 6 | 7 | # Terraform Talos Provider Version 0.2 Upgrade Guide 8 | 9 | Version 0.2 of the Talos Terraform provider is a major release and include some breaking chages. This guide will walk you through the changes and how to upgrade your Terraform configuration. 10 | 11 | ~> **NOTE:** Version 0.2 of the Talos Terraform provider drops support for the following resources: 12 | 13 | > * `talos_client_configuration` 14 | > * `talos_cluster_kubeconfig` 15 | > * `talos_machine_configuration_controlplane` 16 | > * `talos_machine_configuration_worker` 17 | 18 | The following table lists the resources that have been removed and the new resources that replace them. 19 | 20 | | Removed Resource | Type | New Resource | Type | 21 | | ------------------------------------------ | -------- | ----------------------------- | ------------- | 22 | | `talos_client_configuration` | Resource | `talos_client_configuration` | Data Source | 23 | | `talos_cluster_kubeconfig` | Resource | `talos_cluster_kubeconfig` | Data Source | 24 | | `talos_machine_configuration_controlplane` | Resource | `talos_machine_configuration` | Data Resource | 25 | | `talos_machine_configuration_worker` | Resource | `talos_machine_configuration` | Data Resource | 26 | 27 | ## Upgrade topics: 28 | 29 | - [Upgrading `talos_client_configuration` resource](#upgrading-talos_client_configuration-resource) 30 | - [Upgrading `talos_cluster_kubeconfig` resource](#upgrading-talos_cluster_kubeconfig-resource) 31 | - [Upgrading `talos_machine_configuration_controlplane` resource](#upgrading-talos_machine_configuration_controlplane-resource) 32 | - [Upgrading `talos_machine_configuration_worker` resource](#upgrading-talos_machine_configuration_worker-resource) 33 | 34 | ### Upgrading `talos_client_configuration` resource 35 | 36 | The `talos_client_configuration` resource has been removed. The `talos_client_configuration` data source should be used instead. 37 | 38 | For example if the following resource was used: 39 | 40 | ```hcl 41 | resource "talos_machine_secrets" "this" {} 42 | 43 | resource "talos_client_configuration" "talosconfig" { 44 | cluster_name = "example-cluster" 45 | machine_secrets = talos_machine_secrets.this.machine_secrets 46 | } 47 | ``` 48 | 49 | `talos_client_configuration` resource should be first removed from the state: 50 | 51 | ```bash 52 | terraform state rm talos_client_configuration.talosconfig 53 | ``` 54 | 55 | and the code should be updated to: 56 | 57 | ```hcl 58 | resource "talos_machine_secrets" "machine_secrets" {} 59 | 60 | data "talos_client_configuration" "this" { 61 | cluster_name = "example-cluster" 62 | client_configuration = talos_machine_secrets.this.client_configuration 63 | } 64 | ``` 65 | 66 | ### Upgrading `talos_cluster_kubeconfig` resource 67 | 68 | The `talos_cluster_kubeconfig` resource has been removed. The `talos_cluster_kubeconfig` data source should be used instead. 69 | 70 | For example if the following resource was used: 71 | 72 | ```hcl 73 | resource "talos_machine_secrets" "this" {} 74 | 75 | resource "talos_client_configuration" "this" { 76 | cluster_name = "example-cluster" 77 | machine_secrets = talos_machine_secrets.this.machine_secrets 78 | } 79 | 80 | resource "talos_cluster_kubeconfig" "kubeconfig" { 81 | talos_config = talos_client_configuration.this.talos_config 82 | endpoint = "10.5.0.2" 83 | node = "10.5.0.2" 84 | } 85 | ``` 86 | 87 | `talos_cluster_kubeconfig` resource should be first removed from the state: 88 | 89 | ```bash 90 | terraform state rm talos_cluster_kubeconfig.kubeconfig 91 | ``` 92 | 93 | and the code should be updated to: 94 | 95 | ```hcl 96 | resource "talos_machine_secrets" "machine_secrets" {} 97 | 98 | data "talos_cluster_kubeconfig" "this" { 99 | client_configuration = talos_machine_secrets.this.client_configuration 100 | node = "10.5.0.2" 101 | } 102 | ``` 103 | 104 | ### Upgrading `talos_machine_configuration_controlplane` resource 105 | 106 | The `talos_machine_configuration_controlplane` resource has been removed. The `talos_machine_configuration` data source should be used instead. 107 | 108 | For example if the following resource was used: 109 | 110 | ```hcl 111 | resource "talos_machine_secrets" "this" {} 112 | 113 | resource "talos_client_configuration" "this" { 114 | cluster_name = "example-cluster" 115 | machine_secrets = talos_machine_secrets.this.machine_secrets 116 | } 117 | 118 | resource "talos_machine_configuration_controlplane" "this" { 119 | cluster_name = "example-cluster" 120 | cluster_endpoint = "https://10.5.0.2:6443" 121 | machine_secrets = talos_machine_secrets.this.machine_secrets 122 | } 123 | 124 | resource "talos_machine_configuration_apply" "this" { 125 | talos_config = talos_client_configuration.this.talos_config 126 | machine_configuration = talos_machine_configuration_controlplane.this.machine_config 127 | node = "10.5.0.2" 128 | endpoint = "10.5.0.2" 129 | } 130 | ``` 131 | 132 | `talos_machine_configuration_controlplane` resource should be first removed from the state: 133 | 134 | ```bash 135 | terraform state rm talos_machine_configuration_controlplane.cp 136 | ``` 137 | 138 | and the code should be updated to: 139 | 140 | ```hcl 141 | resource "talos_machine_secrets" "machine_secrets" {} 142 | 143 | data "talos_machine_configuration" "this" { 144 | cluster_name = "example-cluster" 145 | cluster_endpoint = "https://10.5.0.2:6443" 146 | machine_type = "controlplane" 147 | talos_version = talos_machine_secrets.this.talos_version 148 | machine_secrets = talos_machine_secrets.this.machine_secrets 149 | } 150 | 151 | resource "talos_machine_configuration_apply" "this" { 152 | client_configuration = talos_machine_secrets.this.client_configuration 153 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 154 | node = "10.5.0.2" 155 | } 156 | ``` 157 | 158 | ### Upgrading `talos_machine_configuration_worker` resource 159 | 160 | The `talos_machine_configuration_worker` resource has been removed. The `talos_machine_configuration` data source should be used instead. 161 | 162 | For example if the following resource was used: 163 | 164 | ```hcl 165 | resource "talos_machine_secrets" "this" {} 166 | 167 | resource "talos_client_configuration" "this" { 168 | cluster_name = "example-cluster" 169 | machine_secrets = talos_machine_secrets.this.machine_secrets 170 | } 171 | 172 | resource "talos_machine_configuration_worker" "this" { 173 | cluster_name = "example-cluster" 174 | cluster_endpoint = "https://10.5.0.2:6443" 175 | machine_secrets = talos_machine_secrets.this.machine_secrets 176 | } 177 | 178 | resource "talos_machine_configuration_apply" "this" { 179 | talos_config = talos_client_configuration.this.talos_config 180 | machine_configuration = talos_machine_configuration_worker.this.machine_config 181 | node = "10.5.0.3" 182 | endpoint = "10.5.0.3" 183 | } 184 | ``` 185 | 186 | `talos_machine_configuration_worker` resource should be first removed from the state: 187 | 188 | ```bash 189 | terraform state rm talos_machine_configuration_worker.worker 190 | ``` 191 | 192 | and the code should be updated to: 193 | 194 | ```hcl 195 | resource "talos_machine_secrets" "machine_secrets" {} 196 | 197 | data "talos_machine_configuration" "this" { 198 | cluster_name = "example-cluster" 199 | cluster_endpoint = "https://10.5.0.2:6443" 200 | machine_type = "worker" 201 | talos_version = talos_machine_secrets.this.talos_version 202 | machine_secrets = talos_machine_secrets.this.machine_secrets 203 | } 204 | 205 | resource "talos_machine_configuration_apply" "this" { 206 | client_configuration = talos_machine_secrets.this.client_configuration 207 | machine_configuration_input = data.talos_machine_configuration.this.machine_configuration 208 | node = "10.5.0.3" 209 | } 210 | ``` 211 | -------------------------------------------------------------------------------- /templates/index.md.tmpl: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "Provider: Talos" 3 | description: |- 4 | The Talos provider is used to manage a Talos cluster config generation and initial setup. 5 | --- 6 | 7 | # Talos Provider 8 | 9 | Talos provider allows to generate configs for a Talos cluster and apply them to the nodes, bootstrap nodes, check cluster health, and retrieve `kubeconfig` and `talosconfig`. 10 | 11 | Complete usages for this provider across a variety of environments can be found [here](https://github.com/siderolabs/contrib/tree/main/examples/terraform). 12 | -------------------------------------------------------------------------------- /templates/resources.md.tmpl: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}" 3 | subcategory: "" 4 | description: |- 5 | {{ .Description | plainmarkdown | trimspace | prefixlines " " }} 6 | --- 7 | 8 | # {{.Name}} ({{.Type}}) 9 | 10 | {{ .Description | trimspace }} 11 | 12 | {{ if .HasExample -}} 13 | ## Example Usage 14 | 15 | {{ tffile (printf .ExampleFile) }} 16 | {{- end }} 17 | {{ .SchemaMarkdown | trimspace }} 18 | {{ if .HasImport -}} 19 | ## Import 20 | 21 | Import is supported using the following syntax: 22 | 23 | {{ tffile (printf .ImportFile) }} 24 | {{- end }} 25 | -------------------------------------------------------------------------------- /terraform-registry-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "metadata": { 4 | "protocol_versions": [ 5 | "5.0" 6 | ] 7 | } 8 | } -------------------------------------------------------------------------------- /tools/tools.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | //go:build tools 6 | 7 | package tools 8 | 9 | import ( 10 | // document generation 11 | _ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs" 12 | ) 13 | --------------------------------------------------------------------------------