Merge lp:~thomir-deactivatedaccount/core-image-tester/trunk-local-ssh-setup into lp:core-image-tester

Proposed by Thomi Richards
Status: Merged
Approved by: Thomi Richards
Approved revision: 32
Merged at revision: 32
Proposed branch: lp:~thomir-deactivatedaccount/core-image-tester/trunk-local-ssh-setup
Merge into: lp:core-image-tester
Diff against target: 464 lines (+405/-8)
3 files modified
README.rst (+16/-7)
core_image_tester/worker.py (+13/-1)
uci-nova (+376/-0)
To merge this branch: bzr merge lp:~thomir-deactivatedaccount/core-image-tester/trunk-local-ssh-setup
Reviewer Review Type Date Requested Status
Francis Ginther Approve
Review via email: mp+257582@code.launchpad.net

Commit message

Make uci-nova inline.

Description of the change

This branch copies uci-nova from revno 6 of the uci-nova branch. I'll follow this with another branch that removes some of the options that aren't applicable to the core-image-tester.

To post a comment you must log in.
Revision history for this message
Francis Ginther (fginther) wrote :

Approve

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'README.rst'
--- README.rst 2015-04-01 00:32:13 +0000
+++ README.rst 2015-04-27 21:05:47 +0000
@@ -28,17 +28,10 @@
28 $ sudo apt-get update28 $ sudo apt-get update
29 $ sudo apt-get install autopkgtest29 $ sudo apt-get install autopkgtest
3030
31.. note::
32 Thomi: At the time of writing (16/3/2015), the autopkgtest from the PPA is not
33 enough to make this work. You also need to manually branch
34 lp:~canonical-ci-engineering/adt-cloud-worker/uci-nova and follow the instructions
35 there.
36
37...and install bzr, which is needed to get the test branch::31...and install bzr, which is needed to get the test branch::
3832
39 $ sudo apt-get install bzr33 $ sudo apt-get install bzr
4034
41
42Install the service itself::35Install the service itself::
4336
44 $ python setup.py install37 $ python setup.py install
@@ -49,6 +42,22 @@
4942
50 $ python setup.py develop43 $ python setup.py develop
5144
45uci-nova
46++++++++
47
48This service includes a custom adt-run ssh setup script called 'uci-nova'. This
49is a shell script that exists in the root of the branch, and is called by the
50core-image-tester service.
51
52You can run adt-run manually yourself, in order to replicate what the service
53does. For example::
54
55 $ adt-run --built-tree <test_dir> \
56 --output-dir <result_dir> \
57 --- ssh -s ./uci-nova -- \
58 --flavor <nova_flavour> \
59 --image <nova_image>
60
52Run the tests!61Run the tests!
53==============62==============
5463
5564
=== modified file 'core_image_tester/worker.py'
--- core_image_tester/worker.py 2015-04-17 16:02:30 +0000
+++ core_image_tester/worker.py 2015-04-27 21:05:47 +0000
@@ -18,6 +18,7 @@
18"""ADT Cloud worker functional code."""18"""ADT Cloud worker functional code."""
19import logging19import logging
20import os20import os
21import os.path
21import shutil22import shutil
22import subprocess23import subprocess
23import tarfile24import tarfile
@@ -204,7 +205,7 @@
204 '--built-tree', test_dir,205 '--built-tree', test_dir,
205 '--output-dir', result_dir,206 '--output-dir', result_dir,
206 # Specify the ssh backend, and the uci-nova setup script:207 # Specify the ssh backend, and the uci-nova setup script:
207 '---', 'ssh', '-s', 'uci-nova', '--',208 '---', 'ssh', '-s', get_uci_nova_path(), '--',
208 '--flavor', config['adt']['image_flavor'],209 '--flavor', config['adt']['image_flavor'],
209 '--image', nova_image,210 '--image', nova_image,
210 '--console', os.path.join(result_dir, 'nova-console.log'),211 '--console', os.path.join(result_dir, 'nova-console.log'),
@@ -219,6 +220,17 @@
219 return 0220 return 0
220221
221222
223def get_uci_nova_path():
224 return os.path.abspath(
225 os.path.join(
226 __file__,
227 '..',
228 '..',
229 'uci-nova'
230 )
231 )
232
233
222def sanitize_results(results_dir, config):234def sanitize_results(results_dir, config):
223 """Filter out any secrets exposed in select log files.235 """Filter out any secrets exposed in select log files.
224236
225237
=== added file 'uci-nova'
--- uci-nova 1970-01-01 00:00:00 +0000
+++ uci-nova 2015-04-27 21:05:47 +0000
@@ -0,0 +1,376 @@
1#!/bin/sh
2#
3# This script is part of autopkgtest
4# autopkgtest is a tool for testing Debian binary packages
5#
6# This script sets up a nova instance to use as an autopkgtest testbed. It
7# assumes that the host system is already prepared to run nova commands.
8# WARNING: This is mostly a proof of concept and not very robust.
9
10# Options:
11#
12# -f flavor | --flavor=flavor
13# Name or ID of flavor (see 'nova flavor-list'), mandatory
14# -i image | --image=image
15# Name or ID of image (see 'nova image-list'), mandatory
16# -N net-id | --net-id=net-id
17# UUID of the network that should be used for the instance
18# -n name | --name=name
19# Name for the new server. A name will be generated if not specified.
20# -c console-log | --console=file-name
21# Save the nova console-log of the server to the specified file.
22#
23#
24# Authors:
25# Celso Providelo <celso.providelo@canonical.com>
26#
27#
28# autopkgtest is Copyright (C) 2006-2015 Canonical Ltd.
29#
30# This program is free software; you can redistribute it and/or modify
31# it under the terms of the GNU General Public License as published by
32# the Free Software Foundation; either version 2 of the License, or
33# (at your option) any later version.
34#
35# This program is distributed in the hope that it will be useful,
36# but WITHOUT ANY WARRANTY; without even the implied warranty of
37# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38# GNU General Public License for more details.
39#
40# You should have received a copy of the GNU General Public License
41# along with this program; if not, write to the Free Software
42# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
43#
44# See the file CREDITS for a full list of credits information (often
45# installed as /usr/share/doc/autopkgtest/CREDITS).
46set -eu
47
48CAPABILITIES='isolation-machine,reboot,revert,revert-full-system'
49
50SUDO_PASSWORD=''
51SSH_USER=ubuntu
52
53FLAVOR=""
54IMAGE=""
55
56SRVNAME=""
57NET_ID=""
58CONSOLE=""
59DEBUG=""
60
61
62debug() {
63 [ -z "$DEBUG" ] && return
64 echo "$@">&2
65}
66
67warning() {
68 echo "$@">&2
69}
70
71error() {
72 echo "$@">&2
73}
74
75parse_args() {
76 # Parse command line argument and populate environment
77
78 SHORTOPTS="f:,i:,N:,n:,c:,d"
79 LONGOPTS="flavor:,image:,net-id:,name:,console:,debug"
80
81 TEMP=$(getopt -o $SHORTOPTS --long $LONGOPTS -- "$@")
82 eval set -- "$TEMP"
83
84 while true; do
85 case "$1" in
86 -f|--flavor)
87 FLAVOR=$2
88 shift 2;;
89 -i|--image)
90 IMAGE=$2
91 shift 2;;
92 -N|--net-id)
93 NET_ID="$2"
94 shift 2;;
95 -n|--name)
96 SRVNAME=$2
97 shift 2;;
98 -c|--console)
99 CONSOLE=$2
100 shift 2;;
101 -d|--debug)
102 DEBUG=1; shift;;
103 --)
104 shift;
105 break;;
106 *)
107 error "E: $(basename $0): Unsupported option $1"
108 exit 1;;
109 esac
110 done
111
112 if [ -z "$FLAVOR" ]; then
113 error "Argument 'flavor' is mandatory. Run 'nova flavor-list' to "\
114 "print a list of available flavors."
115 exit 1
116 fi
117 if [ -z "$IMAGE" ]; then
118 error "Argument 'image' is mandatory. Run 'nova image-list' to "\
119 "print a list of available images to boot from."
120 exit 1
121 fi
122}
123
124security_setup_nova() {
125 debug "Creating specific nova security-group: $SRVNAME"
126 nova secgroup-create $SRVNAME "$SRVNAME testbed"
127
128 debug "Allowing ingress SSH ..."
129 nova secgroup-add-rule $SRVNAME tcp 22 22 0.0.0.0/0
130
131 debug "Egress traffic will respect external Firewall rules ..."
132}
133
134security_setup_neutron() {
135 debug "Creating specific neutron security-group: $SRVNAME"
136 neutron security-group-create $SRVNAME \
137 --description "$SRVNAME testbed"
138
139 debug "Cleaning up default egress rules ..."
140 DEFAULT_RULES=$(neutron security-group-rule-list \
141 --format csv -c id -c security_group --quote none \
142 | grep $SRVNAME | cut -d',' -f1)
143 for rule_id in $DEFAULT_RULES; do
144 neutron security-group-rule-delete $rule_id
145 done
146
147 debug "Allowing ingress SSH ..."
148 neutron security-group-rule-create \
149 --direction ingress \
150 --ethertype ipv4 \
151 --protocol tcp \
152 --port-range-min 22 \
153 --port-range-max 22 \
154 --remote-ip-prefix 0.0.0.0/0 \
155 $SRVNAME
156
157 debug "Allowing DNS egress traffic ..."
158 neutron security-group-rule-create \
159 --direction egress \
160 --remote-ip-prefix 8.8.8.8 \
161 $SRVNAME
162
163 debug "Allowing APT and NTP egress traffic ..."
164 neutron security-group-rule-create \
165 --direction egress \
166 --remote-ip-prefix 91.189.88.0/21 \
167 $SRVNAME
168}
169
170# create a testbed (if necessary), configure ssh, copy ssh key into it,
171# configure sudo, etc.; print a list of "key=value" parameters to stdout on
172# success
173open() {
174 # Boot a nova instance and returns its connection parameters
175 [ -n "$SRVNAME" ] || SRVNAME=`mktemp -u adt-nova-XXXXXX`
176
177 mkdir /tmp/$SRVNAME
178
179 debug "Creating new SSH key on /tmp/$SRVNAME"
180 SSH_IDENTITY=/tmp/$SRVNAME/id_rsa
181 ssh-keygen -f $SSH_IDENTITY -q -N ""
182
183 debug "Creating specific nova keypair: $SRVNAME"
184 nova keypair-add --pub-key $SSH_IDENTITY.pub $SRVNAME
185
186 # Setup testbed security with nova or neutron according to their
187 # availability in the target cloud.
188 if ! neutron security-group-list; then
189 security_setup_nova
190 else
191 security_setup_neutron
192 fi
193
194 # generate cloud-init user data; mostly for manage_etc_hosts, but also get
195 # rid of some unnecessary stuff in the VM
196 local userdata=`mktemp`
197 cat <<EOF > $userdata
198#cloud-config
199manage_etc_hosts: true
200apt_update: true
201apt_upgrade: false
202snappy:
203 ssh_enabled: True
204
205runcmd:
206 - echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/90nolanguages
207 - echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/autopkgtest
208EOF
209
210 EXTRA_OPTS=''
211 if [ -n "$NET_ID" ]; then
212 EXTRA_OPTS="$EXTRA_OPTS --nic net-id=$NET_ID"
213 fi
214
215 # Boot the instance
216 debug "Creating nova instance $SRVNAME ..."
217 OUT=$(nova boot --config-drive=1 \
218 --flavor $FLAVOR --image $IMAGE --user-data $userdata \
219 --key_name $SRVNAME --security-groups $SRVNAME \
220 $EXTRA_OPTS $SRVNAME 2>&1) || {
221 error "nova boot failed:"
222 error "$OUT"
223 exit 1
224 }
225 debug "Nova boot succeeded"
226 rm $userdata
227
228 # Find IP address
229 ipaddr=""
230 retry=60
231 while [ -z "$ipaddr" ]; do
232 OUT=$(nova show --minimal $SRVNAME)
233 ipaddr=$(echo "$OUT" | awk 'BEGIN {FS="|"} /network/ {n=split($3,i,/,\s*/); gsub(" ", "", i[n]); print i[n]}')
234 retry=$(( retry - 1 ))
235 if [ $retry -le 0 ]; then
236 error "Failed to acquire an IP address. Aborting!"
237 error "$OUT"
238 cleanup
239 exit 1
240 fi
241 sleep 3
242 done
243 debug "Finding IP address succeeded: $ipaddr"
244
245 # purge the device host key so that SSH doesn't print a scary warning
246 ssh-keygen -f ~/.ssh/known_hosts -R $ipaddr >/dev/null 2>&1 || true
247
248 ADT_EXTRA_OPTS="-n $SRVNAME"
249 if [ -n "$CONSOLE" ]; then
250 ADT_EXTRA_OPTS="$ADT_EXTRA_OPTS -c $CONSOLE"
251 fi
252
253 # Return access information to adt-virt-ssh.
254 cat<<EOF
255identity=$SSH_IDENTITY
256login=$SSH_USER
257hostname=$ipaddr
258capabilities=$CAPABILITIES
259extraopts=$ADT_EXTRA_OPTS
260EOF
261 if [ -n "$SUDO_PASSWORD" ]; then
262 echo "password=$SUDO_PASSWORD"
263 fi
264
265 # wait until ssh is available and cloud-config is done
266 debug "Waiting until ssh becomes available"
267 SSH="ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i /tmp/$SRVNAME/id_rsa -l $SSH_USER $ipaddr"
268 retry=60
269 while ! $SSH true; do
270 retry=$(( retry - 1 ))
271 if [ $retry -le 0 ]; then
272 error "Timed out waiting for ssh. Aborting!"
273 cleanup
274 exit 1
275 fi
276 sleep 5
277 done
278
279 debug "Waiting for cloud-init to finish"
280 if ! timeout 30m $SSH 'while [ ! -e /var/lib/cloud/instance/boot-finished ]; do sleep 1; done'; then
281 error "Timed out waiting for cloud-init to finish. Aborting!"
282 cleanup
283 exit 1
284 fi
285
286}
287
288cleanup() {
289 if [ -z "$SRVNAME" ]; then
290 error "Cannot determine server name. Instance won't be deleted!"
291 exit 0
292 fi
293
294 if [ -n "$CONSOLE" ]; then
295 debug "Saving console-log for $SRVNAME"
296 nova console-log $SRVNAME > $CONSOLE
297 fi
298
299 debug "Deleting $SRVNAME instance"
300 nova delete $SRVNAME || true
301
302 debug "Deleting $SRVNAME keypair"
303 nova keypair-delete $SRVNAME || true
304
305 debug "Deleting /tmp/$SRVNAME SSH keys"
306 rm -rf /tmp/$SRVNAME || true
307
308 DELETE_CMD="neutron security-group-delete $SRVNAME"
309 if ! neutron security-group-list; then
310 DELETE_CMD="nova secgroup-delete $SRVNAME"
311 fi
312
313 debug "Deleting $SRVNAME security-group"
314 retry=3
315 while ! eval "$DELETE_CMD"; do
316 retry=$(( retry - 1 ))
317 if [ $retry -le 0 ]; then
318 error "Timed out deleting secgroup. Aborting!"
319 cleanup
320 exit 1
321 fi
322 sleep 5
323 done
324
325 SRVNAME=""
326}
327
328revert() {
329 if [ -z "$SRVNAME" ]; then
330 echo "Needs to be called with -n <server name>" >&2
331 exit 1
332 fi
333 cleanup
334 open
335}
336
337reboot() {
338 if [ -z "$SRVNAME" ]; then
339 error "Cannot determine server name. Instance won't be rebooted!"
340 exit 1
341 fi
342
343 nova reboot --poll $SRVNAME >/dev/null 2>&1||true
344}
345
346# ########################################
347# Main procedure
348#
349if [ $# -eq 0 ]; then
350 error "Invalid number of arguments, command is missing"
351 exit 1
352fi
353cmd=$(echo $1|tr [[:upper:]] [[:lower:]])
354shift
355parse_args "$@"
356
357# Don't leave stuff behind ...
358trap "cleanup" 1 2 6 15
359
360case $cmd in
361 open)
362 open;;
363 cleanup)
364 cleanup;;
365 revert)
366 revert;;
367 reboot)
368 reboot;;
369 '')
370 echo "Needs to be called with command as first argument" >&2
371 exit 1
372 ;;
373 *)
374 echo "invalid command $cmd" >&2
375 exit 1
376esac

Subscribers

People subscribed via source and target branches

to all changes: