Merge lp:~flacoste/maas/vdenv-cleanup into lp:~maas-committers/maas/trunk

Proposed by Francis J. Lacoste
Status: Merged
Approved by: Francis J. Lacoste
Approved revision: no longer in the source branch.
Merged at revision: 247
Proposed branch: lp:~flacoste/maas/vdenv-cleanup
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 1111 lines (+1024/-0)
16 files modified
MANIFEST.in (+1/-0)
vdenv/HOWTO (+48/-0)
vdenv/HOWTO.juju (+68/-0)
vdenv/README.txt (+5/-0)
vdenv/TODO (+14/-0)
vdenv/api-list.py (+47/-0)
vdenv/bin/authorize-ssh (+46/-0)
vdenv/bin/start-odev (+33/-0)
vdenv/bin/system-setup (+52/-0)
vdenv/bin/virsh-listener (+34/-0)
vdenv/libvirt-domain.tmpl (+56/-0)
vdenv/libvirt-network.tmpl (+23/-0)
vdenv/settings.cfg (+24/-0)
vdenv/setup.py (+226/-0)
vdenv/zimmer-build/build (+277/-0)
vdenv/zimmer-build/ud-build.txt (+70/-0)
To merge this branch: bzr merge lp:~flacoste/maas/vdenv-cleanup
Reviewer Review Type Date Requested Status
Francis J. Lacoste (community) Approve
Review via email: mp+96831@code.launchpad.net

Commit message

Tab nanny the files in vdenv and added copyright headers and other boilerplate from our standard templates.

Description of the change

Tab nanny the files in vdenv and added copyright headers and other boilerplate from our standard templates.

To post a comment you must log in.
Revision history for this message
Francis J. Lacoste (flacoste) wrote :

