Merge lp:~dpb/charms/precise/landscape-client/add-landscape-relation into lp:~charmers/charms/precise/landscape-client/trunk

Proposed by David Britton
Status: Merged
Merged at revision: 22
Proposed branch: lp:~dpb/charms/precise/landscape-client/add-landscape-relation
Merge into: lp:~charmers/charms/precise/landscape-client/trunk
Diff against target: 472 lines (+314/-20)
13 files modified
README (+4/-9)
TESTING (+5/-0)
config.yaml (+1/-0)
hooks/common.py (+14/-2)
hooks/hooks.py (+45/-8)
hooks/install (+11/-0)
metadata.yaml (+2/-0)
revision (+1/-1)
tests/001_install.test (+95/-0)
tests/Makefile (+8/-0)
tests/lib/test-config.yaml (+8/-0)
tests/lib/test-helpers.sh (+114/-0)
tests/test.sh (+6/-0)
To merge this branch: bzr merge lp:~dpb/charms/precise/landscape-client/add-landscape-relation
Reviewer Review Type Date Requested Status
Marco Ceppi (community) Approve
Review via email: mp+161497@code.launchpad.net

Description of the change

- Main change: allow association to a landscape-server via relation. This is mostly useful for testing, but could be useful in the future for rapid deployment into an environment that already has a landscape server (which there is no public charm for yet)
- Update README with a couple changes I noticed during testing.
- Add 'tests/' jitsu-test-style test case. Still need to work with m_3 to figure out a couple oddities with it, but it does work for me at least
- centralize hooks into a hooks.py with symlinks
- Add ability to install from a branch (lp: syntax)

To post a comment you must log in.
Revision history for this message
Marco Ceppi (marcoceppi) wrote :

Hi David, sorry it took so long to get around to this. So I'll be brief with the review. This LGTM! Thank you for supplying tests. I've got some more information for you below.

