#!/usr/bin/env python # hardware-reinstall - Prepare a physical box in FI for re-install. # (c) 2012 Red Hat, Inc. # Ricky Elrod # GPLv2+ import os import sys import urllib import socket import subprocess import shlex import platform from optparse import OptionParser parser = OptionParser( description='Prepare a physical box in FI for re-install.') parser.add_option('-n', '--noop', action='store_true', help="Don't actually modify/download anything, just " "output stuff.") parser.add_option('-y', '--yes', action='store_true', default=False, dest="yes", help="Don't prompt to confirm, just do it.") parser.add_option('--ip', help="Override the IP of the box (passed to Grubby)") parser.add_option('--gw', help="Override the Gateway of the box (passed to Grubby)", dest='gateway') parser.add_option('--nm', help="Override the Netmask of the box (passed to Grubby)", dest='netmask') parser.add_option('--dns', help="Comma-delimited list of DNS resolvers (passed to " "Grubby)", dest='dns_resolvers') parser.add_option('--ks-file', help="Set the kickstart file to use (default:" "hardware-rhel-6-nohd)", default='hardware-rhel-6-nohd', dest='ks_file') (options, args) = parser.parse_args() if options.yes and options.noop: print "Don't ask AND don't do anything? Cmon" sys.exit(1) # 0. Get our hostname/primary ip # Get our primary IP by resolving our hostname. if options.ip: if not options.netmask: print 'You gave a custom IP and should specify a custom netmask too.' sys.exit(1) primary_ip = options.ip else: primary_ip = socket.gethostbyname(socket.gethostname()) # so - anaconda sometimes doesn't seem to listen to our dns # when fetching kickstarts, etc - so if we give the ip of the host # if we're in 10.5.X network (phx2) then things just work. if primary_ip.startswith('10.5.'): basehost = "http://10.5.126.23/" else: basehost = "http://infrastructure.fedoraproject.org/" arch = platform.machine() VMLINUZ_URL = '%srepo/rhel/RHEL6-%s/images/pxeboot/vmlinuz' % (basehost, arch) INITRD_URL = '%srepo/rhel/RHEL6-%s/images/pxeboot/initrd.img' % (basehost, arch) # 1. Grab initrd and vmlinuz and throw them in /boot # FIXME - more error catching here if not options.noop: print 'Fetching vmlinuz' urllib.urlretrieve(VMLINUZ_URL, "/boot/vmlinuz-install") print 'Fetching initrd' urllib.urlretrieve(INITRD_URL, "/boot/initrd-install.img") # 2. Find our network info. if options.netmask: primary_netmask = options.netmask # We still have to get the MAC address, of the primary NIC # even if we specify a custom IP/NM. cmd = subprocess.Popen('/sbin/ifconfig', stdout=subprocess.PIPE) stdout = cmd.communicate()[0] i = 0 lines = stdout.split("\n") for line in lines: if socket.gethostbyname(socket.gethostname()) in line: # Somewhere between EL6 and F17, ifconfig output has changed. # We accommodate for both. if ':' in line: # We are EL6 if not options.netmask: # inet addr:10.5.127.51 Bcast:10.5.127.255 Mask:255.255.255.0 primary_netmask = line.split('Mask:')[1] # On EL6 MAC addr is always one line before the IP address line primary_mac = lines[i - 1].split('HWaddr ')[1] else: # We are likely something newer if not options.netmask: # inet 10.10.10.113 netmask 255.255.255.0 broadcast # 10.10.10.255 # (cont. from above comment) primary_netmask = line.split('netmask ')[1].split(' ')[0] # On newer things, life gets harder. We have to continue # parsing lines until we get one with 'ether ' in it. # The range is the line we're on now -> the last line. for y in xrange(i, len(lines) - 1): if 'ether ' in lines[y]: primary_mac = lines[y].split('ether ')[1].split(' ')[0] break break i += 1 # Gateway if options.gateway: primary_gateway = options.gateway else: cmd = subprocess.Popen(['/sbin/ip', 'route'], stdout=subprocess.PIPE) stdout = cmd.communicate()[0] for line in stdout.split("\n"): if 'default' in line: # default via 10.10.10.1 dev wlan0 proto static primary_gateway = line.split('via ')[1].split(' ')[0] break # And DNS servers if options.dns_resolvers: dns_resolvers = options.dns_resolvers else: dns_servers = [] with open('/etc/resolv.conf', 'r') as f: for line in f.readlines(): if 'nameserver' in line: dns = line.split(' ') if len(dns) == 2: dns_servers.append(dns[1].strip()) dns_resolvers = ','.join(dns_servers) print '-' * 30 print 'Primary IP: ' + primary_ip print 'Primary Netmask: ' + primary_netmask print 'Primary Gateway: ' + primary_gateway print 'Primary MAC Address: ' + primary_mac print 'DNS Resolvers: ' + dns_resolvers print '-' * 30 # 3. Construct the grubby line. # grubby --add-kernel=/boot/vmlinuz-install \ # --args="ks=http://infrastructure.fedoraproject.org/\ # repo/rhel/ks/hardware-rhel-6-nohd \ # repo=http://infrastructure.fedoraproject.org/repo/rhel/RHEL6-x86_64/ \ # ksdevice=link ip=$IP gateway=$GATEWAY netmask=$NETMASK dns=$DNS" \ # --title="install el6" --initrd=/boot/initrd-install.img grubby_command = '/sbin/grubby --add-kernel=/boot/vmlinuz-install ' \ '--args="ks=%srepo/rhel/ks/%s ksdevice=%s ' \ 'ip=%s gateway=%s netmask=%s dns=%s repo=%srepo/rhel/RHEL6-x86_64/" ' \ '--title="install el6" --initrd=/boot/initrd-install.img' % (basehost, options.ks_file, primary_mac, primary_ip, primary_gateway, primary_netmask, dns_resolvers, basehost) print 'This grubby command seems like it will work:' print '-' * 30 print grubby_command print '-' * 30 print 'Check the command and be sure that it looks correct.' if not options.noop: if not options.yes: print 'Type yes to continue, anything else to abort.' print 'By continuing, I will run the above command.' if raw_input('> ') != 'yes': print 'Removing downloaded files.' os.unlink('/boot/vmlinuz-install') os.unlink('/boot/initrd-install.img') print 'Aborting.' sys.exit(1) cmd = subprocess.Popen(shlex.split(grubby_command), stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = cmd.communicate() if stdout: print stdout if stderr: print "[STDERR output]" print stderr if not options.yes: raw_input( 'Examine the above output, if it looks sane, press enter to ' 'continue.') print 'The next command I will run is:' print 'echo "savedefault --default=0 --once" | grub --batch' if not options.noop: cmd = subprocess.Popen(['/sbin/grub', '--batch'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout = cmd.communicate(input='savedefault --default=0 --once\n') print stdout[0] print 'Done.' print 'When you are ready, run: `shutdown -r now` to reboot.' print 'Go here:' print 'http://infrastructure.fedoraproject.org/infra/docs/kickstarts.txt' print 'And control-f for "Installation" (no quotes). Continue from there.' if options.noop: print '-' * 30 print 'Script was run in "no-op" mode - none of the above commands ' \ 'actually ran.' print '-' * 30