Self-reviewing.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'MANIFEST.in'
2--- MANIFEST.in 2012-01-23 21:16:00 +0000
3+++ MANIFEST.in 2012-03-09 21:00:25 +0000
4@@ -1,5 +1,6 @@
5 graft src/*/static
6 graft src/*/templates
7+graft vdenv
8 prune src/*/testing
9 prune src/*/tests
10 prune src/maastesting
11
12=== added directory 'vdenv'
13=== added file 'vdenv/HOWTO'
14--- vdenv/HOWTO 1970-01-01 00:00:00 +0000
15+++ vdenv/HOWTO 2012-03-09 21:00:25 +0000
16@@ -0,0 +1,48 @@
17+#!/usr/bin/env bash
18+# Copyright 2012 Canonical Ltd. This software is licensed under the
19+# GNU Affero General Public License version 3 (see the file LICENSE).
20+#
21+# This file documents how to get odev running on your system. But it's also
22+# a script; you may find that you can just run it and get a working setup.
23+
24+# Exit immediately if a command exits with a non-zero status.
25+set -o errexit
26+# Treat unset variables as an error when substituting.
27+set -o nounset
28+
29+## System-level setup. This needs to be done only once.
30+./bin/system-setup
31+
32+## Build a zimmer image in this branch.
33+pushd zimmer-build
34+./build zimmer-disk0.img --import-keys=auto
35+popd
36+
37+## Get zimmer and cobbler running.
38+./bin/start-odev
39+
40+cobblerlogin=ubuntu@192.168.123.2
41+cat <<EOF
42+While we're waiting for the server to come up, let's set up ssh login to
43+the cobbler server at $cobblerlogin.
44+
45+Please enter your Launchpad login name to import your ssh keys from Launchpad,
46+or an asterisk ("*") to import your local public ssh keys. Enter nothing to
47+skip this step.
48+
49+(If the server prompts you for a password, the default is "passw0rd")
50+EOF
51+read keyowner
52+./bin/authorize-ssh $cobblerlogin $keyowner
53+
54+## populate the nodes into the cobbler server
55+./setup.py cobbler-setup
56+
57+## Listen for libvirt requests from the Cobbler server.
58+VIRSH_LISTENER_DEBUG=1 ./bin/virsh-listener &
59+
60+
61+## at this point you may want to modify zimmer to provide a proxy
62+## other than itself to things installing from it (LP: #914202).
63+## ssh to zimmer, and then edit :
64+## /var/lib/cobbler/snippets/orchestra_proxy
65
66=== added file 'vdenv/HOWTO.juju'
67--- vdenv/HOWTO.juju 1970-01-01 00:00:00 +0000
68+++ vdenv/HOWTO.juju 2012-03-09 21:00:25 +0000
69@@ -0,0 +1,68 @@
70+# http://askubuntu.com/questions/65359/how-do-i-configure-juju-for-local-usage
71+
72+pkgs="libzookeeper-java zookeeper juju bzr"
73+
74+JUJU_D=$HOME/juju
75+JUJU_ORIGIN="lp:juju"
76+JUJU_SERIES="precise"
77+
78+REPO="$HOME/charms"
79+CHARMS_D="$CHARMS_D/$JUJU_SERIES"
80+
81+ZIMMER_IP=192.168.123.2
82+
83+id_rsa="$HOME/.ssh/id_rsa"
84+[ -f "$id_rsa" ] || ssh-keygen -t rsa -N '' -f "$id_rsa"
85+read x y z < "$id_rsa"
86+grep -q "$y" ~/.ssh/authorized_keys ||
87+ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
88+
89+sudo apt-get --assume-yes install $pkgs </dev/null
90+
91+mkdir -p "${JUJU_D%/*}"
92+#( cd ${JUJU_D%/*} && bzr branch lp:juju )
93+( cd ${JUJU_D%/*} && bzr branch $JUJU_ORIGIN juju )
94+
95+mkdir -p "$CHARMS_D"
96+( cd "$CHARMS_D" && bzr branch lp:charm/mysql && bzr branch lp:charm/wordpress )
97+
98+ENAME="odev"
99+
100+mkdir ~/.juju/
101+cat > ~/.juju/environments.yaml <<EOF
102+environments:
103+ $ENAME:
104+ type: orchestra
105+ juju-origin: $JUJU_ORIGIN
106+ orchestra-server: $ZIMMER_IP
107+ orchestra-user: cobbler
108+ orchestra-pass: xcobbler
109+ acquired-mgmt-class: orchestra-juju-acquired
110+ available-mgmt-class: orchestra-juju-available
111+ admin-secret: SEEKRIT
112+ storage-url: http://$ZIMMER_IP/webdav
113+ authorized-keys: $(cat ~/.ssh/id_rsa.pub)
114+ data-dir: $HOME/juju-data/$ENAME
115+ default-series: $JUJU_SERIES
116+EOF
117+
118+export PATH="$JUJU_D/bin:$HOME/bin:/usr/sbin:/usr/bin:/sbin:/bin" PYTHONPATH=$JUJU_D
119+
120+# now start your juju bootstrap node. this will take some time, as we're
121+# doing a full install into the VM.
122+juju bootstrap --environment $ENAME
123+
124+# now create the mysql and wordpress units
125+# this takes quite a while as full VM install of each
126+juju deploy --environment $ENAME --repository $REPO local:mysql
127+juju deploy --environment $ENAME --repository $REPO local:wordpress
128+
129+# now link the two
130+juju add-relation --environment $ENAME wordpress mysql
131+
132+# juju status:
133+# FIXME: resolution will try to use dns and will not work for nodes
134+# workaround: can add 192.168.123.1 to /etc/resolv.conf 'server' line
135+# FIXME: juju status hangs "connecting to environment" during bootstrap
136+# node installation. The post should call home and indicate done. so
137+# juju could/should know that its still installing.
138
139=== added file 'vdenv/README.txt'
140--- vdenv/README.txt 1970-01-01 00:00:00 +0000
141+++ vdenv/README.txt 2012-03-09 21:00:25 +0000
142@@ -0,0 +1,5 @@
143+This allows you to create a VM cobbler provisioning environment in
144+a single system. That allows development working with cobbler or the
145+API without need for lots of hardware.
146+
147+
148
149=== added file 'vdenv/TODO'
150--- vdenv/TODO 1970-01-01 00:00:00 +0000
151+++ vdenv/TODO 2012-03-09 21:00:25 +0000
152@@ -0,0 +1,14 @@
153+- prefix names with 'odev' (or some prefix)
154+- settings.cfg: add 'cobbler' section for auth
155+- improve the Domain objects
156+- document
157+ - vinagre $(virsh vncdisplay node01)
158+ - ssh -L 5901:localhost:5901 -L 8000:192.168.123.2:80
159+ - start ssh connection to remote system with a bunch of ports
160+ forwarded for vnc connections and http to the zimmer box
161+ ssh -C home-jimbo \
162+ $(t=98; for((i=0;i<5;i++)); do p=$(printf "%02d" "$i"); echo -L $t$p:localhost:59$p; done ; echo -L${t}80:192.168.123.2:80)
163+- tell orchestra to point to a different proxy server
164+- document or fix annoying ssh key entries (juju prompt for add and change)
165+- get serial consoles to log file for domains
166+- support i386 (for i386 installs of ubuntu)
167
168=== added file 'vdenv/api-list.py'
169--- vdenv/api-list.py 1970-01-01 00:00:00 +0000
170+++ vdenv/api-list.py 2012-03-09 21:00:25 +0000
171@@ -0,0 +1,47 @@
172+#!/usr/bin/env python2.7
173+# Copyright 2012 Canonical Ltd. This software is licensed under the
174+# GNU Affero General Public License version 3 (see the file LICENSE).
175+
176+"""Print information from the Cobbler server."""
177+
178+from __future__ import (
179+ print_function,
180+ unicode_literals,
181+ )
182+
183+__metaclass__ = type
184+
185+import xmlrpclib
186+import sys
187+
188+host = "192.168.123.2"
189+user = "cobbler"
190+password = "cobbler"
191+if len(sys.argv) >= 2:
192+ host = sys.argv[1]
193+if len(sys.argv) >= 3:
194+ user = sys.argv[2]
195+if len(sys.argv) >= 4:
196+ password = sys.argv[3]
197+
198+if not host.startswith('http://'):
199+ host = "http://%s/cobbler_api" % host
200+
201+server = xmlrpclib.Server(host)
202+token = server.login(user, password)
203+
204+distros = server.get_distros()
205+print "::::::::::: distros :::::::::::"
206+for d in server.get_distros():
207+ print("%s: breed=%s, os_version=%s, mgmt_classes=%s" %
208+ (d['name'], d['breed'], d['os_version'], d['mgmt_classes']))
209+
210+profiles = server.get_profiles()
211+print "\n::::::::::: profiles :::::::::::"
212+for d in server.get_profiles():
213+ print("%s: distro=%s parent=%s kickstart=%s" %
214+ (d['name'], d['distro'], d['parent'], d['kickstart']))
215+
216+print "\n::::::::::: servers :::::::::::"
217+for s in server.get_systems():
218+ print s['interfaces']
219
220=== added directory 'vdenv/bin'
221=== added file 'vdenv/bin/authorize-ssh'
222--- vdenv/bin/authorize-ssh 1970-01-01 00:00:00 +0000
223+++ vdenv/bin/authorize-ssh 2012-03-09 21:00:25 +0000
224@@ -0,0 +1,46 @@
225+#!/usr/bin/env bash
226+# Copyright 2012 Canonical Ltd. This software is licensed under the
227+# GNU Affero General Public License version 3 (see the file LICENSE).
228+#
229+# Wait for the virtual cobbler instance's ssh server to start up, and set up
230+# passwordless login if desired.
231+#
232+# Usage:
233+# authorize-ssh <cobbler-ssh-login> <key-owner>
234+#
235+# Where:
236+# * cobbler-ssh-login is an ssh user/hostname, e.g. ubuntu@192.168.123.2
237+# * key-owner is a Launchpad login name, or * to use local keys, or nothing.
238+#
239+# If a Launchpad login name is given, import the associated ssh keys into the
240+# cobbler instance. If key-owner is an asterisk, import the local public ssh
241+# keys from ~/.ssh/id_*.pub
242+
243+# Exit immediately if a command exits with a non-zero status.
244+set -o errexit
245+# Treat unset variables as an error when substituting.
246+set -o nounset
247+
248+cobblerlogin=$1
249+keyowner=$2
250+
251+if test -z "$keyowner"
252+then
253+ echo "Not setting up ssh keys."
254+ echo "I'll still test a login to Cobbler though."
255+ inputfiles=/dev/null
256+ remotecmd="uptime"
257+elif test "$keyowner" = "*"
258+then
259+ inputfiles=`ls ~/.ssh/id_*.pub`
260+ echo "Copying public key(s): $inputfiles"
261+ remotecmd="tee .ssh/authorized_keys"
262+else
263+ inputfiles=/dev/null
264+ remotecmd="ssh-import-id $keyowner"
265+fi
266+
267+while ! cat $inputfiles | ssh $cobblerlogin -o StrictHostKeyChecking=no $remotecmd
268+do
269+ sleep 5
270+done
271
272=== added file 'vdenv/bin/start-odev'
273--- vdenv/bin/start-odev 1970-01-01 00:00:00 +0000
274+++ vdenv/bin/start-odev 2012-03-09 21:00:25 +0000
275@@ -0,0 +1,33 @@
276+#!/usr/bin/env bash
277+# Copyright 2012 Canonical Ltd. This software is licensed under the
278+# GNU Affero General Public License version 3 (see the file LICENSE).
279+
280+# Get zimmer and cobbler running, assuming that zimmer has already been set up.
281+
282+# Exit immediately if a command exits with a non-zero status.
283+set -o errexit
284+# Treat unset variables as an error when substituting.
285+set -o nounset
286+
287+## create libvirt xml files for nodes, zimmer, network
288+./setup.py libvirt-setup
289+
290+## start odev-net network
291+virsh -c qemu:///system net-start odev-net
292+
293+## create zimmer disk image qcow backing against pristine version
294+qemu-img create -f qcow2 -b zimmer-build/zimmer-disk0.img zimmer-disk0.img
295+
296+## start zimmer instance / orchestra server
297+virsh -c qemu:///system start zimmer
298+
299+cat <<EOF
300+Starting orchestra server.
301+You can now ssh ubuntu@192.168.123.2 (password: passw0rd).
302+If you do that, you may run 'ssh-import-id' to import your ssh key.
303+
304+Access the cobbler UI on http://192.168.123.2/cobbler_web
305+and log in with 'cobbler:xcobbler'.
306+EOF
307+
308+
309
310=== added file 'vdenv/bin/system-setup'
311--- vdenv/bin/system-setup 1970-01-01 00:00:00 +0000
312+++ vdenv/bin/system-setup 2012-03-09 21:00:25 +0000
313@@ -0,0 +1,52 @@
314+#!/usr/bin/env bash
315+# Copyright 2012 Canonical Ltd. This software is licensed under the
316+# GNU Affero General Public License version 3 (see the file LICENSE).
317+
318+#
319+# System-wide setup for odev. This requires sudo.
320+
321+# Exit immediately if a command exits with a non-zero status.
322+set -o errexit
323+# Treat unset variables as an error when substituting.
324+set -o nounset
325+
326+## install some dependencies
327+pkgs=""
328+pkgs="$pkgs genisoimage coreutils" # for cloud-init's 'make-iso'
329+pkgs="$pkgs python-libvirt libvirt-bin" # for libvirt interaction
330+pkgs="$pkgs socat" # for libvirt-> cobbler
331+pkgs="$pkgs python-cheetah" # for setup.py
332+pkgs="$pkgs qemu-utils qemu-kvm" # needed generally
333+
334+new_pkgs=""
335+for pkg in ${pkgs}; do
336+ dpkg-query --show "$pkg" >/dev/null ||
337+ new_pkgs="${new_pkgs:+${new_pkgs} }${pkg}"
338+done
339+
340+if [ -n "$new_pkgs" ]; then
341+ sudo apt-get update -qq || /bin/true
342+ sudo apt-get install -y $pkgs </dev/null
343+fi
344+
345+new_groups=""
346+for group in libvirtd kvm; do
347+ groups $USER | grep -q $group && continue
348+ sudo adduser $USER $group
349+ new_groups="${new_groups:+${new_groups} }${group}"
350+done
351+
352+if [ -n "$new_groups" ]; then
353+ cat <<EOF
354+Done.
355+
356+The script just added you to the system group[s] $new_groups
357+
358+If you were not previously in these groups, you will need to log out and
359+log back in again to make the changes take effect.
360+EOF
361+
362+ # The user may need to log out at this point.
363+ echo "Ctrl-C if you want to log out now. Otherwise, press <enter>."
364+ read
365+fi
366
367=== added file 'vdenv/bin/virsh-listener'
368--- vdenv/bin/virsh-listener 1970-01-01 00:00:00 +0000
369+++ vdenv/bin/virsh-listener 2012-03-09 21:00:25 +0000
370@@ -0,0 +1,34 @@
371+#!/usr/bin/env bash
372+# Copyright 2012 Canonical Ltd. This software is licensed under the
373+# GNU Affero General Public License version 3 (see the file LICENSE).
374+
375+## * libvirt from the cobbler system:
376+## after 'cobbler-setup' above is done, the cobbler system will know about
377+## all the nodes and it will believe it can control them via the 'virsh'
378+## power module. It is configured
379+## to talk to qemu+tcp://192.168.123.1:65001/system . In order to allow
380+## that to be valid we have to make libvirt listen on that port/interface.
381+## This can be done moderately securely with 'socat'. Below, we tell socat
382+## to forward tcp connections on 192.168.123.1:65001 to the libvirt unix
383+## socket . It restricts connections to zimmer's IP address.
384+
385+# Exit immediately if a command exits with a non-zero status.
386+set -o errexit
387+# Treat unset variables as an error when substituting.
388+set -o nounset
389+
390+sock="/var/run/libvirt/libvirt-sock"
391+
392+[ "${VIRSH_LISTENER_DEBUG:-0}" != "0" ] && cat <<EOF
393+Starting virsh listener.
394+
395+You can verify this is working by powering a sytem on from the web-ui or
396+the following on the cobbler server:
397+
398+zimmmer$ virsh -c qemu+tcp://192.168.123.1:65001/system
399+EOF
400+
401+echo "Listening for libvirt requests on $sock."
402+exec socat -d -d \
403+ TCP4-LISTEN:65001,bind=192.168.123.1,range=192.168.123.2/32,fork \
404+ UNIX-CONNECT:$sock
405
406=== added file 'vdenv/libvirt-domain.tmpl'
407--- vdenv/libvirt-domain.tmpl 1970-01-01 00:00:00 +0000
408+++ vdenv/libvirt-domain.tmpl 2012-03-09 21:00:25 +0000
409@@ -0,0 +1,56 @@
410+<domain type='kvm'>
411+ <name>$name</name>
412+ <memory>$mem</memory>
413+ <currentMemory>$mem</currentMemory>
414+ <vcpu>1</vcpu>
415+ <os>
416+ <type arch='x86_64' machine='pc-0.12'>hvm</type>
417+ <boot dev='network' />
418+ <boot dev='hd' />
419+ </os>
420+ <features>
421+ <acpi/>
422+ <apic/>
423+ <pae/>
424+ </features>
425+ <clock offset='utc'/>
426+ <on_poweroff>destroy</on_poweroff>
427+ <on_reboot>restart</on_reboot>
428+ <on_crash>restart</on_crash>
429+ <devices>
430+ <emulator>/usr/bin/kvm</emulator>
431+ <disk type='file' device='disk'>
432+ <driver name='qemu' type='qcow2'/>
433+ <source file='$disk0'/>
434+ <target dev='vda' bus='virtio'/>
435+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
436+ </disk>
437+ <controller type='ide' index='0'>
438+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
439+ </controller>
440+ <interface type='network'>
441+ <!-- <boot order='1'/> -->
442+ <source network='$network'/>
443+ <target dev='vnet1'/>
444+ <model type='virtio'/>
445+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
446+ <mac address='$mac'/>
447+ </interface>
448+ <serial type='pty'>
449+ <source path='/dev/pts/5'/>
450+ <target port='0'/>
451+ </serial>
452+ <console type='pty'>
453+ <target type='serial' port='0'/>
454+ </console>
455+ <input type='mouse' bus='ps2'/>
456+ <graphics type='vnc' autoport='yes' keymap='en-us'/>
457+ <video>
458+ <model type='cirrus' vram='9216' heads='1'/>
459+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
460+ </video>
461+ <memballoon model='virtio'>
462+ <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
463+ </memballoon>
464+ </devices>
465+</domain>
466
467=== added file 'vdenv/libvirt-network.tmpl'
468--- vdenv/libvirt-network.tmpl 1970-01-01 00:00:00 +0000
469+++ vdenv/libvirt-network.tmpl 2012-03-09 21:00:25 +0000
470@@ -0,0 +1,23 @@
471+<network>
472+ <name>$name</name>
473+ <forward mode='nat'/>
474+ <bridge name='$bridge' stp='off' delay='0' />
475+ <dns>
476+ <host ip='$ip_pre.1'>
477+ <hostname>host-system</hostname>
478+ </host>
479+ <host ip='$ip_pre.2'>
480+ <hostname>zimmer-server</hostname>
481+ </host>
482+ </dns>
483+ <ip address='$ip_pre.1' netmask='$netmask'>
484+ <dhcp>
485+ <range start='$ip_pre.$dhcp.range.start' end='$ip_pre.$dhcp.range.end' />
486+ <bootp server="$all_systems.zimmer.ipaddr" file="pxelinux.0" />
487+ #for $sys in $all_systems.itervalues()
488+ <host mac="$sys.mac" name="$sys.name" ip="$sys.ipaddr" />
489+ #end for
490+ </dhcp>
491+ </ip>
492+</network>
493+
494
495=== added file 'vdenv/settings.cfg'
496--- vdenv/settings.cfg 1970-01-01 00:00:00 +0000
497+++ vdenv/settings.cfg 2012-03-09 21:00:25 +0000
498@@ -0,0 +1,24 @@
499+network:
500+ name: odev-net
501+ bridge: virbr1
502+ ip_pre: 192.168.123
503+ ip: 1
504+ netmask: 255.255.255.0
505+ dhcp:
506+ range:
507+ start: 2
508+ end: 254
509+ template: libvirt-network.tmpl
510+
511+systems:
512+ zimmer:
513+ ip: 2 # ip address must be in dhcp range
514+ mac: 00:16:3e:3e:a9:1a
515+ template: libvirt-domain.tmpl
516+ mem: 512
517+
518+nodes:
519+ prefix: odev-node
520+ mac_pre: 00:16:3e:3e:aa
521+ mem: 512
522+ template: libvirt-domain.tmpl
523
524=== added file 'vdenv/setup.py'
525--- vdenv/setup.py 1970-01-01 00:00:00 +0000
526+++ vdenv/setup.py 2012-03-09 21:00:25 +0000
527@@ -0,0 +1,226 @@
528+#!/usr/bin/env python2.7
529+# Copyright 2012 Canonical Ltd. This software is licensed under the
530+# GNU Affero General Public License version 3 (see the file LICENSE).
531+
532+"""Setup a Virtual Data-center Environment."""
533+
534+from __future__ import (
535+ print_function,
536+ unicode_literals,
537+ )
538+
539+__metaclass__ = type
540+
541+import yaml
542+import os
543+import re
544+import sys
545+import libvirt
546+from Cheetah.Template import Template
547+import subprocess
548+import xmlrpclib
549+
550+NODES_RANGE = range(1,4)
551+
552+def yaml_loadf(fname):
553+ fp = open(fname)
554+ ret = yaml.load(fp)
555+ fp.close()
556+ return(ret)
557+
558+class Domain:
559+ def __init__(self, syscfg, ident, basedir=None):
560+ self.ip_pre = syscfg['network']['ip_pre']
561+ if basedir == None:
562+ basedir = os.path.abspath(os.curdir)
563+ self.basedir = basedir
564+ self._setcfg(syscfg,ident)
565+ self.network = syscfg['network']['name']
566+
567+ def __repr__(self):
568+ return("== %s ==\n ip: %s\n mac: %s\n template: %s\n" %
569+ (self.name, self.ipaddr, self.mac, self.template))
570+
571+ @property
572+ def ipaddr(self):
573+ return("%s.%s" % (self.ip_pre, self.ipnum))
574+
575+ @property
576+ def disk0(self):
577+ return("%s/%s-disk0.img" % (self.basedir, self.name))
578+
579+ def dictInfo(self):
580+ ret = vars(self)
581+ # have to add the getters
582+ for prop in ( "ipaddr", "disk0" ):
583+ ret[prop] = getattr(self,prop)
584+ return ret
585+
586+ def toLibVirtXml(self):
587+ template = Template(file=self.template, searchList=[self.dictInfo()])
588+ return template.respond()
589+
590+class Node(Domain):
591+ def _setcfg(self, cfg, num):
592+ cfg = cfg['nodes']
593+ self.name = "%s%02i" % (cfg['prefix'],num)
594+ self.mac = "%s:%02x" % (cfg['mac_pre'],num)
595+ self.ipnum = num + 100
596+ self.template = cfg['template']
597+ self.mem = cfg['mem'] * 1024
598+ return
599+
600+class System(Domain):
601+ def _setcfg(self, cfg, ident):
602+ cfg = cfg['systems'][ident]
603+ self.name = ident
604+ self.mac = cfg['mac']
605+ self.ipnum = cfg['ip']
606+ self.template = cfg['template']
607+ self.mem = cfg['mem'] * 1024
608+
609+def renderSysDom(config, syscfg, stype="node"):
610+ template = Template(file=syscfg['template'], searchList=[config, syscfg])
611+ return template.respond()
612+
613+# cobbler:
614+# ip: 2 # ip address must be in dhcp range
615+# mac: 00:16:3e:3e:a9:1a
616+# template: libvirt-system.tmpl
617+# mem: 524288
618+#
619+#nodes:
620+# prefix: node
621+# mac_pre: 00:16:3e:3e:aa
622+# mam: 256
623+
624+def writeDomXmlFile(dom, outpre=""):
625+ fname="%s%s.xml" % (outpre, dom.name)
626+ output = open(fname,"w")
627+ output.write(dom.toLibVirtXml())
628+ output.close()
629+ return fname
630+
631+def libvirt_setup(config):
632+ conn = libvirt.open("qemu:///system")
633+ netname = config['network']['name']
634+ if netname in conn.listDefinedNetworks() or netname in conn.listNetworks():
635+ net = conn.networkLookupByName(netname)
636+ if net.isActive():
637+ net.destroy()
638+ net.undefine()
639+
640+ allsys = {}
641+ for system in config['systems']:
642+ d = System(config, system)
643+ allsys[d.name]=d.dictInfo()
644+ for num in NODES_RANGE:
645+ d = Node(config, num)
646+ allsys[d.name]=d.dictInfo()
647+
648+ conn.networkDefineXML(Template(file=config['network']['template'],
649+ searchList=[config['network'],
650+ {'all_systems': allsys }]).respond())
651+
652+ print "defined network %s " % netname
653+
654+ cob = System(config, "zimmer")
655+ systems = [ cob ]
656+
657+ for node in NODES_RANGE:
658+ systems.append(Node(config, node))
659+
660+ qcow_create = "qemu-img create -f qcow2 %s 2G"
661+ defined_systems = conn.listDefinedDomains()
662+ for system in systems:
663+ if system.name in defined_systems:
664+ dom = conn.lookupByName(system.name)
665+ if dom.isActive():
666+ dom.destroy()
667+ dom.undefine()
668+ conn.defineXML(system.toLibVirtXml())
669+ if isinstance(system,Node):
670+ subprocess.check_call(qcow_create % system.disk0, shell=True)
671+ print "defined domain %s" % system.name
672+
673+def cobbler_addsystem(server, token, system, profile, hostip):
674+ eth0 = {
675+ "macaddress-eth0" : system.mac,
676+ "ipaddress-eth0" : system.ipaddr,
677+ "static-eth0" : False,
678+ }
679+ items = {
680+ 'name': system.name,
681+ 'hostname': system.name,
682+ 'power_address': "qemu+tcp://%s:65001" % hostip,
683+ 'power_id': system.name,
684+ 'power_type': "virsh",
685+ 'profile': profile,
686+ 'netboot_enabled': True,
687+ 'modify_interface': eth0,
688+ 'mgmt_classes': ['orchestra-juju-available'],
689+ }
690+
691+ if len(server.find_system({"name": system.name})):
692+ server.remove_system(system.name,token)
693+ server.update()
694+ print "removed existing %s" % system.name
695+
696+ sid = server.new_system(token)
697+ for key, val in items.iteritems():
698+ ret = server.modify_system(sid, key, val, token)
699+ if not ret:
700+ raise Exception("failed for %s [%s]: %s, %s" %
701+ (system.name, ret, key, val))
702+ ret = server.save_system(sid,token)
703+ if not ret:
704+ raise Exception("failed to save %s" % system.name)
705+ print "added %s" % system.name
706+
707+
708+def get_profile_arch():
709+ """Get the system architecture for use in the cobbler setup profile."""
710+ # This should, for any given system, match what the zimmer-build
711+ # script does to determine the right architecture.
712+ arch_text = subprocess.check_output(['/bin/uname', '-m']).strip()
713+ if re.match('i.86', arch_text):
714+ return 'i386'
715+ else:
716+ return arch_text
717+
718+
719+def cobbler_setup(config):
720+ hostip = "%s.1" % config['network']['ip_pre']
721+ arch = get_profile_arch()
722+ profile = "precise-%s-juju" % arch
723+
724+ cob = System(config, "zimmer")
725+ cobbler_url = "http://%s/cobbler_api" % cob.ipaddr
726+ print("Connecting to %s." % cobbler_url)
727+ server = xmlrpclib.Server(cobbler_url)
728+ token = server.login("cobbler","xcobbler")
729+
730+ systems = [Node(config, node) for node in NODES_RANGE]
731+
732+ for system in systems:
733+ cobbler_addsystem(server, token, system, profile, hostip)
734+
735+def main():
736+ outpre = "libvirt-cobbler-"
737+ cfg_file = "settings.cfg"
738+
739+ if len(sys.argv) == 1:
740+ print(
741+ "Usage: setup.py action\n"
742+ "action one of: libvirt-setup, cobbler-setup")
743+ sys.exit(1)
744+
745+ config = yaml_loadf(cfg_file)
746+
747+ if sys.argv[1] == "libvirt-setup":
748+ libvirt_setup(config)
749+ elif sys.argv[1] == "cobbler-setup":
750+ cobbler_setup(config)
751+
752+if __name__ == '__main__':
753+ main()
754
755=== added directory 'vdenv/zimmer-build'
756=== added file 'vdenv/zimmer-build/build'
757--- vdenv/zimmer-build/build 1970-01-01 00:00:00 +0000
758+++ vdenv/zimmer-build/build 2012-03-09 21:00:25 +0000
759@@ -0,0 +1,277 @@
760+#!/usr/bin/env bash
761+# Copyright 2012 Canonical Ltd. This software is licensed under the
762+# GNU Affero General Public License version 3 (see the file LICENSE).
763+
764+# Exit immediately if a command exits with a non-zero status.
765+set -o errexit
766+# Treat unset variables as an error when substituting.
767+set -o nounset
768+
769+# This should mirror what's in odev's setup.py, except here x86_64 is called
770+# amd64, not x86_64 because that is Ubuntu's selected name for the arch.
771+GUEST_ARCHITECTURE=$(uname -m)
772+case "$GUEST_ARCHITECTURE" in
773+ i?86) GUEST_ARCHITECTURE="i386" ;;
774+ x86_64) GUEST_ARCHITECTURE="amd64" ;;
775+esac
776+
777+
778+DEF_ZIMG="http://cloud-images.ubuntu.com/server/precise/current/precise-server-cloudimg-${GUEST_ARCHITECTURE}-disk1.img"
779+DEF_SAVE_D="pristine"
780+DEF_UD_FILE="ud-build.txt"
781+ZIMMER_SSH_FORWARD=""
782+#ZIMMER_SSH_FORWARD=${ZIMMER_SSH_FORWARD:-"hostfwd=tcp::2222-:22"}
783+ZIMMER_MEM="${ZIMMER_MEM:-1024}"
784+KVM_PID=""
785+TAIL_PID=""
786+LOG="output.log"
787+
788+case $(uname -m) in
789+ i?86) DEF_ZIMG=${DEF_ZIMG//amd64/i386};;
790+esac
791+
792+VERBOSITY=0
793+TEMP_D=""
794+
795+error() { echo "$@" 1>&2; }
796+errorp() { printf "$@" 1>&2; }
797+fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
798+failp() { [ $# -eq 0 ] || errorp "$@"; exit 1; }
799+
800+Usage() {
801+ cat <<EOF
802+Usage: ${0##*/} [ options ] output
803+
804+ build a zimmer server from a cloud image, and put it in 'output'
805+
806+ options:
807+ --zimg Z url or path to compressed cloud image
808+ (will be uncompressed)
809+ def: $DEF_ZIMG
810+ --img I url or path to uncompressed cloud image
811+ expected to be uncompressed.
812+ default: create from zimg
813+ --log L log items to LOG
814+ default: $LOG
815+ --save D put pristine copies of things in D
816+ default: $DEF_SAVE_D
817+ --ud-file F use user-data file F
818+ default: $DEF_USER_DATA
819+ --import-keys K import ssh keys
820+ values are 'auto', 'lp:<id>', or path to file
821+EOF
822+}
823+
824+bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; exit 1; }
825+cleanup() {
826+ [ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
827+ [ -z "$KVM_PID" ] || kill "$KVM_PID"
828+ [ -z "$TAIL_PID" ] || kill "$TAIL_PID"
829+}
830+
831+log() {
832+ [ -n "$LOG" ] || return
833+ echo "$(date -R):" "$@" >> "$LOG"
834+}
835+debug() {
836+ local level=${1}; shift;
837+ log "$@"
838+ [ "${level}" -gt "${VERBOSITY}" ] && return
839+ error "${@}"
840+}
841+
842+# Download image file.
843+# Parameters: source URL, filename to save to
844+download() {
845+ local src="$1" dest="$2"
846+
847+ debug 0 "downloading $src to $dest"
848+ wget --progress=dot:mega "$src" -O "$dest.partial" &&
849+ mv -- "$dest.partial" "$dest" ||
850+ fail "failed to get $src"
851+}
852+
853+short_opts="ho:v"
854+long_opts="help,img:,import-keys:,log:,ud-file:,verbose,zimg:"
855+getopt_out=$(getopt --name "${0##*/}" \
856+ --options "${short_opts}" --long "${long_opts}" -- "$@") &&
857+ eval set -- "${getopt_out}" ||
858+ bad_Usage
859+
860+img=""
861+zimg=""
862+save_d="$DEF_SAVE_D"
863+ud_file="$DEF_UD_FILE"
864+import_keys=""
865+
866+while [ $# -ne 0 ]; do
867+ cur=${1}; next=${2};
868+ case "$cur" in
869+ -h|--help) Usage ; exit 0;;
870+ --img) img=${2}; shift;;
871+ --log) LOG=${2}; shift;;
872+ --save) save_d=${2}; shift;;
873+ --ud-file) ud_file=${2}; shift;;
874+ -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
875+ --zimg) zimg=${2}; shift;;
876+ --import-keys) import_keys=${2}; shift;;
877+ --) shift; break;;
878+ esac
879+ shift;
880+done
881+
882+## check arguments here
883+## how many args do you expect?
884+[ $# -gt 1 ] && bad_Usage "too many arguments"
885+[ $# -eq 0 ] && bad_Usage "need an output argument"
886+output="$1"
887+[ "${output%.zimg}" = "${output}" ] || fail "do not name output with .zimg"
888+
889+command -v genisoimage >/dev/null ||
890+ fail "you do not have genisoimage installed. install genisoimage package"
891+
892+
893+[ -f "$ud_file" ] ||
894+ fail "user data file $ud_file" is not a file
895+
896+TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
897+ fail "failed to make tempdir"
898+trap cleanup EXIT
899+
900+mkdir -p "$save_d" || fail "failed to mkdir $save_d"
901+
902+# if --import-keys was specified, get the keys into a local file
903+keyf="$TEMP_D/keys"
904+if [ "$import_keys" = "auto" ]; then
905+ ssh-add -L > "${keyf}" 2>/dev/null ||
906+ cat $HOME/.ssh/id*.pub > "$keyf" 2>/dev/null ||
907+ error "Warning: unable to find 'auto' keys"
908+elif [ -f "$import_keys" ]; then
909+ cat "$import_keys" > "$keyf"
910+elif [ "${import_keys#lp:}" != "${import_keys}" ]; then
911+ ssh-import-id -o - ${import_keys#lp:} > "$keyf" 2>/dev/null ||
912+ error "Warning: failed to ssh-import ${import_keys#lp:}"
913+fi
914+
915+if [ -n "$img" ]; then
916+ # if img was given, then we assume good, its the backing image
917+ [ -f "$img" ] || fail "$img (--img) is not a file"
918+ debug 0 "using $img as uncompressed image"
919+else
920+ if [ -z "$zimg" ]; then
921+ zimg="$DEF_ZIMG"
922+ fi
923+ case "$zimg" in
924+ http://*|https://*)
925+ o_zimg="${zimg}"
926+ zimg=${save_d}/$(basename "$o_zimg" ".img").zimg
927+ [ -f "$zimg" ] &&
928+ fail "please delete $destfirst or use --zimg|--img"
929+ download "$o_zimg" "$zimg"
930+ ;;
931+ file://*)
932+ o_zimg=${zimg}
933+ zimg=${zimg#file://}
934+ debug 0 "using file $o_zimg as zimg"
935+ [ -f "$zimg" ] || fail "$zimg is not a file"
936+ ;;
937+ *) [ -f "$zimg" ] || fail "$zimg is not a file"
938+ debug 0 "using file $zimg as zimg"
939+ ;;
940+ esac
941+ img=${zimg%.zimg}.img
942+ debug 0 "creating uncompressed img $img from $zimg"
943+ qemu-img convert -O qcow2 "$zimg" "$img"
944+fi
945+
946+debug 0 "making nocloud data source in iso"
947+seed_d="$TEMP_D/seed"
948+mkdir "$seed_d" || fail "failed to make 'seed' in tempdir"
949+
950+cp "$ud_file" "$seed_d/user-data" || fail "failed to copy $ud_file to $seed_d"
951+cat > "$seed_d/meta-data" <<EOF
952+instance-id: i-zimmer-build
953+local-hostname: zimmer-build
954+EOF
955+
956+# if keys were specified, dump them into meta-data
957+if [ -s "$keyf" ]; then
958+ {
959+ echo "public-keys:"
960+ echo " zimmer-build:"
961+ while read line; do
962+ echo " - \"$line\""
963+ done < "$keyf"
964+ } >> "$seed_d/meta-data"
965+fi
966+
967+( cd "$seed_d" &&
968+ genisoimage -output "$TEMP_D/build.iso" \
969+ -volid cidata -joliet -rock user-data meta-data 2>/dev/null ) ||
970+ fail "failed to create iso for user-data from $ud_file"
971+
972+build0="$TEMP_D/build0.img"
973+img_fp=$(readlink -f "$img") || fail "failed to get fullpath for $img"
974+qemu-img create -f qcow2 -b "$img_fp" "${build0}" ||
975+ fail "failed to create qcow image backed by $img"
976+
977+## on precise, you do do not need 'boot=on' in kvm commanad line
978+[ "$(lsb_release -sc)" = "precise" ] && bton="" || bton="boot=on"
979+
980+serial_out="$TEMP_D/serial.output"
981+monitor="${TEMP_D}/monitor.fifo" && mkfifo "$monitor" ||
982+ fail "failed to mkfifo for monitor"
983+
984+debug 0 "booting kvm guest to turn cloud-image into zimmer"
985+kvm_start=$SECONDS
986+MONITOR="-monitor null"
987+NOGRAPHIC="-nographic"
988+kvm \
989+ -drive file=${build0},if=virtio,cache=unsafe${bton:+,${bton}} \
990+ -boot c -cdrom "$TEMP_D/build.iso" \
991+ -net nic,model=virtio \
992+ -net user${ZIMMER_SSH_FORWARD:+,${ZIMMER_SSH_FORWARD}} \
993+ -m "${ZIMMER_MEM}" \
994+ $NOGRAPHIC \
995+ $MONITOR \
996+ -serial "file:$serial_out" \
997+ 2>&1 &
998+
999+KVM_PID=$!
1000+tail -F "$serial_out" 2>/dev/null &
1001+TAIL_PID=$!
1002+
1003+sleep 20
1004+[ -s "$serial_out" ] ||
1005+ fail "no output in serial console output after 20 seconds"
1006+
1007+wait $KVM_PID
1008+ret=$?
1009+KVM_PID=""
1010+
1011+{ kill $TAIL_PID ; } >/dev/null 2>&1
1012+TAIL_PID=""
1013+
1014+{
1015+ echo ===== begin serial console ====
1016+ cat "$serial_out"
1017+ echo ===== end serial console ====
1018+} >> "$LOG"
1019+[ $ret -eq 0 ] || fail "failed to build via kvm guest"
1020+grep -q "ZIMMER BUILD FINISHED" "$serial_out" ||
1021+ fail "did not find finished message in $serial_out"
1022+
1023+debug 0 "kvm image built in $(($SECONDS-$kvm_start))s"
1024+debug 0 "creating dist image in $output"
1025+## create a re-shrunk image of build0.img into 'zimmer-disk0.img.dist'
1026+[ ! -f "$output" ] || rm -f "$output" ||
1027+ fail "failed to remove existing $output"
1028+qemu-img convert -O qcow2 "$TEMP_D/build0.img" "$output" &&
1029+ chmod 444 "$output" ||
1030+ fail "failed to create $output from build0.img"
1031+
1032+debug 0 "creating pristine compressed zimmer-disk0.zimg"
1033+## optionally create a zip'd image for transmission
1034+qemu-img convert -f qcow2 -O qcow2 -c "$output" "${output%.img}.zimg"
1035+
1036+debug 0 "done. took $SECONDS seconds"
1037
1038=== added file 'vdenv/zimmer-build/ud-build.txt'
1039--- vdenv/zimmer-build/ud-build.txt 1970-01-01 00:00:00 +0000
1040+++ vdenv/zimmer-build/ud-build.txt 2012-03-09 21:00:25 +0000
1041@@ -0,0 +1,70 @@
1042+#cloud-config
1043+password: passw0rd
1044+chpasswd: { expire: False }
1045+ssh_pwauth: True
1046+
1047+#apt_proxy: "http://local-proxy:3128/"
1048+#apt_mirror: "http://us.archive.ubuntu.com/ubuntu"
1049+#ssh_import_id: smoser
1050+
1051+bucket:
1052+ - &setup |
1053+ cd /root
1054+ (
1055+ #ONE_TIME_PROXY=http://local-proxy:3128/
1056+
1057+ echo === $(date) ====
1058+ debconf-set-selections <<EOF
1059+ ubuntu-orchestra-provisioning-server ubuntu-orchestra-provisioning-server/import-isos boolean false
1060+ ubuntu-orchestra-provisioning-server ubuntu-orchestra-provisioning-server/dnsmasq-dhcp-range string 10.10.10.2,10.10.10.254
1061+ ubuntu-orchestra-provisioning-server ubuntu-orchestra-provisioning-server/dnsmasq-enabled boolean false
1062+ cobbler cobbler/server_and_next_server string zimmer-server
1063+ cobbler cobbler/password password xcobbler
1064+ cloud-init cloud-init/datasources multiselect NoCloud, OVF
1065+
1066+ EOF
1067+
1068+ [ -n "$ONE_TIME_PROXY" ] && export http_proxy="$ONE_TIME_PROXY"
1069+ export DEBIAN_FRONTEND=noninteractive;
1070+ dpkg-reconfigure cloud-init
1071+
1072+ read oldhost < /etc/hostname
1073+ sed -i "/$oldhost/d;/zimmer/d" /etc/hosts
1074+ echo zimmer > /etc/hostname
1075+ hostname zimmer
1076+
1077+ echo "127.0.1.2 zimmer-server" >> /etc/hosts
1078+
1079+ echo === $(date): starting apt ====
1080+ apt_get() {
1081+ DEBIAN_FRONTEND=noninteractive apt-get \
1082+ --option "Dpkg::Options::=--force-confold" --assume-yes "$@"
1083+ }
1084+ apt_get update
1085+ apt_get install ubuntu-orchestra-provisioning-server libvirt-bin cobbler-web
1086+
1087+ case $(uname -m) in
1088+ i?86) arches="i386";;
1089+ *) arches="amd64";;
1090+ esac
1091+ cat >> /etc/orchestra/import_isos <<END
1092+ RELEASES="oneiric precise"
1093+ ARCHES="${arches}"
1094+ END
1095+
1096+ echo === $(date): starting import ====
1097+ orchestra-import-isos
1098+
1099+ sed -i '/zimmer-server/d' /etc/hosts
1100+
1101+ echo === $(date): starting cleanup ====
1102+ apt_get clean
1103+ time sh -c 'dd if=/dev/zero of=/out.img; rm /out.img'
1104+
1105+ echo === $(date): poweroff ===
1106+ echo === ZIMMER BUILD FINISHED ===
1107+ ) 2>&1 | tee out.log
1108+
1109+runcmd:
1110+ - [ sh, -c, *setup ]
1111+ - [ /sbin/poweroff ]