So, we're going to be dropping jitsu very soon as a lot of it isn't compatible with juju-core. I'm working on a real set of testing-helpers ("testing harness") that will replace jitsu-watch and test-helpers.sh with a more robust bash/python library. Keep an eye on the list for more information on that next week. I don't see it necessary to change what you have here but just be aware in the next few months as we move our automated testing environment from just pyjuju to both pyjuju + juju-core and eventually just juju-core that these tests will need to be amended.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'README'
2--- README 2013-02-26 00:45:59 +0000
3+++ README 2013-04-29 20:44:30 +0000
4@@ -14,7 +14,6 @@
5 landscape-client:
6 account-name: <account_name_here>
7 registration-key: <registration_key_here>
8- computer-title: <computer_title_here>
9 tags: <csv_tag_list>
10
11 The following is a version if you need to customize the communication URL
12@@ -25,12 +24,11 @@
13 landscape-client:
14 account-name: standalone
15 registration-key: 128-qosk-7382
16- computer-title: Dev Laptop 09
17 tags: laptop,precise,developer
18- ping-url = http://landscape.example.com/ping
19- url = https://landscape.example.com/message-system
20- script-users = ALL
21- include-manager-plugins = ScriptExecution
22+ ping-url: http://landscape.example.com/ping
23+ url: https://landscape.example.com/message-system
24+ script-users: ALL
25+ include-manager-plugins: ScriptExecution
26
27 Configuration
28 =============
29@@ -52,9 +50,6 @@
30 registration-key:
31 The account registration key, found in the Landscape account GUI.
32
33-computer-title:
34- Human readable title for your computer.
35-
36 tags:
37 Comma separated list of tags to apply to the computer once it is
38 registered.
39
40=== added file 'TESTING'
41--- TESTING 1970-01-01 00:00:00 +0000
42+++ TESTING 2013-04-29 20:44:30 +0000
43@@ -0,0 +1,5 @@
44+Simple end-to-end testing can be performed by:
45+
46+ cd tests
47+ make build
48+ ./test.sh
49
50=== modified file 'config.yaml'
51--- config.yaml 2013-02-26 00:45:59 +0000
52+++ config.yaml 2013-04-29 20:44:30 +0000
53@@ -6,6 +6,7 @@
54 distro (default), ppa:somecustom/ppa or a full APT url source
55 entry with optional key. For example:
56 deb https://asf@private-ppa.launchpad.net/myrepo precise main|YOURAPTKEY"
57+ Also supported is a public branch like lp:~landscape/landscape-client/trunk
58 type: string
59 data-path:
60 description: |
61
62=== modified file 'hooks/common.py'
63--- hooks/common.py 2013-03-02 00:05:38 +0000
64+++ hooks/common.py 2013-04-29 20:44:30 +0000
65@@ -47,7 +47,12 @@
66 stop_client_and_disable_init_script()
67 self.exit_code = exit_code
68
69-
70+def clear_registration():
71+ """
72+ Do steps necessary to clear the client registration, so that next time
73+ it will re-register
74+ """
75+ stop_client_and_disable_init_script()
76
77 def try_to_register():
78 """Try to register the client if needed.
79@@ -58,6 +63,9 @@
80 which means that it's expected that the configuration will be broken
81 at that point.
82
83+ The following keys need to be set for an attempt to be made:
84+ - account_name, computer_title
85+
86 If an error is encountered, the client will be disabled and the hook
87 calling this function will exit with an error code.
88 """
89@@ -68,7 +76,11 @@
90 config = LandscapeSetupConfiguration()
91 config.load([])
92 config.silent = True
93- if configured or not config.get("computer_title"):
94+ if configured:
95+ print "Client already registered, skipping"
96+ return 0
97+ if not config.get("account_name") or not config.get("computer_title"):
98+ print "Need account-name and computer-title to proceed, skipping"
99 return 0
100 try:
101 setup(config)
102
103=== added file 'hooks/common.pyc'
104Binary files hooks/common.pyc 1970-01-01 00:00:00 +0000 and hooks/common.pyc 2013-04-29 20:44:30 +0000 differ
105=== added symlink 'hooks/config-changed'
106=== target is u'hooks.py'
107=== renamed file 'hooks/config-changed' => 'hooks/hooks.py'
108--- hooks/config-changed 2013-02-01 11:55:50 +0000
109+++ hooks/hooks.py 2013-04-29 20:44:30 +0000
110@@ -3,11 +3,48 @@
111 from subprocess import check_output
112 import json
113 import sys
114-
115-from common import update_client_config
116-
117-
118-configs = json.loads(check_output(["config-get", "--format=json"]))
119-if configs:
120- sys.exit(update_client_config(configs))
121-
122+import os
123+import base64
124+
125+from common import update_client_config, clear_registration
126+
127+
128+def _write_certificate(certificate, filename):
129+ """
130+ @param certificate Text of the certificate, base64 encoded.
131+ @param filename Full path to file to write
132+ """
133+ with open(filename, "w") as file:
134+ file.write(base64.b64decode(certificate))
135+
136+def _registration_relation():
137+ cert_file = "/etc/ssl/certs/landscape_server_ca.crt"
138+ data = json.loads(check_output(["relation-get", "--format=json"]))
139+ if "ssl-public-key" in data:
140+ _write_certificate(data["ssl-public-key"], cert_file)
141+ data["ssl-public-key"] = cert_file
142+ if "ping-url" in data:
143+ config_changed(relation_data=data)
144+
145+def config_changed(relation_data={}):
146+ """
147+ @param relation_data: data from the context of a relation, it should
148+ match the data in the config
149+ """
150+ configs = json.loads(check_output(["config-get", "--format=json"]))
151+ relation_data.update(configs)
152+ if 'account-name' in relation_data:
153+ sys.exit(update_client_config(relation_data))
154+
155+def registration_relation_joined():
156+ _registration_relation();
157+
158+def registration_relation_changed():
159+ _registration_relation();
160+
161+def registration_relation_departed():
162+ clear_registration()
163+
164+if __name__ == "__main__":
165+ hook = os.path.basename(sys.argv[0]).replace("-", "_")
166+ eval("%s()" % hook)
167
168=== modified file 'hooks/install'
169--- hooks/install 2013-02-27 00:16:45 +0000
170+++ hooks/install 2013-04-29 20:44:30 +0000
171@@ -45,6 +45,17 @@
172 chmod go+r $SOURCES_FILE
173 return
174 ;;
175+ lp*)
176+ rm -rf landscape-client-source; bzr branch $src landscape-client-source
177+ cd landscape-client-source
178+ apt_get install devscripts
179+ apt_get build-dep landscape-client
180+ DEBUILD_OPTS="-uc -us" make package
181+ dpkg -i ../landscape-client_* ../landscape-common_* || /bin/true
182+ apt_get -f install
183+ cd ../
184+ # Should no-op the install later.
185+ ;;
186 *)
187 echo "Invalid repository origin specified: '" $src "'"
188 ;;
189
190=== added symlink 'hooks/registration-relation-changed'
191=== target is u'hooks.py'
192=== added symlink 'hooks/registration-relation-departed'
193=== target is u'hooks.py'
194=== added symlink 'hooks/registration-relation-joined'
195=== target is u'hooks.py'
196=== modified file 'metadata.yaml'
197--- metadata.yaml 2013-02-08 17:37:09 +0000
198+++ metadata.yaml 2013-04-29 20:44:30 +0000
199@@ -11,3 +11,5 @@
200 container:
201 interface: juju-info
202 scope: container
203+ registration:
204+ interface: http
205
206=== modified file 'revision'
207--- revision 2013-03-07 20:22:30 +0000
208+++ revision 2013-04-29 20:44:30 +0000
209@@ -1,1 +1,1 @@
210-9
211+10
212
213=== added directory 'tests'
214=== added file 'tests/001_install.test'
215--- tests/001_install.test 1970-01-01 00:00:00 +0000
216+++ tests/001_install.test 2013-04-29 20:44:30 +0000
217@@ -0,0 +1,95 @@
218+#!/bin/bash -eu
219+
220+source lib/test-helpers.sh
221+
222+test_setup() {
223+ echo "INFO: Setup Test Environment"
224+ juju deploy ubuntu
225+ juju deploy --repository . local:landscape-client
226+ juju add-relation ubuntu landscape-client
227+}
228+
229+teardown() {
230+ echo "INFO: Starting Teardown"
231+ juju destroy-service ubuntu || /bin/true
232+ juju destroy-service landscape-client || /bin/true
233+}
234+
235+assert_command_on_unit() {
236+ # Assert the command succeeds on the unit
237+ # $1 = unit to contact
238+ # $2 = command
239+ if ! juju ssh $1 "$2"; then
240+ error "CMD: $2 failed in $(diagnose)"
241+ exit 1
242+ fi
243+}
244+
245+run_command_on_unit() {
246+ juju ssh $1 "$2"
247+}
248+
249+assert_config() {
250+ # $1 = config
251+ # $2 and on = list of strings to run through egrep
252+ config=$1
253+ shift
254+ while [ $# -gt 0 ]; do
255+ if ! echo "$config" | egrep "$1"; then
256+ error "Config incorrect or missing: $1\n$(diagnose)"
257+ exit 1
258+ fi
259+ shift
260+ done
261+}
262+
263+
264+start-test "landscape-client add relation verify deploy"
265+
266+teardown
267+test_setup
268+
269+# Ensure ubuntu started, and landscape-client is related without error
270+jitsu watch --failfast \
271+ ubuntu --state=started -r "ubuntu landscape-client" \
272+ landscape-client --state=started
273+
274+
275+# Ensure all ubuntu service units look as expected (unregistered)
276+for i in $(jitsu get-service-info ubuntu public-address); do
277+ unit=$(echo $i | cut -d: -f1)
278+ host=$(echo $i | cut -d: -f2)
279+ assert_command_on_unit $unit "ps -ef | grep -v /usr/bin/landscape-client"
280+ assert_command_on_unit $unit "test -e /etc/landscape/client.conf"
281+ assert_command_on_unit $unit "sudo cat /etc/landscape/client.conf"
282+ assert_command_on_unit $unit "sudo grep computer_title /etc/landscape/client.conf | grep $unit"
283+done
284+
285+# Set appropriate config for testing
286+juju set --config lib/test-config.yaml landscape-client
287+
288+# We expect error since we aren't actually going to register the client
289+jitsu watch \
290+ landscape-client --state=configure-error
291+
292+# Ensure all ubuntu service units look as expected (registration-attempt)
293+for i in $(jitsu get-service-info ubuntu public-address); do
294+ unit=$(echo $i | cut -d: -f1)
295+ host=$(echo $i | cut -d: -f2)
296+ assert_command_on_unit $unit "ps -ef | grep -v /usr/bin/landscape-client"
297+ assert_command_on_unit $unit "test -e /etc/landscape/client.conf"
298+ config=$(run_command_on_unit $unit "sudo cat /etc/landscape/client.conf")
299+ assert_config "$config" \
300+ "ping_url = http://foo.example.com/ping" \
301+ "data_path = /var/lib/landscape/client" \
302+ "computer_title = $unit" \
303+ "tags = foo,bar,baz" \
304+ "registration_password = foo-registration-key" \
305+ "url = https://foo.example.com/message-system" \
306+ "include_manager_plugins = ScriptExecution" \
307+ "script_users = ALL" \
308+ "registration_key = foo-registration-key" \
309+ "account_name = foo-account-name"
310+done
311+
312+end-test "Deployed Successfully"
313
314=== added file 'tests/Makefile'
315--- tests/Makefile 1970-01-01 00:00:00 +0000
316+++ tests/Makefile 2013-04-29 20:44:30 +0000
317@@ -0,0 +1,8 @@
318+build:
319+ @mkdir -p precise
320+ @test -e precise/landscape-client || ln -sf ../ precise/landscape-client
321+ @echo "- Checking juju status, to make sure juju bootstrap has been done"
322+ @juju status > /dev/null 2>/dev/null
323+
324+test:
325+ ./install-test
326
327=== added directory 'tests/lib'
328=== added file 'tests/lib/test-config.yaml'
329--- tests/lib/test-config.yaml 1970-01-01 00:00:00 +0000
330+++ tests/lib/test-config.yaml 2013-04-29 20:44:30 +0000
331@@ -0,0 +1,8 @@
332+landscape-client:
333+ account-name: foo-account-name
334+ registration-key: foo-registration-key
335+ tags: foo,bar,baz
336+ ping-url: http://foo.example.com/ping
337+ url: https://foo.example.com/message-system
338+ script-users: ALL
339+ include-manager-plugins: ScriptExecution
340
341=== added file 'tests/lib/test-helpers.sh'
342--- tests/lib/test-helpers.sh 1970-01-01 00:00:00 +0000
343+++ tests/lib/test-helpers.sh 2013-04-29 20:44:30 +0000
344@@ -0,0 +1,114 @@
345+#!/bin/bash
346+
347+set -eu
348+
349+# Test setup
350+readonly TEST_NAME=$0
351+
352+# Test counts. Neither skips or errors are necessarily fatal.
353+SKIPS=0
354+ERRORS=0
355+UNHANDLED=0
356+
357+
358+function info() {
359+ echo "INFO: $@"
360+}
361+
362+function ok() {
363+ echo "PASS: $@"
364+}
365+
366+function skip() {
367+ echo "SKIP: $@"
368+ (( SKIPS +=1 ))
369+}
370+
371+function error() {
372+ echo "FAIL: $@"
373+ (( ERRORS += 1 ))
374+}
375+
376+
377+function start-test() {
378+ readonly DATADIR=$(mktemp -d --tmpdir "${TEST_NAME}.XXXXXXX")
379+ info "Executing ${TEST_NAME} with results in $DATADIR: $1"
380+ setup
381+ trap trapped-teardown EXIT TERM INT
382+}
383+
384+function setup() {
385+ # Empty, override in actual test as needed
386+ true
387+}
388+
389+
390+function end-test() {
391+ info "Completed test $TEST_NAME"
392+ trap - EXIT
393+ test-teardown
394+}
395+
396+
397+function teardown() {
398+ # Empty, override in actual test as needed
399+ true
400+}
401+
402+
403+function test-teardown() {
404+ teardown
405+
406+ if [[ "$ERRORS" -gt 0 ]] ; then
407+ TEST_RESULT=1
408+ elif [[ "$SKIPS" -gt 0 ]] ; then
409+ TEST_RESULT=100
410+ touch $DATADIR/passed
411+ else
412+ TEST_RESULT=0
413+ touch $DATADIR/passed
414+ fi
415+
416+ if [ -n "$DATADIR" ] ; then
417+ if [ -f $DATADIR/passed ]; then
418+ info "Passed test results for ${TEST_NAME} in ${DATADIR}, skips=${SKIPS}"
419+ # rm -r $DATADIR
420+ else
421+ info "Failed test results for ${TEST_NAME} in ${DATADIR}, errors=${ERRORS}, skips=${SKIPS}"
422+ if [ -f $DATADIR/wget.log ] ; then
423+ info "BEGIN wget.log"
424+ cat $DATADIR/wget.log
425+ info "END wget.log"
426+ fi
427+ fi
428+ fi
429+ exit $TEST_RESULT
430+}
431+
432+
433+function diagnose() {
434+ # Unpack the caller info to get some useful diagnostics for
435+ # tracing any assertion issues
436+ local data=( $(caller 1) )
437+ local lineno=${data[0]}
438+ local function_name=${data[1]}
439+ local script_name=${data[2]}
440+ echo "function $function_name at line $lineno ($script_name)"
441+}
442+
443+function trapped-teardown() {
444+ (( UNHANDLED += 1 ))
445+ error "Untrapped error in $(diagnose)"
446+ test-teardown
447+}
448+
449+function assert() {
450+ # The assert function takes two args, such as:
451+ # assert "what we are asserting" "non empty result passes"
452+ # If the second arg is empty or undefined, the assertion fails
453+ if [[ "$#" -lt 2 || -z "$2" ]] ; then
454+ error "$1, assertion failed in $(diagnose)"
455+ else
456+ ok "$1"
457+ fi
458+}
459
460=== added directory 'tests/precise'
461=== added symlink 'tests/precise/landscape-client'
462=== target is u'../..'
463=== added file 'tests/test.sh'
464--- tests/test.sh 1970-01-01 00:00:00 +0000
465+++ tests/test.sh 2013-04-29 20:44:30 +0000
466@@ -0,0 +1,6 @@
467+#!/bin/bash -e
468+
469+DIR="$( cd "$( dirname "$0" )" && pwd )"
470+cd $DIR
471+
472+run-parts -v --exit-on-error --regex '^.*\.test$' .

Subscribers

People subscribed via source and target branches