-
Notifications
You must be signed in to change notification settings - Fork 16
Add baremetal deploy via Ansible playbook #89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e1edbf3
251d127
3140888
1a1c5e3
10747b2
84ebb54
388f2fe
4f112de
9b6cefb
b895d7d
101f533
8d9c936
298336d
1053afe
368571b
dc00a3b
9f45936
0f098dc
62206c7
01da195
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,10 @@ | ||
| inventory.ini | ||
| inventory_baremetal.ini | ||
|
|
||
| proxy.env | ||
| kubeconfig | ||
| kubeadmin-password | ||
| clusters/ | ||
| *.pyc | ||
| *.pyo | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| --- | ||
| # Deploy a TNF fencing cluster on adopted baremetal nodes via dev-scripts ABI. | ||
| # | ||
| # Targets the [provisioning_host] group from inventory_baremetal.ini. | ||
| # Expects adoption artifacts from 'make baremetal-adopt' in | ||
| # roles/dev-scripts/install-dev/files/. | ||
| # | ||
| # Usage: | ||
| # ansible-playbook deploy-baremetal.yml -i inventory_baremetal.ini | ||
| # ansible-playbook deploy-baremetal.yml -i inventory_baremetal.ini -e dev_scripts_branch=my-branch | ||
| # | ||
| - hosts: provisioning_host | ||
| gather_facts: no | ||
| force_handlers: yes | ||
|
|
||
| vars: | ||
| method: agent | ||
| topology: fencing | ||
| test_cluster_name: ostest | ||
|
|
||
| pre_tasks: | ||
| - name: Check adoption artifacts exist on controller | ||
| ansible.builtin.stat: | ||
| path: "{{ playbook_dir }}/roles/dev-scripts/install-dev/files/{{ item }}" | ||
| delegate_to: localhost | ||
| become: false | ||
| register: artifact_check | ||
| loop: | ||
| - config_baremetal_fencing.sh | ||
| - ironic_nodes.json | ||
|
|
||
| - name: Fail if adoption artifacts are missing | ||
| ansible.builtin.fail: | ||
| msg: >- | ||
| Adoption artifact not found: {{ item.item }}. | ||
| Run 'make baremetal-adopt' first. | ||
| when: not item.stat.exists | ||
| loop: "{{ artifact_check.results }}" | ||
| loop_control: | ||
| label: "{{ item.item }}" | ||
|
|
||
| tasks: | ||
| # --- Validation, config deploy, pull-secret (reused from install-dev role) --- | ||
| - name: Validate and deploy config + pull-secret | ||
| ansible.builtin.include_role: | ||
| name: dev-scripts/install-dev | ||
| tasks_from: config | ||
| vars: | ||
| method: agent | ||
| config_file: | ||
| agent: config_baremetal_fencing.sh | ||
| install_host_deps: false | ||
|
|
||
| # --- Git checkout --- | ||
| - name: Checkout dev-scripts | ||
| ansible.builtin.git: | ||
| dest: "{{ dev_scripts_path }}" | ||
| repo: "{{ dev_scripts_src_repo }}" | ||
| version: "{{ dev_scripts_branch }}" | ||
|
|
||
| # --- Baremetal-specific setup --- | ||
| - name: Copy ironic_nodes.json to dev-scripts | ||
| ansible.builtin.copy: | ||
| src: "{{ playbook_dir }}/roles/dev-scripts/install-dev/files/ironic_nodes.json" | ||
| dest: "{{ dev_scripts_path }}/ironic_nodes.json" | ||
| mode: "0600" | ||
|
|
||
| - name: Create working directory | ||
| ansible.builtin.shell: mkdir -p "${HOME}/dev-scripts-workdir" | ||
| changed_when: false | ||
|
|
||
| - name: Append WORKING_DIR to deployed config | ||
| ansible.builtin.lineinfile: | ||
| path: "{{ dev_scripts_path }}/config_{{ whoami.stdout }}.sh" | ||
| regexp: '^export WORKING_DIR=' | ||
| line: 'export WORKING_DIR="${HOME}/dev-scripts-workdir"' | ||
|
|
||
| # --- Ensure SSH key exists for node access --- | ||
| - name: Check for existing SSH keypair | ||
| ansible.builtin.stat: | ||
| path: ~/.ssh/id_ed25519 | ||
| register: ssh_key_check | ||
|
|
||
| - name: Generate SSH keypair if missing | ||
| ansible.builtin.command: | ||
| cmd: ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N '' | ||
| when: not ssh_key_check.stat.exists | ||
|
|
||
| - name: Read SSH public key | ||
| ansible.builtin.slurp: | ||
| src: ~/.ssh/id_ed25519.pub | ||
| register: ssh_pub_key | ||
|
|
||
| - name: Append SSH_PUB_KEY to deployed config | ||
| ansible.builtin.lineinfile: | ||
| path: "{{ dev_scripts_path }}/config_{{ whoami.stdout }}.sh" | ||
| regexp: '^export SSH_PUB_KEY=' | ||
| line: 'export SSH_PUB_KEY="{{ ssh_pub_key.content | b64decode | trim }}"' | ||
|
|
||
| - name: Create empty mirror registry credentials | ||
| ansible.builtin.shell: | | ||
| f="${HOME}/private-mirror-{{ test_cluster_name }}.json" | ||
| [ -f "$f" ] || echo '{"auths":{}}' > "$f" | ||
| changed_when: false | ||
|
|
||
| # --- Clean prior deployment state --- | ||
| - name: Remove prior cluster state (required by dev-scripts verifyClean) | ||
| ansible.builtin.file: | ||
| path: "{{ dev_scripts_path }}/ocp/{{ test_cluster_name }}" | ||
| state: absent | ||
|
|
||
| # --- Deploy --- | ||
| - name: Run dev-scripts ABI pipeline | ||
| block: | ||
| - name: Run dev-scripts make target | ||
| make: | ||
| chdir: "{{ dev_scripts_path }}" | ||
| target: "{{ item }}" | ||
| loop: | ||
| - requirements | ||
| - agent_requirements | ||
| - agent_build_installer | ||
| - agent_prepare_release | ||
| - agent_configure | ||
| - agent_create_cluster | ||
| loop_control: | ||
| label: "{{ item }}" | ||
| rescue: | ||
| - name: Display recovery instructions | ||
| ansible.builtin.debug: | ||
| msg: | | ||
| DEPLOYMENT FAILED. To recover: | ||
| 1. Power off baremetal nodes via BMC | ||
| 2. Clean dev-scripts state: | ||
| make -C {{ dev_scripts_path }} clean | ||
| 3. Fix the issue and re-run: | ||
| make baremetal-fencing-agent | ||
| - name: Fail after displaying recovery steps | ||
| ansible.builtin.fail: | ||
| msg: "dev-scripts ABI pipeline failed" | ||
|
|
||
| # --- Post-deploy: proxy + credentials --- | ||
| - name: Setup proxy and fetch credentials | ||
| ansible.builtin.include_role: | ||
| name: proxy-setup | ||
| vars: | ||
| kubeconfig_path: "{{ dev_scripts_path }}/ocp/{{ test_cluster_name }}/auth/kubeconfig" | ||
| kubeadmin_password_path: "{{ dev_scripts_path }}/ocp/{{ test_cluster_name }}/auth/kubeadmin-password" | ||
|
|
||
| - name: Fetch SSH private key to controller | ||
| ansible.builtin.fetch: | ||
| src: ~/.ssh/id_ed25519 | ||
| dest: "clusters/{{ test_cluster_name }}/auth/id_ed25519" | ||
| flat: true | ||
| mode: "0600" | ||
|
|
||
| - name: Display access information | ||
| ansible.builtin.debug: | ||
| msg: |- | ||
| Baremetal TNF cluster deployed successfully! | ||
|
|
||
| Next steps: | ||
| 1. Source the proxy environment from anywhere: | ||
| source {{ playbook_dir }}/proxy.env | ||
| (or from openshift-clusters directory: source proxy.env) | ||
| 2. Verify cluster access: oc get nodes | ||
| 3. SSH to nodes: | ||
| ssh -i clusters/{{ test_cluster_name }}/auth/id_ed25519 core@<node-ip> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| # Baremetal node inventory for TNF adoption | ||
| # | ||
| # NOTE: This is separate from inventory.ini, which targets the hypervisor host. | ||
| # This file describes the physical baremetal nodes to be adopted as OpenShift nodes. | ||
| # inventory.ini → hypervisor (where dev-scripts runs) | ||
| # inventory_baremetal.ini → baremetal nodes (BMC endpoints for adoption) | ||
| # | ||
| # Copy this file to inventory_baremetal.ini and fill in your node details. | ||
| # Then run: make baremetal-adopt | ||
| # | ||
| # Each node requires: | ||
| # bmc_address - BMC/iDRAC/iLO management address (IP or hostname) | ||
| # bmc_user - BMC login username | ||
| # bmc_pass - BMC login password | ||
| # bmc_port - (optional) BMC Redfish port (default: 443) | ||
| # boot_mac - (optional) MAC address of the NIC used for PXE boot | ||
| # If omitted, the adopt script attempts Redfish discovery. | ||
| # node_ip - (optional) Static IP address for this node on the machine network | ||
| # Required for baremetal ABI deployments with static IPs. | ||
| # | ||
| # The hostname (first field) becomes the node name in ironic_nodes.json. | ||
| # For TNF, you need exactly 2 nodes (master-0 and master-1). | ||
|
|
||
| [baremetal_nodes] | ||
| master-0 bmc_address=192.168.1.100 bmc_user=admin bmc_pass=changeme boot_mac=52:54:00:00:00:01 node_ip=192.168.1.10 | ||
| master-1 bmc_address=192.168.1.101 bmc_user=admin bmc_pass=changeme boot_mac=52:54:00:00:00:02 node_ip=192.168.1.11 | ||
|
Comment on lines
+25
to
+26
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win Replace the sample
🤖 Prompt for AI AgentsSource: Coding guidelines |
||
|
|
||
| [baremetal_nodes:vars] | ||
| # BMC driver — only redfish is supported for TNF fencing | ||
| bmc_driver=redfish | ||
|
|
||
| # BMC Redfish port (per-node bmc_port overrides this) | ||
| bmc_port=443 | ||
|
|
||
| # Skip TLS verification for BMC endpoints (common with self-signed certs) | ||
| bmc_verify_ca=False | ||
|
|
||
| # Node CPU architecture | ||
| cpu_arch=x86_64 | ||
|
|
||
| [baremetal_network] | ||
| # Cluster-wide network config for baremetal ABI deployments (all optional). | ||
| # machine_network - Machine network CIDR (e.g. 192.168.1.0/24) | ||
| # gateway - Default gateway IP | ||
| # api_vip - API virtual IP | ||
| # ingress_vip - Ingress virtual IP | ||
| # dns_servers - Comma-separated DNS server IPs reachable from the nodes. | ||
| # Used as the node DNS resolver during install (resolves quay.io, etc.). | ||
| # If unset, falls back to gateway — which may not run DNS. | ||
| #machine_network=192.168.1.0/24 | ||
| #gateway=192.168.1.1 | ||
| #api_vip=192.168.1.100 | ||
| #ingress_vip=192.168.1.101 | ||
| #dns_servers=10.11.5.160,10.2.32.85 | ||
|
|
||
| [provisioning_host] | ||
| # Provisioning host for baremetal ABI deployment. Must be on the same L2 network | ||
| # as the baremetal nodes (serves agent ISO via HTTP, runs dnsmasq, acts as gateway). | ||
| # | ||
| # Standard Ansible inventory format — one host entry with connection variables. | ||
| # For local deployment, use: localhost ansible_connection=local | ||
| # | ||
| #10.1.155.50 ansible_user=root ansible_ssh_private_key_file=~/.ssh/lab_key | ||
|
|
||
| [provisioning_host:vars] | ||
| # Override dev-scripts checkout on the provisioning host (optional). | ||
| # Defaults come from roles/dev-scripts/install-dev/defaults/main.yml: | ||
| # dev_scripts_path=openshift-metal3/dev-scripts | ||
| # dev_scripts_src_repo=https://github.com/openshift-metal3/dev-scripts | ||
| # dev_scripts_branch=master | ||
| # | ||
| #dev_scripts_path=~/openshift-metal3/dev-scripts | ||
| #dev_scripts_src_repo=https://github.com/myuser/dev-scripts | ||
| #dev_scripts_branch=my-feature-branch | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -125,3 +125,4 @@ | |
| - containernetworking-plugins | ||
| state: present | ||
| become: true | ||
| when: install_host_deps | default(true) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Is community.general collection required for the ansible make module, or is it part of ansible.builtin?💡 Result:
The make module is part of the community.general collection, not ansible.builtin [1][2]. In modern Ansible (following the move to the collections-based architecture), you should reference it by its fully qualified collection name (FQCN): community.general.make [2]. While the module existed as a built-in module in older versions of Ansible (prior to the introduction of collections and the separation of modules into the community and core distributions) [3][4], it was migrated to the community.general collection as part of the project's modularization [2][5]. If you are using a modern version of Ansible, you must ensure the community.general collection is installed in your environment to use this module [2].
Citations:
🏁 Script executed:
Repository: openshift-eng/two-node-toolbox
Length of output: 6055
🏁 Script executed:
Repository: openshift-eng/two-node-toolbox
Length of output: 15874
🏁 Script executed:
Repository: openshift-eng/two-node-toolbox
Length of output: 917
🌐 Web query:
Ansible short module name resolution for collection modules: can community.general.make be used as make when the collection is installed but no collections: is declared?💡 Result:
No, you cannot use the short module name make to refer to the community.general.make module if the collections keyword is not declared in your playbook or role [1][2][3]. Ansible requires either the Fully Qualified Collection Name (FQCN), such as community.general.make, or the explicit use of the collections keyword to resolve short module names that are not part of the ansible.builtin collection [2][3]. The collections keyword creates an ordered search path that allows Ansible to resolve unqualified module names [2][3]. Without this declaration, or without explicitly using the FQCN, Ansible will attempt to find a module named make within the default search path (which includes ansible.builtin) and will fail if it cannot find it there [2][3]. The official documentation consistently recommends using the FQCN (community.general.make) to ensure clarity, avoid conflicts, and eliminate the need for the collections keyword [2][4][3].
Citations:
Use
community.general.makehere.makeis a collection module, and this play doesn’t declarecollections:, so the short name can fail to resolve; switch to the FQCN or addcommunity.generalto the play scope.🤖 Prompt for AI Agents