Passed
Push — master ( 42467a...9d011f )
by Matěj
03:19 queued 11s
created

tests.install_vm   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 206
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 156
dl 0
loc 206
rs 10
c 0
b 0
f 0
wmc 24

2 Functions

Rating   Name   Duplication   Size   Complexity  
B parse_args() 0 90 1
F main() 0 101 23
1
#!/usr/bin/env python2
2
3
import argparse
4
import os
5
import sys
6
import subprocess
7
8
9
def parse_args():
10
    parser = argparse.ArgumentParser()
11
12
    parser.add_argument(
13
        "--libvirt",
14
        dest="libvirt",
15
        default="qemu:///session",
16
        help="What hypervisor should be used when installing VM."
17
    )
18
    parser.add_argument(
19
        "--kickstart",
20
        dest="kickstart",
21
        default="kickstarts/test_suite.cfg",
22
        help="Path to a kickstart file for installation of a VM."
23
    )
24
    parser.add_argument(
25
        "--distro",
26
        dest="distro",
27
        required=True,
28
        choices=['fedora', 'rhel7', 'centos7', 'rhel8'],
29
        help="What distribution to install."
30
    )
31
    parser.add_argument(
32
        "--domain",
33
        dest="domain",
34
        required=True,
35
        help="What name should the new domain have."
36
    )
37
    parser.add_argument(
38
        "--disk-dir",
39
        dest="disk_dir",
40
        default=None,
41
        help="Location of the VM qcow2 file."
42
    )
43
    parser.add_argument(
44
        "--ram",
45
        dest="ram",
46
        default=2048,
47
        type=int,
48
        help="Amount of RAM configured for the VM."
49
    )
50
    parser.add_argument(
51
        "--cpu",
52
        dest="cpu",
53
        default=2,
54
        type=int,
55
        help="Number of CPU cores configured for the VM."
56
    )
57
    parser.add_argument(
58
        "--network",
59
        dest="network",
60
        help="Network type/spec, ie. bridge=br0 or network=name."
61
    )
62
    parser.add_argument(
63
        "--disk",
64
        dest="disk",
65
        help="Disk type/spec, ie. pool=MyPool,bus=sata,cache=unsafe."
66
    )
67
    parser.add_argument(
68
        "--url",
69
        dest="url",
70
        default=None,
71
        help="URL to an installation tree on a remote server."
72
    )
73
    parser.add_argument(
74
        "--extra-repo",
75
        dest="extra_repo",
76
        default=None,
77
        help="URL to an extra repository to be used during installation (e.g. AppStream)."
78
    )
79
    parser.add_argument(
80
        "--dry",
81
        dest="dry",
82
        action="store_true",
83
        help="Print command line instead of triggering command."
84
    )
85
    parser.add_argument(
86
        "--ssh-pubkey",
87
        dest="ssh_pubkey",
88
        default=None,
89
        help="Path to an SSH public key which will be used to access the VM."
90
    )
91
    parser.add_argument(
92
        "--uefi",
93
        dest="uefi",
94
        choices=['secureboot', 'normal'],
95
        help="Perform UEFI based installation, optionally with secure boot support."
96
    )
97
98
    return parser.parse_args()
99
100
101
def main():
102
    data = parse_args()
103
    username = ""
104
    try:
105
        username = os.environ["SUDO_USER"]
106
    except KeyError:
107
        pass
108
    home_dir = os.path.expanduser('~' + username)
109
110
    if not data.url:
111
        if data.distro == "fedora":
112
            data.url = "https://download.fedoraproject.org/pub/fedora/linux/releases/31/Everything/x86_64/os"
113
        elif data.distro == "centos7":
114
            data.url = "http://mirror.centos.org/centos/7/os/x86_64"
115
    if not data.url:
116
        sys.stderr.write("For the '{}' distro the `--url` option needs to be provided.\n".format(data.distro))
117
        return 1
118
119
    if not data.ssh_pubkey:
120
        data.ssh_pubkey = home_dir + "/.ssh/id_rsa.pub"
121
    if not os.path.isfile(data.ssh_pubkey):
122
        sys.stderr.write("Error: SSH public key not found at {0}\n".format(data.ssh_pubkey))
123
        sys.stderr.write("You can use the `--ssh-pubkey` to specify which key should be used.\n")
124
        return 1
125
    with open(data.ssh_pubkey) as f:
126
        pub_key = f.readline().rstrip()
