c7testvm: Script to create a CentOS 7 test VM
This script creates a new virtual machine using `virt-install`. It then starts an HTTP server to serve a kickstart configuration file to the new VM, which is used to automatically install CentOS.master
parent
1f2d490e44
commit
0f8df4ce89
|
@ -0,0 +1,226 @@
|
|||
#!/usr/bin/env python
|
||||
import argparse
|
||||
import binascii
|
||||
import http.server
|
||||
import os
|
||||
import random
|
||||
import socket
|
||||
import string
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
|
||||
HTTP_PROXY = 'caithe.pyrocufflink.jazz:3128'
|
||||
PORT_RANGE = (10000, 65535)
|
||||
REPO_URL = 'http://mirror.centos.org/centos/7/os/x86_64'
|
||||
|
||||
|
||||
KICKSTART = string.Template('''\
|
||||
text
|
||||
install
|
||||
url --url=http://mirror.centos.org/centos/7/os/x86_64
|
||||
repo --name=updates --baseurl=http://mirror.centos.org/centos/7/updates/x86_64
|
||||
repo --name=extras --baseurl=http://mirror.centos.org/centos/7/extras/x86_64
|
||||
lang en_US.UTF-8
|
||||
keyboard us
|
||||
timezone --utc UTC
|
||||
rootpw --iscrypted x
|
||||
shutdown
|
||||
|
||||
bootloader --location=mbr
|
||||
clearpart --all --initlabel
|
||||
autopart --type=lvm
|
||||
|
||||
network --hostname=${hostname}
|
||||
|
||||
%packages --nocore
|
||||
@core --nodefaults
|
||||
-biosdevname
|
||||
-btrfs-progs
|
||||
-firewalld
|
||||
-iprutils
|
||||
-irqbalance
|
||||
-kexec-tools
|
||||
-man-db
|
||||
-parted
|
||||
-plymouth
|
||||
-teamd
|
||||
-tuned
|
||||
avahi
|
||||
qemu-guest-agent
|
||||
%end
|
||||
|
||||
%addon com_redhat_kdump --disable
|
||||
%end
|
||||
|
||||
%post
|
||||
install -d /root/.ssh
|
||||
cat > /root/.ssh/authorized_keys <<EOF
|
||||
${ssh_pubkey}
|
||||
EOF
|
||||
sed 's/use-ipv6=.*/use-ipv6=yes/' /etc/avahi/avahi-daemon.conf
|
||||
%end
|
||||
''')
|
||||
|
||||
|
||||
class KickstartHTTPServer(http.server.HTTPServer):
|
||||
|
||||
address_family = socket.AF_INET6
|
||||
|
||||
def __init__(self, kickstart):
|
||||
port = random.randint(*PORT_RANGE)
|
||||
super(KickstartHTTPServer, self).__init__(
|
||||
server_address=('::', port),
|
||||
RequestHandlerClass=KickstartHTTPRequestHandler,
|
||||
)
|
||||
self.kickstart = kickstart
|
||||
|
||||
|
||||
class KickstartHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
|
||||
|
||||
def do_GET(self):
|
||||
self.do_HEAD()
|
||||
self.wfile.write(self.server.kickstart)
|
||||
|
||||
def do_HEAD(self):
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'text/plain; charset=utf-8')
|
||||
self.send_header('Content-Length', str(len(self.server.kickstart)))
|
||||
self.end_headers()
|
||||
|
||||
|
||||
def get_server_name():
|
||||
tries = [
|
||||
(socket.AF_INET6, '2001:db8::1'),
|
||||
(socket.AF_INET, '203.0.113.1'),
|
||||
]
|
||||
addr = None
|
||||
for af, remote in tries:
|
||||
s = socket.socket(af, socket.SOCK_DGRAM)
|
||||
try:
|
||||
s.connect((remote, 0))
|
||||
addr = s.getsockname()[0]
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
s.close()
|
||||
if addr is None:
|
||||
try:
|
||||
addr = socket.gethostbyname(socket.gethostname())
|
||||
except:
|
||||
return socket.gethostname()
|
||||
try:
|
||||
return socket.gethostbyaddr(addr)[0]
|
||||
except:
|
||||
return addr
|
||||
|
||||
|
||||
def get_ssh_pubkey():
|
||||
dirname = os.path.expanduser('~/.ssh')
|
||||
for t in ('ed25519', 'rsa', 'ecdsa'):
|
||||
try:
|
||||
with open(os.path.join(dirname, 'id_{}.pub'.format(t))) as f:
|
||||
return f.read()
|
||||
except OSError:
|
||||
continue
|
||||
return ''
|
||||
|
||||
|
||||
def virt_install(args):
|
||||
yield 'virt-install'
|
||||
for key, value in args.items():
|
||||
yield '--{}'.format(key)
|
||||
if value is not None:
|
||||
yield str(value)
|
||||
|
||||
|
||||
def wait_for_host(host, port, timeout=300):
|
||||
deadline = time.time() + timeout
|
||||
while time.time() < deadline:
|
||||
try:
|
||||
sock = socket.create_connection((host, port))
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
sock.close()
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--ram', type=int, default=1024)
|
||||
parser.add_argument('--vcpus', type=int, default=2)
|
||||
parser.add_argument('--cpu', default='host')
|
||||
parser.add_argument('--location', default=REPO_URL)
|
||||
parser.add_argument('--disk-pool', default='default')
|
||||
parser.add_argument('--disk-size', type=int, default=6)
|
||||
parser.add_argument('--network', default='bridge=br0')
|
||||
parser.add_argument('--sound', default='none')
|
||||
parser.add_argument('--server-name')
|
||||
parser.add_argument('--ip', default='dhcp')
|
||||
parser.add_argument('--ssh-key')
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
name = 'C7-{}'.format(binascii.hexlify(os.urandom(3)).decode())
|
||||
hostname = '{}.local'.format(name.lower())
|
||||
|
||||
if args.ssh_key is None:
|
||||
ssh_pubkey = get_ssh_pubkey()
|
||||
else:
|
||||
ssh_pubkey = args.ssh_key
|
||||
|
||||
kickstart = KICKSTART.substitute(
|
||||
hostname=hostname,
|
||||
ssh_pubkey=ssh_pubkey,
|
||||
)
|
||||
|
||||
httpd = KickstartHTTPServer(kickstart.encode('utf-8'))
|
||||
|
||||
kcmdline = 'ip={ip} proxy={proxy} ks=http://{server}:{port}/'.format(
|
||||
ip=args.ip,
|
||||
proxy=HTTP_PROXY,
|
||||
server=args.server_name or get_server_name(),
|
||||
port=httpd.server_port,
|
||||
)
|
||||
|
||||
cmd = list(virt_install({
|
||||
'name': name,
|
||||
'ram': args.ram,
|
||||
'vcpus': args.vcpus,
|
||||
'cpu': args.cpu,
|
||||
'location': args.location,
|
||||
'extra-args': kcmdline,
|
||||
'os-type': 'linux',
|
||||
'os-variant': 'rhel7',
|
||||
'disk': 'pool={pool},size={size}'.format(
|
||||
pool=args.disk_pool,
|
||||
size=args.disk_size,
|
||||
),
|
||||
'network': args.network,
|
||||
'sound': args.sound,
|
||||
'redirdev': 'none',
|
||||
'noautoconsole': None,
|
||||
'wait': -1,
|
||||
}))
|
||||
env = os.environ.copy()
|
||||
env['http_proxy'] = HTTP_PROXY
|
||||
p = subprocess.Popen(cmd, env=env)
|
||||
httpd.handle_request()
|
||||
httpd.server_close()
|
||||
p.wait()
|
||||
print('Waiting for host to come up...')
|
||||
if wait_for_host(hostname, 22):
|
||||
os.execlp('ssh', 'ssh', '-oStrictHostKeyChecking=no',
|
||||
'root@{}'.format(hostname))
|
||||
else:
|
||||
sys.stderr.write('Timed out waiting for {}\n'.format(hostname))
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue