summaryrefslogtreecommitdiffstats
path: root/lib/configure-vm
blob: 5cb452187eaf7e2f888a99d6d214d55dc083b12d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highl
#!/usr/bin/env python

import argparse
import math
import os
import random

import libvirt

templatedir = os.getenv('LIB', '/var/opt/opnfv/lib') + '/installer/'

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('--direct-boot',
            help='Enable directboot to <value>.{vmlinux & initrd}')
    parser.add_argument('--kernel-arg', action="append", dest='kernel_args',
            help='Kernel arguments, use multiple time for multiple args.')
    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': '',
        'direct_boot': '',
        'kernel_args': '',
        'user_interface': '',
        }
    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>
        """
    if args.direct_boot:
        params['direct_boot'] = """
        <kernel>/var/lib/libvirt/images/%(direct_boot)s.vmlinuz</kernel>
        <initrd>/var/lib/libvirt/images/%(direct_boot)s.initrd</initrd>
        """ % { 'direct_boot': args.direct_boot }
    if args.kernel_args:
        params['kernel_args'] = """
        <cmdline>%s</cmdline>
        """ % ' '.join(args.kernel_args)

    if args.arch == 'aarch64':

        params['direct_boot'] += """
        <loader readonly='yes' type='pflash'>/usr/share/AAVMF/AAVMF_CODE.fd</loader>
        <nvram>/var/lib/libvirt/qemu/nvram/centos7.0_VARS.fd</nvram>
        """
        params['user_interface'] = """
        <controller type='virtio-serial' index='0'>
          <address type='virtio-mmio'/>
        </controller>
        <serial type='pty'>
          <target port='0'/>
        </serial>
        <console type='pty'>
          <target type='serial' port='0'/>
        </console>
        <channel type='unix'>
          <target type='virtio' name='org.qemu.guest_agent.0'/>
          <address type='virtio-serial' controller='0' bus='0' port='1'/>
        </channel>
        """
    else:
        params['user_interface'] = """
        <input type='mouse' bus='ps2'/>
        <graphics type='vnc' port='-1' autoport='yes'/>
        <video>
          <model type='cirrus' vram='9216' heads='1'/>
        </video>
        """


    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()