From d988f5b4c12ed4690ae5243838c597233740dd6a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 21 Nov 2025 13:14:25 -0500 Subject: [PATCH 1/2] gen_tfvars: Fail gracefully when "make cloud-config" hasn't been done The gen_tfvars playbook was failing with an undefined variable when the user forgot to run the new "make cloud-config" step. Add a helpful error message. Signed-off-by: Chuck Lever --- playbooks/roles/gen_tfvars/tasks/main.yml | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/playbooks/roles/gen_tfvars/tasks/main.yml b/playbooks/roles/gen_tfvars/tasks/main.yml index 72ff5f095..7972de94c 100644 --- a/playbooks/roles/gen_tfvars/tasks/main.yml +++ b/playbooks/roles/gen_tfvars/tasks/main.yml @@ -28,6 +28,37 @@ path: "{{ topdir_path }}/{{ kdevops_terraform_tfvars }}" register: kdevops_tfvars_dest +- name: Find dynamic Kconfig files for {{ kdevops_terraform_provider }} + ansible.builtin.find: + paths: "{{ topdir_path }}/terraform/{{ kdevops_terraform_provider }}/kconfigs" + patterns: "Kconfig*.generated" + register: provider_kconfig_files + when: + - kdevops_enable_terraform + +- name: Check if any dynamic Kconfig files are empty + ansible.builtin.fail: + msg: | + ERROR: Dynamic cloud configuration not generated or incomplete. + + Found {{ provider_kconfig_files.matched }} dynamic Kconfig file(s) for {{ kdevops_terraform_provider }}, + but at least one is empty ({{ item.path }}). + + Before running 'make' or 'make bringup', you must generate the + dynamic cloud configuration by running: + + make cloud-config + + For more information, run 'make help' and see the cloud-config + targets section. + when: + - kdevops_enable_terraform + - provider_kconfig_files.matched > 0 + - item.size == 0 + loop: "{{ provider_kconfig_files.files }}" + loop_control: + label: "{{ item.path }}" + - name: Ensure proper permission on {{ kdevops_terraform_tfvars }} become: true become_flags: "su - -c" From 7f46a4a313d2f3da3027bee1d28f2a75df5fc212 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sun, 16 Nov 2025 19:58:25 -0500 Subject: [PATCH 2/2] terraform: add OpenTofu support as an alternative to Terraform Add comprehensive support for OpenTofu as an alternative to Terraform for infrastructure provisioning. OpenTofu is an open-source fork of Terraform maintained by the Linux Foundation that provides full compatibility with Terraform configurations while offering a community-driven development model. The implementation adds a Kconfig choice between Terraform and OpenTofu with automatic binary path configuration. The install_terraform role now handles installation of either tool based on user selection, downloading from appropriate sources. All Ansible tasks using the cloud.terraform.terraform and terraform_output modules now use the binary_path parameter to invoke the correct tool. Users can select their preferred tool via menuconfig and the system handles all necessary configuration automatically through extra_vars.yaml. Default versions are Terraform 1.2.3 and OpenTofu 1.6.0, both configurable via Ansible variables. Generated-by: Claude AI Signed-off-by: Chuck Lever --- .../roles/extra_volumes/defaults/main.yml | 3 ++ .../extra_volumes/tasks/providers/aws.yml | 1 + .../roles/install_terraform/defaults/main.yml | 1 + .../tasks/install-deps/debian/main.yml | 21 ++++++++++++ .../tasks/install-deps/redhat/main.yml | 21 ++++++++++++ .../tasks/install-deps/suse/main.yml | 25 +++++++++++++- playbooks/roles/terraform/defaults/main.yml | 2 ++ playbooks/roles/terraform/tasks/main.yml | 4 +++ terraform/Kconfig | 33 +++++++++++++++++++ 9 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 playbooks/roles/extra_volumes/defaults/main.yml diff --git a/playbooks/roles/extra_volumes/defaults/main.yml b/playbooks/roles/extra_volumes/defaults/main.yml new file mode 100644 index 000000000..447c538a0 --- /dev/null +++ b/playbooks/roles/extra_volumes/defaults/main.yml @@ -0,0 +1,3 @@ +--- +# This will be set from extra_vars.yaml based on Kconfig selection +terraform_binary_path: "/usr/local/bin/terraform" diff --git a/playbooks/roles/extra_volumes/tasks/providers/aws.yml b/playbooks/roles/extra_volumes/tasks/providers/aws.yml index b110f68ec..a0c90e47d 100644 --- a/playbooks/roles/extra_volumes/tasks/providers/aws.yml +++ b/playbooks/roles/extra_volumes/tasks/providers/aws.yml @@ -17,6 +17,7 @@ delegate_to: localhost run_once: true cloud.terraform.terraform_output: + binary_path: "{{ terraform_binary_path }}" format: json name: "extra_volumes_map" project_path: "{{ topdir_path }}/terraform/aws" diff --git a/playbooks/roles/install_terraform/defaults/main.yml b/playbooks/roles/install_terraform/defaults/main.yml index 230fa17e1..79fa1d621 100644 --- a/playbooks/roles/install_terraform/defaults/main.yml +++ b/playbooks/roles/install_terraform/defaults/main.yml @@ -3,6 +3,7 @@ # You can override these terraform_version: "1.2.3" +opentofu_version: "1.6.0" force_install_if_present: false # Ignores using distro packages and installs from zip file instead diff --git a/playbooks/roles/install_terraform/tasks/install-deps/debian/main.yml b/playbooks/roles/install_terraform/tasks/install-deps/debian/main.yml index 43d94d933..854468e54 100644 --- a/playbooks/roles/install_terraform/tasks/install-deps/debian/main.yml +++ b/playbooks/roles/install_terraform/tasks/install-deps/debian/main.yml @@ -4,6 +4,15 @@ register: terraform_present changed_when: terraform_present.rc == 1 failed_when: terraform_present.rc != 0 and terraform_present.rc != 1 + when: terraform_use_terraform|bool + tags: ["terraform", "verify"] + +- name: Verify OpenTofu installation + ansible.builtin.command: "which tofu" + register: opentofu_present + changed_when: opentofu_present.rc == 1 + failed_when: opentofu_present.rc != 0 and opentofu_present.rc != 1 + when: terraform_use_opentofu|bool tags: ["terraform", "verify"] - name: Install Terraform Dependencies @@ -23,4 +32,16 @@ dest: /usr/local/bin remote_src: true when: + - terraform_use_terraform|bool - force_install_if_present|bool or terraform_present.rc != 0 + +- name: Download OpenTofu from the latest release and install locally + become: true + become_method: sudo + ansible.builtin.unarchive: + src: https://github.com/opentofu/opentofu/releases/download/v{{ opentofu_version }}/tofu_{{ opentofu_version }}_linux_amd64.zip + dest: /usr/local/bin + remote_src: true + when: + - terraform_use_opentofu|bool + - force_install_if_present|bool or opentofu_present.rc != 0 diff --git a/playbooks/roles/install_terraform/tasks/install-deps/redhat/main.yml b/playbooks/roles/install_terraform/tasks/install-deps/redhat/main.yml index 45dbef649..e6a4d9688 100644 --- a/playbooks/roles/install_terraform/tasks/install-deps/redhat/main.yml +++ b/playbooks/roles/install_terraform/tasks/install-deps/redhat/main.yml @@ -4,6 +4,15 @@ register: terraform_present changed_when: terraform_present.rc == 1 failed_when: terraform_present.rc != 0 and terraform_present.rc != 1 + when: terraform_use_terraform|bool + tags: ["terraform", "verify"] + +- name: Verify OpenTofu installation + ansible.builtin.command: "which tofu" + register: opentofu_present + changed_when: opentofu_present.rc == 1 + failed_when: opentofu_present.rc != 0 and opentofu_present.rc != 1 + when: terraform_use_opentofu|bool tags: ["terraform", "verify"] - name: Download Terraform from the latest release and install locally @@ -14,4 +23,16 @@ dest: /usr/local/bin remote_src: true when: + - terraform_use_terraform|bool - force_install_if_present|bool or terraform_present.rc != 0 + +- name: Download OpenTofu from the latest release and install locally + become: true + become_method: sudo + ansible.builtin.unarchive: + src: https://github.com/opentofu/opentofu/releases/download/v{{ opentofu_version }}/tofu_{{ opentofu_version }}_linux_amd64.zip + dest: /usr/local/bin + remote_src: true + when: + - terraform_use_opentofu|bool + - force_install_if_present|bool or opentofu_present.rc != 0 diff --git a/playbooks/roles/install_terraform/tasks/install-deps/suse/main.yml b/playbooks/roles/install_terraform/tasks/install-deps/suse/main.yml index 46cd30ed6..db3186f21 100644 --- a/playbooks/roles/install_terraform/tasks/install-deps/suse/main.yml +++ b/playbooks/roles/install_terraform/tasks/install-deps/suse/main.yml @@ -17,6 +17,15 @@ register: terraform_present changed_when: terraform_present.rc == 1 failed_when: terraform_present.rc != 0 and terraform_present.rc != 1 + when: terraform_use_terraform|bool + tags: ["terraform", "verify"] + +- name: Verify OpenTofu installation + ansible.builtin.command: "which tofu" + register: opentofu_present + changed_when: opentofu_present.rc == 1 + failed_when: opentofu_present.rc != 0 and opentofu_present.rc != 1 + when: terraform_use_opentofu|bool tags: ["terraform", "verify"] - name: Download Terraform from the latest release and install locally @@ -27,10 +36,23 @@ dest: /usr/local/bin remote_src: true when: + - terraform_use_terraform|bool - force_install_zip|bool - force_install_if_present|bool or (is_sle or is_leap and terraform_present.rc != 0) -- name: Install vagrant and vagrant-libvirt from your tumbleweed repository +- name: Download OpenTofu from the latest release and install locally + become: true + become_method: sudo + ansible.builtin.unarchive: + src: https://github.com/opentofu/opentofu/releases/download/v{{ opentofu_version }}/tofu_{{ opentofu_version }}_linux_amd64.zip + dest: /usr/local/bin + remote_src: true + when: + - terraform_use_opentofu|bool + - force_install_zip|bool + - force_install_if_present|bool or (is_sle or is_leap and opentofu_present.rc != 0) + +- name: Install terraform from your tumbleweed repository become: true become_method: sudo ansible.builtin.package: @@ -38,6 +60,7 @@ - terraform state: present when: + - terraform_use_terraform|bool - not force_install_zip|bool - not force_install_if_present|bool - terraform_present.rc != 0 diff --git a/playbooks/roles/terraform/defaults/main.yml b/playbooks/roles/terraform/defaults/main.yml index 33bd00e6d..8ceb3d5c5 100644 --- a/playbooks/roles/terraform/defaults/main.yml +++ b/playbooks/roles/terraform/defaults/main.yml @@ -1,2 +1,4 @@ --- ssh_config_kexalgorithms: "" +# This will be set from extra_vars.yaml based on Kconfig selection +terraform_binary_path: "/usr/local/bin/terraform" diff --git a/playbooks/roles/terraform/tasks/main.yml b/playbooks/roles/terraform/tasks/main.yml index dabc9384e..271a56ef4 100644 --- a/playbooks/roles/terraform/tasks/main.yml +++ b/playbooks/roles/terraform/tasks/main.yml @@ -86,6 +86,7 @@ - name: Bring up terraform resources cloud.terraform.terraform: + binary_path: "{{ terraform_binary_path }}" force_init: true project_path: "{{ topdir_path }}/terraform/{{ kdevops_terraform_provider }}" state: present @@ -94,6 +95,7 @@ - name: Retrieve the controller_ip_map from terraform cloud.terraform.terraform_output: + binary_path: "{{ terraform_binary_path }}" format: json name: controller_ip_map project_path: "{{ topdir_path }}/terraform/{{ kdevops_terraform_provider }}" @@ -131,6 +133,7 @@ block: - name: Retrieve the controller_ip_map from terraform cloud.terraform.terraform_output: + binary_path: "{{ terraform_binary_path }}" format: json name: controller_ip_map project_path: "{{ topdir_path }}/terraform/{{ kdevops_terraform_provider }}" @@ -165,6 +168,7 @@ - name: Destroy terraform resources cloud.terraform.terraform: + binary_path: "{{ terraform_binary_path }}" force_init: true project_path: "{{ topdir_path }}/terraform/{{ kdevops_terraform_provider }}" state: absent diff --git a/terraform/Kconfig b/terraform/Kconfig index 62d138b62..dbb04ccf1 100644 --- a/terraform/Kconfig +++ b/terraform/Kconfig @@ -34,4 +34,37 @@ config TERRAFORM_PRIVATE_NET_MASK depends on TERRAFORM_PRIVATE_NET help Length of the network mask to use for the private network. + +choice + prompt "Infrastructure as Code tool" + default TERRAFORM_USE_TERRAFORM + help + Choose whether to use Terraform or OpenTofu for infrastructure + provisioning. OpenTofu is an open-source fork of Terraform that + maintains compatibility with Terraform configurations. + +config TERRAFORM_USE_TERRAFORM + bool "Use Terraform" + output yaml + help + Use HashiCorp Terraform for infrastructure provisioning. + Terraform is the original infrastructure as code tool. + +config TERRAFORM_USE_OPENTOFU + bool "Use OpenTofu" + output yaml + help + Use OpenTofu for infrastructure provisioning. OpenTofu is an + open-source fork of Terraform maintained by the Linux Foundation + that provides a community-driven alternative while maintaining + compatibility with Terraform configurations. + +endchoice + +config TERRAFORM_BINARY_PATH + string + default "/usr/local/bin/terraform" if TERRAFORM_USE_TERRAFORM + default "/usr/local/bin/tofu" if TERRAFORM_USE_OPENTOFU + output yaml + endif # TERRAFORM