127
    print("Using SSH public key from file: {0}".format(data.ssh_pubkey))
128
    print("Using hypervisor: {0}".format(data.libvirt))
129
130
    if data.disk:
131
        data.disk_spec = data.disk
132
    elif data.disk_dir:
133
        disk_path = os.path.join(data.disk_dir, data.domain) + ".qcow2"
134
        print("Location of VM disk: {0}".format(disk_path))
135
        data.disk_spec = "path={0},format=qcow2,size=20".format(disk_path)
136
    else:
137
        data.disk_spec = "size=20,format=qcow2"
138
139
    data.ks_basename = os.path.basename(data.kickstart)
140
141
    tmp_kickstart = "/tmp/" + data.ks_basename
142
    with open(data.kickstart) as infile, open(tmp_kickstart, "w") as outfile:
143
        content = infile.read()
144
        content = content.replace("&&HOST_PUBLIC_KEY&&", pub_key)
145
        if not data.distro == "fedora":
146
            content = content.replace("&&YUM_REPO_URL&&", data.url)
147
        if data.extra_repo:
148
            # extra repository
149
            repo_cmd = "repo --name=extra-repository --baseurl={}".format(data.extra_repo)
150
            content = content.replace("&&YUM_EXTRA_REPO&&", repo_cmd)
151
            content = content.replace("&&YUM_EXTRA_REPO_URL&&", data.extra_repo)
152
        else:
153
            content = content.replace("&&YUM_EXTRA_REPO&&", "")
154
        if data.uefi:
155
            content = content.replace(
156
                "part /boot --fstype=xfs --size=512",
157
                "part /boot --fstype=xfs --size=312\npart /boot/efi --fstype=efi --size=200"
158
            )
159
        outfile.write(content)
160
    data.kickstart = tmp_kickstart
161
    print("Using kickstart file: {0}".format(data.kickstart))
162
163
    if not data.network:
164
        if data.libvirt == "qemu:///system":
165
            data.network = "network=default"
166
        else:
167
            data.network = "bridge=virbr0"
168
169
    # The kernel option 'net.ifnames=0' is used to disable predictable network
170
    # interface names, for more details see:
171
    # https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/
172
    command = 'virt-install --connect={libvirt} --name={domain} --memory={ram} --vcpus={cpu} --network {network} --disk {disk_spec} --initrd-inject={kickstart} --extra-args="inst.ks=file:/{ks_basename} ksdevice=eth0 net.ifnames=0 console=ttyS0,115200" --serial pty --graphics=none --noautoconsole --rng /dev/random --wait=-1 --location={url}'.format(**data.__dict__)
173
    if data.uefi == "normal":
174
        command = command+" --boot uefi"
175
    if data.uefi == "secureboot":
176
        command = command + " --boot uefi,loader_secure=yes,\
177
loader=/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd,\
178
nvram_template=/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd --features smm=on"
179
180
    if data.dry:
181
        print("\nThe following command would be used for the VM installation:")
182
        print(command)
183
    else:
184
        os.system(command)
185
186
    print("\nTo determine the IP address of the {0} VM use:".format(data.domain))
187
    if data.libvirt == "qemu:///system":
188
        print("  sudo virsh domifaddr {0}\n".format(data.domain))
189
    else:
190
        # command evaluation in fish shell is simply surrounded by
191
        # parenthesis for example: (echo foo). In other shells you
192
        # need to prepend the $ symbol as: $(echo foo)
193
        from os import environ
194
        print("  arp -n | grep {0}(virsh -q domiflist {1} | awk '{{print $5}}')\n".format('' if 'fish' == environ['SHELL'][-4:] else '$', data.domain))
195
196
    print("To connect to the {0} VM use:\n  ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@IP\n".format(data.domain))
197
    print("To connect to the VM serial console, use:\n  virsh console {0}\n".format(data.domain))
198
    print("If you have used the `--ssh-pubkey` also add '-o IdentityFile=PATH_TO_PRIVATE_KEY' option to your ssh command and export the SSH_ADDITIONAL_OPTIONS='-o IdentityFile=PATH_TO_PRIVATE_KEY' before running the SSG Test Suite.")
199
200
    if data.libvirt == "qemu:///system":
201
        print("\nIMPORTANT: When running SSG Test Suite use `sudo -E` to make sure that your SSH key is used.")
202
203
204
if __name__ == '__main__':
205
    main()
206