Skip to content

Commit

Permalink
Add hypervisor deployment on baremetal using Kickstart and iDRAC boot
Browse files Browse the repository at this point in the history
  - Implemented Kickstart automation for hypervisor installation.
  - Configured iDRAC boot for baremetal provisioning.
  - Added necessary configurations and templates for network and disk settings.
  - Integrated automation for seamless OS installation with zero intervention.
  - Updated .gitignore file
  - Updated requirements.yml
  - Added ansible.cfg file
  • Loading branch information
kononovn committed Jan 9, 2025
1 parent 03e6028 commit 25d225e
Show file tree
Hide file tree
Showing 12 changed files with 538 additions and 1 deletion.
1 change: 1 addition & 0 deletions .ansible-lint
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ skip_list:
# Define paths or files to ignore
exclude_paths:
- "tests/dast"
- "collections"
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.idea
*host_vars*
*group_vars*
.vscode
inventory*
*__pycache__*
collections
6 changes: 6 additions & 0 deletions ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[defaults]
collections_path = ./collections
host_key_checking = False

[ssh_connection]
ssh_args = -o UserKnownHostsFile=/dev/null
7 changes: 7 additions & 0 deletions inventories/infra/deploy-bm-hypervisor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
executors:
hosts:
bastion:

hypervisors:
hosts:
hypervisor:
227 changes: 227 additions & 0 deletions playbooks/infra/deploy-bm-hypervisor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
---
- name: Create a Kickstart-enabled ISO
hosts: bastion
gather_facts: true
vars:
iso_mount_path: "{{ dest_iso_dir }}/mount"
os_install_path: "{{ dest_iso_dir }}/os-install"
location: rdu
system_iso_link: "{%- if location == 'rdu' -%} {{ system_iso_rdu_link }} {%- else -%} {{ system_iso_tlv_link }} {%- endif -%}"
tasks:
- name: Set ISO name
ansible.builtin.set_fact:
iso_name: installation.iso

- name: Prepare kickstart iso
ansible.builtin.import_role:
name: kickstart_iso
vars:
kickstart_iso_link: "{{ system_iso_link }}"
kickstart_iso_name: "{{ iso_name }}"
kickstart_iso_file_desire_location: /opt/http_store/data
kickstart_iso_timezone: "{{ hostvars['hypervisor'].timezone }}"
kickstart_iso_password: "{{ ansible_password }}"
kickstart_iso_username: "{{ ansible_user }}"
kickstart_iso_net_config:
interface_name: "{{ hostvars['hypervisor'].interface_name }}"
hostname: "{{ hostvars['hypervisor'].hostname }}"
ip: "{{ hostvars['hypervisor'].ip }}"
mask: "{{ hostvars['hypervisor'].mask }}"
gw: "{{ hostvars['hypervisor'].gw }}"
dns: "{{ hostvars['hypervisor'].dns }}"

- name: Set UP http storage
ansible.builtin.import_role:
name: redhatci.ocp.setup_http_store

- name: Deploy Bare-Metal
hosts: hypervisor
gather_facts: false
become: true
vars:
system_rpm_path: "/tmp/{{ system_rpm_link | basename }}"
tasks:
- name: Boot BM using pre-configured ISO
ansible.builtin.import_role:
name: redhatci.ocp.boot_iso
vars:
boot_iso_url: "http://{{ hostvars['bastion']['ansible_host'] }}/{{ hostvars['bastion']['iso_name'] }}"

- name: Wait until BM installation is completed
ansible.builtin.wait_for_connection:
delay: 360
sleep: 10
timeout: 7200
notify:
- Remove installation ISO

- name: Get system rpm from repository
ansible.builtin.get_url:
url: "{{ system_rpm_link }}"
dest: "{{ system_rpm_path }}"
force: false
mode: "0640"

- name: Install system rpm
ansible.builtin.dnf:
name: "{{ system_rpm_path }}"
state: present
disable_gpg_check: true

- name: Activate OS
ansible.builtin.command:
"{{ activate_system_cmd }}"
changed_when: false

- name: Set paswordless sudo
ansible.builtin.lineinfile:
path: /etc/sudoers.d/{{ ansible_user }}
line: "{{ ansible_user }} ALL=(ALL) NOPASSWD: ALL"
mode: "0640"
create: true

