tools: add Dell iDRAC XML generator
This commit is contained in:
parent
3553166073
commit
e74727c5dd
5 changed files with 4144 additions and 0 deletions
48
scripts/drac-xml-writer/README.md
Normal file
48
scripts/drac-xml-writer/README.md
Normal file
|
@ -0,0 +1,48 @@
|
|||
This tool generates XML files to be uploaded to Dell iDRAC consoles
|
||||
|
||||
# Requirements
|
||||
|
||||
- `pandas` for the DHCP parser
|
||||
- `racadm` to talk to the Dells
|
||||
|
||||
# Usage
|
||||
|
||||
1. Put a list of IPs in `hostnames.csv` - 2 IPs are given as an example
|
||||
2. Run `dhcp_parser.py`
|
||||
1. This will reference the IPs and lookup the hostnames that match
|
||||
2. The output is written back to hostnames.csv
|
||||
3. (optional) Export a known-good XML from a DRAC host, and place it in drac-prod.xml.base
|
||||
1. **This is optional, the repo contains our current XML with the edits already done**
|
||||
2. e.g. `sudo racadm -r <ip> -u admin -p "supersecret" get -f ./drac-prod.xml.base -t xml --clone`
|
||||
3. Edit NIC.1#DNSRacName and replace the hostname with PLACEHOLDER, like this:
|
||||
- `<Attribute Name="NIC.1#DNSRacName">PLACEHOLDER</Attribute>`
|
||||
4. Edit the Users and comment out the passwords for the relevant users
|
||||
- `<!-- <Attribute Name="Users.2#Password"></Attribute> -->`
|
||||
4. Edit `xml_writer` to set the passwords used for the prod and stg environments (lines 47, 50, 56 & 59)
|
||||
4. Run `python xml_writer.py`
|
||||
|
||||
# Output
|
||||
|
||||
This will generate 2 directories and 4 scripts.
|
||||
|
||||
The directories are called `prod` and `stg` and contain the customised XML for
|
||||
each target host in the IP list.
|
||||
|
||||
The files are `prod.sh`, `stg.sh`, `prod_test.sh` and `stg_test.sh`. Run the
|
||||
test scripts first - these simply use `racadm` to test the user/password works
|
||||
for each host. `racadm` can be noisy, so run it like this:
|
||||
|
||||
```
|
||||
bash ./stg_test.sh 2>&1 |grep -E "(10.16|ERROR)"
|
||||
```
|
||||
|
||||
Obviously replace the 10.16 with the real IPs - you want to match all the
|
||||
hosts but not the random text `racadm` spews out
|
||||
|
||||
If any fail, check the access manually, and re-run until then work.
|
||||
|
||||
Then run the main script, eg `bash stg.sh` which will apply the custom XML from
|
||||
the directory to the each host in series.
|
||||
|
||||
|
||||
You can run the test script another time after to check access still works
|
52
scripts/drac-xml-writer/dhcp_parser.py
Executable file
52
scripts/drac-xml-writer/dhcp_parser.py
Executable file
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import re
|
||||
import pandas as pd
|
||||
|
||||
# File paths
|
||||
ips_csv = './hostnames.csv'
|
||||
dhcp_data = '/srv/web/infra/ansible/roles/dhcp_server/files/dhcpd.conf.noc01.iad2.fedoraproject.org'
|
||||
|
||||
# Read the CSV
|
||||
ips = pd.read_csv(ips_csv)
|
||||
|
||||
# Read the DHCP config file into a list of lines
|
||||
with open(dhcp_data, 'r', encoding='utf-8') as f:
|
||||
dhcp_lines = f.readlines()
|
||||
|
||||
def get_name(ip):
|
||||
# Search for the line containing the IP address
|
||||
for idx, line in enumerate(dhcp_lines):
|
||||
if ip in line:
|
||||
# Get the next line (like grep -A1)
|
||||
if idx + 1 < len(dhcp_lines):
|
||||
next_line = dhcp_lines[idx + 1]
|
||||
# Extract the hostname using the regex
|
||||
match = re.search(r'"(.*)\.mgmt', next_line)
|
||||
if match:
|
||||
return match.group(1)
|
||||
break
|
||||
return None # Return None if not found
|
||||
|
||||
def get_stg(ip):
|
||||
# Search for the line containing the IP address
|
||||
for idx, line in enumerate(dhcp_lines):
|
||||
if ip in line:
|
||||
# Get the next line (like grep -A1)
|
||||
if idx + 1 < len(dhcp_lines):
|
||||
next_line = dhcp_lines[idx + 1]
|
||||
# Extract the hostname using the regex
|
||||
match = re.search(r'stg', next_line)
|
||||
if match:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
break
|
||||
return None # Return None if not found
|
||||
|
||||
# Apply the function to each IP
|
||||
ips['name'] = ips['ip'].apply(get_name)
|
||||
ips['stg'] = ips['ip'].apply(get_stg)
|
||||
|
||||
# Write the updated DataFrame back to CSV
|
||||
ips.to_csv('./hostnames.csv', index=False)
|
3980
scripts/drac-xml-writer/drac-prod.xml.base
Normal file
3980
scripts/drac-xml-writer/drac-prod.xml.base
Normal file
File diff suppressed because it is too large
Load diff
3
scripts/drac-xml-writer/hostnames.csv
Normal file
3
scripts/drac-xml-writer/hostnames.csv
Normal file
|
@ -0,0 +1,3 @@
|
|||
ip,name,stg
|
||||
10.16.160.14
|
||||
10.16.160.33
|
|
61
scripts/drac-xml-writer/xml_writer.py
Executable file
61
scripts/drac-xml-writer/xml_writer.py
Executable file
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import csv
|
||||
|
||||
# Read the CSV file
|
||||
with open('./hostnames.csv', newline='') as csvfile:
|
||||
reader = csv.DictReader(csvfile)
|
||||
servers = list(reader)
|
||||
|
||||
stg_script = "stg.sh"
|
||||
if os.path.exists(stg_script):
|
||||
os.remove(stg_script)
|
||||
|
||||
stg_test_script = "stg_test.sh"
|
||||
if os.path.exists(stg_test_script):
|
||||
os.remove(stg_test_script)
|
||||
|
||||
prod_script = "prod.sh"
|
||||
if os.path.exists(prod_script):
|
||||
os.remove(prod_script)
|
||||
|
||||
prod_test_script = "prod_test.sh"
|
||||
if os.path.exists(prod_test_script):
|
||||
os.remove(prod_test_script)
|
||||
|
||||
user = 'root'
|
||||
|
||||
# Read the template XML as a string
|
||||
with open('./drac-prod.xml.base', 'r', encoding='utf-8') as f:
|
||||
template = f.read()
|
||||
|
||||
for server in servers:
|
||||
ip = server['ip']
|
||||
name = server['name']
|
||||
stg = server['stg']
|
||||
|
||||
# Replace the placeholder with the actual name
|
||||
xml_content = template.replace(
|
||||
'<Attribute Name="NIC.1#DNSRacName">PLACEHOLDER</Attribute>',
|
||||
f'<Attribute Name="NIC.1#DNSRacName">{name}</Attribute>'
|
||||
)
|
||||
# Write to a new XML file named after the IP
|
||||
if stg == "True":
|
||||
filename = f'stg/{ip}.xml'
|
||||
with open(stg_script, 'a', encoding='utf-8') as f:
|
||||
f.write(f"sudo racadm -r {ip} -u {user} -p 'stg-password' set -f ./stg/{ip}.xml -t xml -s Off\n")
|
||||
with open(stg_test_script, 'a', encoding='utf-8') as f:
|
||||
f.write(f"echo {ip}\n")
|
||||
f.write(f"sudo racadm -r {ip} -u {user} -p 'stg-password' getsvctag\n")
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
f.write(xml_content)
|
||||
else:
|
||||
filename = f'prod/{ip}.xml'
|
||||
with open(prod_script, 'a', encoding='utf-8') as f:
|
||||
f.write(f"sudo racadm -r {ip} -u {user} -p 'prod-password' set -f ./prod/{ip}.xml -t xml -s Off\n")
|
||||
with open(prod_test_script, 'a', encoding='utf-8') as f:
|
||||
f.write(f"echo {ip}\n")
|
||||
f.write(f"sudo racadm -r {ip} -u {user} -p 'prod-password' getsvctag\n")
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
f.write(xml_content)
|
Loading…
Add table
Add a link
Reference in a new issue