160 lines
5.8 KiB
Python
Executable File
160 lines
5.8 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import argparse
|
|
import math
|
|
import os.path
|
|
import random
|
|
|
|
import libvirt
|
|
|
|
templatedir = os.path.join(
|
|
os.path.dirname(
|
|
os.path.dirname(
|
|
os.path.abspath(__file__))), 'templates')
|
|
|
|
MAX_NUM_MACS = math.trunc(0xff/2)
|
|
|
|
|
|
def generate_baremetal_macs(count=1):
|
|
"""Generate an Ethernet MAC address suitable for baremetal testing."""
|
|
# NOTE(dprince): We generate our own bare metal MAC address's here
|
|
# instead of relying on libvirt so that we can ensure the
|
|
# locally administered bit is set low. (The libvirt default is
|
|
# to set the 2nd MSB high.) This effectively allows our
|
|
# fake baremetal VMs to more accurately behave like real hardware
|
|
# and fixes issues with bridge/DHCP configurations which rely
|
|
# on the fact that bridges assume the MAC address of the lowest
|
|
# attached NIC.
|
|
# MACs generated for a given machine will also be in sequential
|
|
# order, which matches how most BM machines are laid out as well.
|
|
# Additionally we increment each MAC by two places.
|
|
macs = []
|
|
|
|
if count > MAX_NUM_MACS:
|
|
raise ValueError("The MAX num of MACS supported is %i." % MAX_NUM_MACS)
|
|
|
|
base_nums = [0x00,
|
|
random.randint(0x00, 0xff),
|
|
random.randint(0x00, 0xff),
|
|
random.randint(0x00, 0xff),
|
|
random.randint(0x00, 0xff)]
|
|
base_mac = ':'.join(map(lambda x: "%02x" % x, base_nums))
|
|
|
|
start = random.randint(0x00, 0xff)
|
|
if (start + (count * 2)) > 0xff:
|
|
# leave room to generate macs in sequence
|
|
start = 0xff - count * 2
|
|
for num in range(0, count*2, 2):
|
|
mac = start + num
|
|
macs.append(base_mac + ":" + ("%02x" % mac))
|
|
return macs
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Configure a kvm virtual machine for the seed image.")
|
|
parser.add_argument('--name', default='seed',
|
|
help='the name to give the machine in libvirt.')
|
|
parser.add_argument('--image',
|
|
help='Use a custom image file (must be qcow2).')
|
|
parser.add_argument('--diskbus', default='sata',
|
|
help='Choose an alternate bus type for the disk')
|
|
parser.add_argument('--baremetal-interface', nargs='+', default=['brbm'],
|
|
help='The interface which bare metal nodes will be connected to.')
|
|
parser.add_argument('--engine', default='kvm',
|
|
help='The virtualization engine to use')
|
|
parser.add_argument('--arch', default='i686',
|
|
help='The architecture to use')
|
|
parser.add_argument('--memory', default='2097152',
|
|
help="Maximum memory for the VM in KB.")
|
|
parser.add_argument('--cpus', default='1',
|
|
help="CPU count for the VM.")
|
|
parser.add_argument('--bootdev', default='hd',
|
|
help="What boot device to use (hd/network).")
|
|
parser.add_argument('--seed', default=False, action='store_true',
|
|
help='Create a seed vm with two interfaces.')
|
|
parser.add_argument('--ovsbridge', default="",
|
|
help='Place the seed public interface on this ovs bridge.')
|
|
parser.add_argument('--libvirt-nic-driver', default='virtio',
|
|
help='The libvirt network driver to use')
|
|
parser.add_argument('--enable-serial-console', action="store_true",
|
|
help='Enable a serial console')
|
|
parser.add_argument('--uri', default='qemu:///system',
|
|
help='The server uri with which to connect.')
|
|
args = parser.parse_args()
|
|
with file(templatedir + '/domain.xml', 'rb') as f:
|
|
source_template = f.read()
|
|
imagefile = '/var/lib/libvirt/images/seed.qcow2'
|
|
if args.image:
|
|
imagefile = args.image
|
|
imagefile = os.path.realpath(imagefile)
|
|
params = {
|
|
'name': args.name,
|
|
'imagefile': imagefile,
|
|
'engine': args.engine,
|
|
'arch': args.arch,
|
|
'memory': args.memory,
|
|
'cpus': args.cpus,
|
|
'bootdev': args.bootdev,
|
|
'network': '',
|
|
'enable_serial_console': '',
|
|
}
|
|
if args.image is not None:
|
|
params['imagefile'] = args.image
|
|
|
|
# Configure the bus type for the target disk device
|
|
params['diskbus'] = args.diskbus
|
|
nicparams = {
|
|
'nicdriver': args.libvirt_nic_driver,
|
|
'ovsbridge': args.ovsbridge,
|
|
}
|
|
if args.seed:
|
|
if args.ovsbridge:
|
|
params['network'] = """
|
|
<interface type='bridge'>
|
|
<source bridge='%(ovsbridge)s'/>
|
|
<virtualport type='openvswitch'/>
|
|
<model type='%(nicdriver)s'/>
|
|
</interface>""" % nicparams
|
|
else:
|
|
params['network'] = """
|
|
<!-- regular natted network, for access to the vm -->
|
|
<interface type='network'>
|
|
<source network='default'/>
|
|
<model type='%(nicdriver)s'/>
|
|
</interface>""" % nicparams
|
|
|
|
macs = generate_baremetal_macs(len(args.baremetal_interface))
|
|
|
|
params['bm_network'] = ""
|
|
for bm_interface, mac in zip(args.baremetal_interface, macs):
|
|
bm_interface_params = {
|
|
'bminterface': bm_interface,
|
|
'bmmacaddress': mac,
|
|
'nicdriver': args.libvirt_nic_driver,
|
|
}
|
|
params['bm_network'] += """
|
|
<!-- bridged 'bare metal' network on %(bminterface)s -->
|
|
<interface type='network'>
|
|
<mac address='%(bmmacaddress)s'/>
|
|
<source network='%(bminterface)s'/>
|
|
<model type='%(nicdriver)s'/>
|
|
</interface>""" % bm_interface_params
|
|
|
|
if args.enable_serial_console:
|
|
params['enable_serial_console'] = """
|
|
<serial type='pty'>
|
|
<target port='0'/>
|
|
</serial>
|
|
<console type='pty'>
|
|
<target type='serial' port='0'/>
|
|
</console>
|
|
"""
|
|
|
|
libvirt_template = source_template % params
|
|
conn=libvirt.open(args.uri)
|
|
a = conn.defineXML(libvirt_template)
|
|
print ("Created machine %s with UUID %s" % (args.name, a.UUIDString()))
|
|
|
|
if __name__ == '__main__':
|
|
main()
|