Fix mclu spec builds.
[mclu.git] / mclu_build.py
1 #!/usr/bin/python
2 # mclu (mini cluster)
3 # Copyright (C) 2014 Red Hat Inc.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19 import argparse
20 import os
21 import re
22 import subprocess
23 import sys
24 import libvirt
25
26 import config
27 import lib
28
29 def cmdline (subparsers):
30     p = subparsers.add_parser (
31         'build',
32         help='build and run a new virtual machine',
33     )
34     p.add_argument (
35         '--memory', default=1024, type=int,
36         help='RAM to give to guest (default unit is megabytes)'
37     )
38     p.add_argument (
39         '--vcpus', default=4, type=int,
40         help='virtual CPUs to give to guest'
41     )
42     p.add_argument (
43         '--virtio', default=True,
44         help='use virtio disks and network'
45     )
46     p.add_argument (
47         '--size', required=True,
48         help='size of disk'
49     )
50     p.add_argument (
51         'name',
52         help='name of the new VM (or use "vm:name")'
53     )
54     p.add_argument (
55         'os_version',
56         help='OS & version of guest (see virt-builder docs)'
57     )
58     p.add_argument (
59         'vbargs', nargs='*',
60         help='virt-builder arguments (after "--")'
61     )
62     p.set_defaults (run=run)
63
64 def run (c, args, nodes):
65     # Did the user request a particular node?  If not, we'll run it
66     # on any node which is up.
67     m = re.match (r'^(.*):(.*)$', args.name)
68     if m:
69         node_name = m.group (1)
70         vm_name = m.group (2)
71         if node_name in nodes:
72             node = nodes[node_name]
73             if not node.ping ():
74                 sys.exit ("error: requested node (%s) is not up, use mclu wake %s" %
75                           (node_name, node_name))
76         else:
77             sys.exit ("error: requested node (%s) does not exist" % node_name)
78     else:
79         node = lib.pick_any_node_which_is_up (nodes)
80         vm_name = args.name
81
82     # Get all the guests, so we can tell if the name is a duplicate.
83     running, inactive = lib.get_all_guests (c, nodes.values ())
84
85     if vm_name in running or vm_name in inactive:
86         sys.exit ("error: node name (%s) already exists" % vm_name)
87
88     output = '%s/%s.img' % (c['images_dir'], vm_name)
89
90     # Call out to virt-builder to build the disk image.
91     vbargs = [
92         config.VIRT_BUILDER,
93         args.os_version,
94         '--output', output,
95         '--format', 'qcow2',
96     ]
97     if args.size:
98         vbargs.extend (['--size', args.size])
99     if args.vbargs:
100         vbargs.extend (args.vbargs)
101     subprocess.check_call (vbargs)
102
103     # XXX Unfortunately this is necessary so qemu can access the disk.
104     os.chmod (output, 0666)
105
106     # Generate the XML.  Would be nice to use virt-install here, but
107     # it doesn't work: RHBZ#1095789
108     network_model = "virtio"
109     if not args.virtio:
110         network_model = "e1000"
111
112     # XXX Quoting, and we should use a real XML generator.
113     xml = """
114 <domain type='kvm'>
115   <name>%s</name>
116   <memory unit='MiB'>%d</memory>
117   <currentMemory unit='MiB'>%d</currentMemory>
118   <vcpu>%d</vcpu>
119   <os>
120     <type>hvm</type>
121     <boot dev='hd'/>
122   </os>
123   <features>
124     <acpi/>
125     <apic/>
126     <pae/>
127   </features>
128   <cpu mode='host-model' fallback='allow' />
129   <clock offset='utc'>
130     <timer name='rtc' tickpolicy='catchup'/>
131     <timer name='pit' tickpolicy='delay'/>
132     <timer name='hpet' present='no'/>
133   </clock>
134   <on_poweroff>destroy</on_poweroff>
135   <on_reboot>restart</on_reboot>
136   <on_crash>restart</on_crash>
137   <devices>
138     <interface type='bridge'>
139       <source bridge='br0'/>
140       <model type='%s'/>
141     </interface>
142     <console type='pty'>
143       <target type='virtio' port='0'/>
144     </console>
145     <input type='tablet' bus='usb'/>
146     <input type='mouse' bus='ps2'/>
147     <!-- <input type='keyboard' bus='ps2'/> -->
148     <graphics type='vnc' autoport='yes'/>
149     <video>
150       <model type='cirrus' vram='9216' heads='1'/>
151     </video>
152 """ % (vm_name, args.memory, args.memory, args.vcpus, network_model)
153
154     # virtio-scsi or IDE disk:
155     if args.virtio:
156         xml += """
157     <controller type="scsi" index="0" model="virtio-scsi"/>
158     <disk type='file' device='disk'>
159       <driver name='qemu' type='qcow2' cache='none' io='native'/>
160       <source file='%s'/>
161       <target dev='sda' bus='scsi'/>
162     </disk>
163 """ % output
164     else:
165         xml += """
166     <disk type='file' device='disk'>
167       <driver name='qemu' type='qcow2' cache='none' io='native'/>
168       <source file='%s'/>
169       <target dev='sda' bus='ide'/>
170     </disk>
171 """ % output
172
173     xml += """
174   </devices>
175 </domain>
176 """
177
178     # Write the XML to the xmls_dir.
179     fp = open ("%s/%s.xml" % (c['xmls_dir'], vm_name), "w")
180     fp.write (xml)
181     fp.close ()
182
183     # Start the guest.
184     lib.start_guest (c, node, vm_name)