- name: Configure network connection baremetal
community.general.nmcli:
type: bridge
conn_name: bridge-baremetal
method4: manual
method6: disabled
state: present
stp: false
ifname: baremetal
autoconnect: true
ip4: "{{ hostvars[inventory_hostname]['ip'] }}/24"
gw4: "{{ hostvars[inventory_hostname]['gw'] }}"
dns4:
- "{{ hostvars[inventory_hostname]['dns'] }}"

- name: Set up network connection bridge-slave
community.general.nmcli:
type: ethernet
slave_type: bridge
ifname: "{{ hostvars[inventory_hostname]['interface_name'] }}"
master: baremetal
method4: disabled
conn_name: "{{ hostvars[inventory_hostname]['interface_name'] }}"
state: present
autoconnect: true

- name: Reload NetworkManager connections
ansible.builtin.shell: |
nmcli con down eno8303 && nmcli con up eno8303 && nmcli con up bridge-baremetal && nmcli con up eno8303
changed_when: true

- name: Gather facts
ansible.builtin.gather_facts:

- name: Configure secondary interface bridges
when: item.value.ifname in ansible_facts.interfaces
loop: "{{ seconday_networks | from_yaml | dict2items }}"
community.general.nmcli:
type: bridge
conn_name: "{{ item.key }}"
method4: manual
method6: disabled
state: present
stp: false
ifname: "{{ item.key }}"
autoconnect: true
ip4: "{{ item.value.ipv4 }}"

- name: Configure vlan interfaces
when: item.value.ifname in ansible_facts.interfaces
loop: "{{ seconday_networks | from_yaml | dict2items }}"
community.general.nmcli:
type: vlan
conn_name: "vlan{{ item.value.vlan }}"
state: present
ifname: "vlan{{ item.value.vlan }}"
autoconnect: true
slave_type: bridge
vlanid: "{{ item.value.vlan }}"
master: "{{ item.key }}"
vlandev: "{{ item.value.ifname }}"

- name: Install virtualization packages
ansible.builtin.dnf:
name:
- qemu-kvm
- libvirt
- virt-install
- virt-viewer
- libguestfs-tools-c
state: present

- name: Add the user to libvirt group
ansible.builtin.user:
name: "{{ ansible_user }}"
groups: libvirt
append: true

- name: Libvir insert lines for non-root user
ansible.builtin.blockinfile:
state: present
dest: /etc/libvirt/qemu.conf
block: |
user= "{{ ansible_user }}"
group= "{{ ansible_user }}"
- name: Create libvirt storage under user's directory
become: false
ansible.builtin.file:
path: "/home/{{ ansible_user }}/.libvirt/images"
recurse: true
mode: "0744"
state: directory

- name: Remove libvirt images directory
ansible.builtin.file:
path: /var/lib/libvirt/images
state: absent

- name: Create a symbolic link for libvirt default storage
ansible.builtin.file:
src: "/home/{{ ansible_user }}/.libvirt/images"
dest: /var/lib/libvirt/images
state: link

- name: Update all dependencies to the latest versions
ansible.builtin.package:
name: '*'
state: latest
update_cache: true
update_only: true

- name: Make sure a libvirtd service unit is running
ansible.builtin.systemd_service:
state: restarted
name: libvirtd
enabled: true

- name: Set up authorized_keys
become: false
ansible.builtin.lineinfile:
path: /home/{{ ansible_user }}/.ssh/authorized_keys
create: true
line: "{{ ssh_public_key }}"
mode: "0600"

- name: Setup RSA key
become: false
ansible.builtin.copy:
content: "{{ ansible_ssh_private_key }}"
dest: /home/{{ ansible_user }}/.ssh/id_rsa
mode: "0600"

- name: Setup RSA public key
become: false
ansible.builtin.copy:
content: "{{ ssh_public_key }}"
dest: /home/{{ ansible_user }}/.ssh/id_rsa.pub
mode: "0600"

handlers:
- name: Remove installation ISO
ansible.builtin.file:
path: /opt/http_store/data/{{ hostvars['bastion']['iso_name'] }}"
state: absent
89 changes: 89 additions & 0 deletions playbooks/infra/roles/kickstart_iso/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Ansible Role: `kickstart_iso`

## Disclaimer
This role is provided as-is, without any guarantees of support or maintenance.
The author or contributors are not responsible for any issues arising from the use of this role. Use it at your own discretion.

## Description
This Ansible role automates the creation of a bootable ISO image customized with a Kickstart file for automated installations. It performs the following tasks:
- Downloads an ISO file.
- Mounts the ISO and extracts its contents.
- Configures a Kickstart file for automated installation.
- Updates bootloader configurations to include the Kickstart installation option.
- Creates a new bootable ISO with the updated configurations.

