Skip to content

Commit 0a551a8

Browse files
clobranofonta-rh
andauthored
feat: Add resource-agents-patch.sh script (#9)
* feat: Add resource-agents-patch.sh script This commit introduces the resource-agents-patch.sh script. This script installs an RPM package on all OpenShift cluster nodes using rpm-ostree. It performs the following actions: - Checks for required tools (oc and jq). - Verifies that the user is logged into an OpenShift cluster. - Discovers the IPs of all nodes in the cluster. - Copies the RPM to each node. - Installs the RPM using rpm-ostree. - Provides instructions for rebooting the nodes. This script simplifies the process of patching resource agents on OpenShift clusters. * Add Ansible playbook to install resource agents RPM This change adds an alternative method to update the resource agents on the target node installing the RPM via playbook. usage: $ ansible-playbook -i inventory.ini \ resource-agents-patch.yml \ -e "rpm_full_path=/path/to/rpm" cat inventory.ini [all] node1 ansible_host=192.168.111.20 node2 ansible_host=192.168.111.21 * Added README * Added inventory sample, updated README to clarify --------- Co-authored-by: Pablo Fontanilla <pfontani@redhat.com>
1 parent 25eb62e commit 0a551a8

4 files changed

Lines changed: 186 additions & 0 deletions

File tree

helpers/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Helpers
2+
3+
Utilities for installing RPM packages on OpenShift cluster nodes using rpm-ostree.
4+
5+
## Description
6+
7+
This directory contains scripts and playbooks for patching OpenShift cluster nodes with RPM packages, specifically designed for resource agent updates. The tools use rpm-ostree's override functionality to replace packages on immutable CoreOS nodes.
8+
9+
## Requirements
10+
11+
### For resource-agents-patch.sh
12+
- `oc` CLI tool (logged into OpenShift cluster)
13+
- `jq` for JSON processing
14+
- SSH access to cluster nodes
15+
16+
### For resource-agents-patch.yml
17+
- Ansible
18+
- Inventory file containing OpenShift cluster nodes (separate from hypervisor deployment inventory, see `inventory_ocp_hosts.sample`)
19+
- SSH access configured for `core` user
20+
21+
## Usage
22+
23+
### Shell Script
24+
25+
```bash
26+
./resource-agents-patch.sh /path/to/package.rpm
27+
```
28+
29+
**Process:**
30+
1. Validates required tools and RPM file
31+
2. Discovers all node IPs via OpenShift API
32+
3. Copies RPM to each node using SCP
33+
4. Installs package with `rpm-ostree override replace`
34+
5. Provides manual reboot commands
35+
36+
### Ansible Playbook
37+
38+
```bash
39+
ansible-playbook -i inventory_ocp_hosts resource-agents-patch.yml -e rpm_full_path=/path/to/package.rpm
40+
```
41+
42+
**Note**: The inventory file should list the OpenShift cluster nodes (VMs), not the hypervisor host. Copy `inventory_ocp_hosts.sample` to `inventory_ocp_hosts` and update with your cluster node IPs.
43+
44+
**Process:**
45+
1. Validates RPM file existence
46+
2. Copies RPM to all nodes
47+
3. Installs using rpm-ostree override
48+
4. Reboots nodes one at a time
49+
5. Verifies etcd health after reboot
50+
51+
## Notes
52+
53+
- Both tools use `rpm-ostree override replace` which is appropriate for updating existing packages
54+
- Node reboots are required to activate rpm-ostree changes
55+
- The Ansible playbook handles rebooting automatically; the shell script requires manual intervention
56+
- Plan reboots carefully to maintain cluster availability
57+
- Monitor cluster health during the patching process

helpers/inventory_ocp_hosts.sample

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[cluster_nodes]
2+
core@10.0.0.10 ansible_ssh_extra_args='-o ServerAliveInterval=30 -o ServerAliveCountMax=120'
3+
core@10.0.0.11 ansible_ssh_extra_args='-o ServerAliveInterval=30 -o ServerAliveCountMax=120'
4+
core@10.0.0.12 ansible_ssh_extra_args='-o ServerAliveInterval=30 -o ServerAliveCountMax=120'

helpers/resource-agents-patch.sh

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/usr/bin/env bash
2+
# -*- coding: UTF-8 -*-
3+
set -o errexit
4+
set -o pipefail
5+
set -o nounset
6+
7+
# Check if required tools are available
8+
command -v oc >/dev/null 2>&1 || { echo "Error: 'oc' command not found. Please ensure you're logged into an OpenShift cluster." >&2; exit 1; }
9+
command -v jq >/dev/null 2>&1 || { echo "Error: 'jq' command not found. Please install jq." >&2; exit 1; }
10+
11+
RPM_FULL_PATH="$1"
12+
PACKAGE=$(basename "$RPM_FULL_PATH")
13+
14+
# Function to show usage
15+
usage() {
16+
echo "Usage: $0 <rpm-file-path>"
17+
echo -e "\nThis script installs an RPM package on all OpenShift cluster nodes using rpm-ostree.\n"
18+
echo "Arguments:"
19+
echo -e " rpm-file-path Path to the RPM file to install\n"
20+
echo "Example:"
21+
echo " $0 /path/to/package.rpm"
22+
exit 1
23+
}
24+
25+
# Check arguments
26+
if [[ $# -ne 1 ]]; then
27+
usage
28+
fi
29+
30+
if [[ ! -f "$RPM_FULL_PATH" ]]; then
31+
echo "Error: RPM file '$RPM_FULL_PATH' not found." >&2
32+
exit 1
33+
fi
34+
35+
# Get the list of all node IPs
36+
echo "Discovering OpenShift cluster nodes..."
37+
mapfile -t NODE_IPS< <(oc get nodes -o json | jq -r '.items[].status.addresses[0].address')
38+
39+
if [[ ${#NODE_IPS[@]} -eq 0 ]]; then
40+
echo "Error: No nodes found in the cluster." >&2
41+
echo "Make sure you're connected to an OpenShift cluster." >&2
42+
exit 1
43+
fi
44+
45+
echo "Found ${#NODE_IPS[@]} node(s):"
46+
for ip in "${NODE_IPS[@]}"; do
47+
echo " - $ip"
48+
done
49+
50+
echo -e "\nInstalling RPM package '$PACKAGE' on ${#NODE_IPS[@]} node(s)...\n"
51+
52+
set -x
53+
for IP in "${NODE_IPS[@]}"; do
54+
echo "Processing node: $IP"
55+
scp "$RPM_FULL_PATH" "core@$IP":/var/home/core
56+
ssh -t "core@$IP" -- sudo rpm-ostree -C override replace /var/home/core/"$PACKAGE"
57+
sleep 2
58+
done
59+
60+
echo -e "\nRPM installation completed on all nodes."
61+
echo -e "\nIMPORTANT: The nodes need to be rebooted to apply the rpm-ostree changes."
62+
echo "Plan the reboots carefully to maintain cluster availability:"
63+
echo "- Consider rebooting nodes one at a time"
64+
echo "- Wait for each node to become Ready before rebooting the next"
65+
echo "- Monitor cluster health during the process"
66+
echo -e "\nReboot commands (run manually when ready):"
67+
for IP in "${NODE_IPS[@]}"; do
68+
echo " ssh core@$IP sudo systemctl reboot"
69+
done
70+

helpers/resource-agents-patch.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
- name: Install RPM package on OpenShift nodes using rpm-ostree
3+
hosts: all
4+
become: true
5+
remote_user: core
6+
tasks:
7+
- name: Store RPM full path in a registry
8+
stat:
9+
path: "{{ rpm_full_path }}"
10+
register: rpm_file
11+
delegate_to: localhost
12+
run_once: true
13+
14+
- name: Fail if RPM file does not exist
15+
fail:
16+
msg: "RPM file '{{ rpm_full_path }}' not found."
17+
when: not rpm_file.stat.exists
18+
19+
- name: Copy RPM file to nodes
20+
copy:
21+
src: "{{ rpm_full_path }}"
22+
dest: /var/home/core/
23+
owner: core
24+
group: core
25+
register: copy_result
26+
27+
- name: Install RPM package using rpm-ostree
28+
command: rpm-ostree -C override replace /var/home/core/{{ rpm_package }}
29+
register: rpm_ostree_result
30+
async: 600 # 10 minutes timeout
31+
poll: 30 # check every 30 seconds
32+
33+
- name: Display rpm-ostree command output
34+
debug:
35+
msg: |
36+
Command: {{ rpm_ostree_result.cmd }}
37+
Return code: {{ rpm_ostree_result.rc }}
38+
STDOUT: {{ rpm_ostree_result.stdout }}
39+
STDERR: {{ rpm_ostree_result.stderr }}
40+
when: rpm_ostree_result is defined
41+
42+
- name: Reboot nodes to apply changes
43+
reboot:
44+
msg: "Rebooting node to apply rpm-ostree changes"
45+
connect_timeout: 5
46+
reboot_timeout: 600 # Extended timeout for ostree boot
47+
pre_reboot_delay: 10
48+
post_reboot_delay: 60 # Wait longer after reboot
49+
test_command: podman exec etcd etcdctl member list
50+
throttle: 1 # Reboot one node at a time
51+
52+
vars:
53+
rpm_full_path: "{{ rpm_full_path | default(lookup('env', 'RPM_FULL_PATH')) }}"
54+
rpm_package: "{{ rpm_full_path | basename }}"
55+

0 commit comments

Comments
 (0)