## Requirements
- Ansible 2.9 or newer.
- Required packages installed on the control node:
- `rsync`
- `mkisofs`
- `sshpass`
- The target system must support ISO mounting and the necessary filesystem tools.


## Role Variables
The following variables can be configured please notice some of the variables are **required**:

| Variable Name | Default Value | Description|
|-------------------------------------|--------------------|------------|
|`kickstart_iso_file_desire_location` | | Target directory where the generated ISO file will be moved after creation. **Required**. Example: `/opt/http_store/data`|
|`kickstart_iso_timezone` | | Timezone to set in the Kickstart configuration file. **Required**. Example: `America/Toronto` |
|`kickstart_iso_password` | | Root password to set in the Kickstart configuration file. **Required**. |
|`kickstart_iso_username` | | Username to create in the Kickstart configuration file. **Required**. |
|`kickstart_iso_net_config` | | Network configuration for the target system in the Kickstart file. **Required**. See example below |
|`kickstart_iso_dest_dir` | `/tmp` | Directory to store the downloaded ISO and generated files. |
|`kickstart_iso_mount_path` | `/tmp/mount` | Directory where the ISO will be mounted. |
|`kickstart_iso_os_install_path` | `/tmp/os-install` | Working directory for extracted ISO contents. |
|`kickstart_iso_name` | `installation.iso` | Name of the final bootable ISO. |
|`kickstart_iso_link` | `https://download.fedoraproject.org/pub/fedora/linux/`<br>`releases/41/Workstation/x86_64/iso/`<br>`Fedora-Workstation-Live-x86_64-41-1.4.iso` | URL of the ISO image to download. |

```yaml
kickstart_iso_net_config:
interface_name: "eth0"
hostname: "myserver.local"
ip: "192.168.1.10"
mask: "255.255.255.0"
gw: "192.168.1.1"
dns: "8.8.8.8"
```
## Handlers
The role includes handlers to clean up temporary files and directories:
- Remove mount directory.
- Remove working directory.
- Remove installation ISO after use.
## Dependencies
This role does not depend on other roles but requires certain utilities to be installed on the target system.
## Example Playbook
Here’s an example of how to use this role in your playbook:
```yaml
---
- name: Create a Kickstart-enabled ISO
hosts: localhost
become: true
roles:
- role: kickstart_iso
vars:
kickstart_iso_name: "custom-fedora.iso"
kickstart_iso_link: "https://download.fedoraproject.org/pub/fedora/linux/releases/41/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-41-1.4.iso"
kickstart_iso_file_desire_location: "/home/user/iso"
kickstart_iso_timezone: "America/Toronto"
kickstart_iso_password: "your_password"
kickstart_iso_username: "your_user"
kickstart_iso_net_config:
interface_name: "eth0"
hostname: "myserver.local"
ip: "192.168.1.10"
mask: "255.255.255.0"
gw: "192.168.1.1"
dns: "8.8.8.8"
```
License
-------
Apache
7 changes: 7 additions & 0 deletions playbooks/infra/roles/kickstart_iso/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
# defaults file for kickstart_iso
kickstart_iso_dest_dir: "/tmp"
kickstart_iso_mount_path: "/tmp/mount"
kickstart_iso_os_install_path: "/tmp/os-install"
kickstart_iso_name: "installation.iso"
kickstart_iso_link: "https://download.fedoraproject.org/pub/fedora/linux/releases/41/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-41-1.4.iso"
25 changes: 25 additions & 0 deletions playbooks/infra/roles/kickstart_iso/handlers/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
# handlers file for kickstart_iso
- name: Remove mount directory {{ kickstart_iso_mount_path }}
become: true
ansible.builtin.file:
state: absent
path: "{{ kickstart_iso_mount_path }}"

- name: Remove working directory
become: true
ansible.builtin.file:
state: absent
path: "{{ kickstart_iso_os_install_path }}"

- name: Remove installation ISO from {{ kickstart_iso_dest_dir }}
become: true
ansible.builtin.file:
state: absent
path: "{{ kickstart_iso_dest_dir }}/{{ kickstart_iso_name }}"

- name: "Remove ISO from {{ kickstart_iso_dest_dir }}"
become: true
ansible.builtin.file:
state: absent
path: "{{ kickstart_iso_dest_dir }}/{{ kickstart_iso_link | basename }}"
Loading

0 comments on commit 25d225e

Please sign in to comment.