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
=== modified file 'README'
--- README 2013-02-26 00:45:59 +0000
+++ README 2013-04-29 20:44:30 +0000
@@ -14,7 +14,6 @@
14landscape-client:14landscape-client:
15 account-name: <account_name_here>15 account-name: <account_name_here>
16 registration-key: <registration_key_here>16 registration-key: <registration_key_here>
17 computer-title: <computer_title_here>
18 tags: <csv_tag_list>17 tags: <csv_tag_list>
1918
20The following is a version if you need to customize the communication URL19The following is a version if you need to customize the communication URL
@@ -25,12 +24,11 @@
25landscape-client:24landscape-client:
26 account-name: standalone25 account-name: standalone
27 registration-key: 128-qosk-738226 registration-key: 128-qosk-7382
28 computer-title: Dev Laptop 09
29 tags: laptop,precise,developer27 tags: laptop,precise,developer
30 ping-url = http://landscape.example.com/ping28 ping-url: http://landscape.example.com/ping
31 url = https://landscape.example.com/message-system29 url: https://landscape.example.com/message-system
32 script-users = ALL30 script-users: ALL
33 include-manager-plugins = ScriptExecution31 include-manager-plugins: ScriptExecution
34 32
35Configuration33Configuration
36=============34=============
@@ -52,9 +50,6 @@
52registration-key:50registration-key:
53 The account registration key, found in the Landscape account GUI. 51 The account registration key, found in the Landscape account GUI.
5452
55computer-title:
56 Human readable title for your computer.
57
58tags:53tags:
59 Comma separated list of tags to apply to the computer once it is54 Comma separated list of tags to apply to the computer once it is
60 registered.55 registered.
6156
=== added file 'TESTING'
--- TESTING 1970-01-01 00:00:00 +0000
+++ TESTING 2013-04-29 20:44:30 +0000
@@ -0,0 +1,5 @@
1Simple end-to-end testing can be performed by:
2
3 cd tests
4 make build
5 ./test.sh
06
=== modified file 'config.yaml'
--- config.yaml 2013-02-26 00:45:59 +0000
+++ config.yaml 2013-04-29 20:44:30 +0000
@@ -6,6 +6,7 @@
6 distro (default), ppa:somecustom/ppa or a full APT url source6 distro (default), ppa:somecustom/ppa or a full APT url source
7 entry with optional key. For example:7 entry with optional key. For example:
8 deb https://asf@private-ppa.launchpad.net/myrepo precise main|YOURAPTKEY"8 deb https://asf@private-ppa.launchpad.net/myrepo precise main|YOURAPTKEY"
9 Also supported is a public branch like lp:~landscape/landscape-client/trunk
9 type: string10 type: string
10 data-path:11 data-path:
11 description: |12 description: |
1213
=== modified file 'hooks/common.py'
--- hooks/common.py 2013-03-02 00:05:38 +0000
+++ hooks/common.py 2013-04-29 20:44:30 +0000
@@ -47,7 +47,12 @@
47 stop_client_and_disable_init_script()47 stop_client_and_disable_init_script()
48 self.exit_code = exit_code48 self.exit_code = exit_code
4949
5050def clear_registration():
51 """
52 Do steps necessary to clear the client registration, so that next time
53 it will re-register
54 """
55 stop_client_and_disable_init_script()
5156
52def try_to_register():57def try_to_register():
53 """Try to register the client if needed.58 """Try to register the client if needed.
@@ -58,6 +63,9 @@
58 which means that it's expected that the configuration will be broken63 which means that it's expected that the configuration will be broken
59 at that point.64 at that point.
6065
66 The following keys need to be set for an attempt to be made:
67 - account_name, computer_title
68
61 If an error is encountered, the client will be disabled and the hook69 If an error is encountered, the client will be disabled and the hook
62 calling this function will exit with an error code.70 calling this function will exit with an error code.
63 """71 """
@@ -68,7 +76,11 @@
68 config = LandscapeSetupConfiguration()76 config = LandscapeSetupConfiguration()
69 config.load([])77 config.load([])
70 config.silent = True78 config.silent = True
71 if configured or not config.get("computer_title"):79 if configured:
80 print "Client already registered, skipping"
81 return 0
82 if not config.get("account_name") or not config.get("computer_title"):
83 print "Need account-name and computer-title to proceed, skipping"
72 return 084 return 0
73 try:85 try:
74 setup(config)86 setup(config)
7587
=== added file 'hooks/common.pyc'
76Binary files hooks/common.pyc 1970-01-01 00:00:00 +0000 and hooks/common.pyc 2013-04-29 20:44:30 +0000 differ88Binary files hooks/common.pyc 1970-01-01 00:00:00 +0000 and hooks/common.pyc 2013-04-29 20:44:30 +0000 differ
=== added symlink 'hooks/config-changed'
=== target is u'hooks.py'
=== renamed file 'hooks/config-changed' => 'hooks/hooks.py'
--- hooks/config-changed 2013-02-01 11:55:50 +0000
+++ hooks/hooks.py 2013-04-29 20:44:30 +0000
@@ -3,11 +3,48 @@
3from subprocess import check_output3from subprocess import check_output
4import json4import json
5import sys5import sys
66import os
7from common import update_client_config7import base64
88
99from common import update_client_config, clear_registration
10configs = json.loads(check_output(["config-get", "--format=json"]))10
11if configs:11
12 sys.exit(update_client_config(configs))12def _write_certificate(certificate, filename):
1313 """
14 @param certificate Text of the certificate, base64 encoded.
15 @param filename Full path to file to write
16 """
17 with open(filename, "w") as file:
18 file.write(base64.b64decode(certificate))
19
20def _registration_relation():
21 cert_file = "/etc/ssl/certs/landscape_server_ca.crt"
22 data = json.loads(check_output(["relation-get", "--format=json"]))
23 if "ssl-public-key" in data:
24 _write_certificate(data["ssl-public-key"], cert_file)
25 data["ssl-public-key"] = cert_file
26 if "ping-url" in data:
27 config_changed(relation_data=data)
28
29def config_changed(relation_data={}):
30 """
31 @param relation_data: data from the context of a relation, it should
32 match the data in the config
33 """
34 configs = json.loads(check_output(["config-get", "--format=json"]))
35 relation_data.update(configs)
36 if 'account-name' in relation_data:
37 sys.exit(update_client_config(relation_data))
38
39def registration_relation_joined():
40 _registration_relation();
41
42def registration_relation_changed():
43 _registration_relation();
44
45def registration_relation_departed():
46 clear_registration()
47
48if __name__ == "__main__":
49 hook = os.path.basename(sys.argv[0]).replace("-", "_")
50 eval("%s()" % hook)
1451
=== modified file 'hooks/install'
--- hooks/install 2013-02-27 00:16:45 +0000
+++ hooks/install 2013-04-29 20:44:30 +0000
@@ -45,6 +45,17 @@
45 chmod go+r $SOURCES_FILE45 chmod go+r $SOURCES_FILE
46 return46 return
47 ;;47 ;;
48 lp*)
49 rm -rf landscape-client-source; bzr branch $src landscape-client-source
50 cd landscape-client-source
51 apt_get install devscripts
52 apt_get build-dep landscape-client
53 DEBUILD_OPTS="-uc -us" make package
54 dpkg -i ../landscape-client_* ../landscape-common_* || /bin/true
55 apt_get -f install
56 cd ../
57 # Should no-op the install later.
58 ;;
48 *)59 *)
49 echo "Invalid repository origin specified: '" $src "'"60 echo "Invalid repository origin specified: '" $src "'"
50 ;;61 ;;
5162
=== added symlink 'hooks/registration-relation-changed'
=== target is u'hooks.py'
=== added symlink 'hooks/registration-relation-departed'
=== target is u'hooks.py'
=== added symlink 'hooks/registration-relation-joined'
=== target is u'hooks.py'
=== modified file 'metadata.yaml'
--- metadata.yaml 2013-02-08 17:37:09 +0000
+++ metadata.yaml 2013-04-29 20:44:30 +0000
@@ -11,3 +11,5 @@
11 container:11 container:
12 interface: juju-info12 interface: juju-info
13 scope: container13 scope: container
14 registration:
15 interface: http
1416
=== modified file 'revision'
--- revision 2013-03-07 20:22:30 +0000
+++ revision 2013-04-29 20:44:30 +0000
@@ -1,1 +1,1 @@
19110
22
=== added directory 'tests'
=== added file 'tests/001_install.test'
--- tests/001_install.test 1970-01-01 00:00:00 +0000
+++ tests/001_install.test 2013-04-29 20:44:30 +0000
@@ -0,0 +1,95 @@
1#!/bin/bash -eu
2
3source lib/test-helpers.sh
4
5test_setup() {
6 echo "INFO: Setup Test Environment"
7 juju deploy ubuntu
8 juju deploy --repository . local:landscape-client
9 juju add-relation ubuntu landscape-client
10}
11
12teardown() {
13 echo "INFO: Starting Teardown"
14 juju destroy-service ubuntu || /bin/true
15 juju destroy-service landscape-client || /bin/true
16}
17
18assert_command_on_unit() {
19 # Assert the command succeeds on the unit
20 # $1 = unit to contact
21 # $2 = command
22 if ! juju ssh $1 "$2"; then
23 error "CMD: $2 failed in $(diagnose)"
24 exit 1
25 fi
26}
27
28run_command_on_unit() {
29 juju ssh $1 "$2"
30}
31
32assert_config() {
33 # $1 = config
34 # $2 and on = list of strings to run through egrep
35 config=$1
36 shift
37 while [ $# -gt 0 ]; do
38 if ! echo "$config" | egrep "$1"; then
39 error "Config incorrect or missing: $1\n$(diagnose)"
40 exit 1
41 fi
42 shift
43 done
44}
45
46
47start-test "landscape-client add relation verify deploy"
48
49teardown
50test_setup
51
52# Ensure ubuntu started, and landscape-client is related without error
53jitsu watch --failfast \
54 ubuntu --state=started -r "ubuntu landscape-client" \
55 landscape-client --state=started
56
57
58# Ensure all ubuntu service units look as expected (unregistered)
59for i in $(jitsu get-service-info ubuntu public-address); do
60 unit=$(echo $i | cut -d: -f1)
61 host=$(echo $i | cut -d: -f2)
62 assert_command_on_unit $unit "ps -ef | grep -v /usr/bin/landscape-client"
63 assert_command_on_unit $unit "test -e /etc/landscape/client.conf"
64 assert_command_on_unit $unit "sudo cat /etc/landscape/client.conf"
65 assert_command_on_unit $unit "sudo grep computer_title /etc/landscape/client.conf | grep $unit"
66done
67
68# Set appropriate config for testing
69juju set --config lib/test-config.yaml landscape-client
70
71# We expect error since we aren't actually going to register the client
72jitsu watch \
73 landscape-client --state=configure-error
74
75# Ensure all ubuntu service units look as expected (registration-attempt)
76for i in $(jitsu get-service-info ubuntu public-address); do
77 unit=$(echo $i | cut -d: -f1)
78 host=$(echo $i | cut -d: -f2)
79 assert_command_on_unit $unit "ps -ef | grep -v /usr/bin/landscape-client"
80 assert_command_on_unit $unit "test -e /etc/landscape/client.conf"
81 config=$(run_command_on_unit $unit "sudo cat /etc/landscape/client.conf")
82 assert_config "$config" \
83 "ping_url = http://foo.example.com/ping" \
84 "data_path = /var/lib/landscape/client" \
85 "computer_title = $unit" \
86 "tags = foo,bar,baz" \
87 "registration_password = foo-registration-key" \
88 "url = https://foo.example.com/message-system" \
89 "include_manager_plugins = ScriptExecution" \
90 "script_users = ALL" \
91 "registration_key = foo-registration-key" \
92 "account_name = foo-account-name"
93done
94
95end-test "Deployed Successfully"
096
=== added file 'tests/Makefile'
--- tests/Makefile 1970-01-01 00:00:00 +0000
+++ tests/Makefile 2013-04-29 20:44:30 +0000
@@ -0,0 +1,8 @@
1build:
2 @mkdir -p precise
3 @test -e precise/landscape-client || ln -sf ../ precise/landscape-client
4 @echo "- Checking juju status, to make sure juju bootstrap has been done"
5 @juju status > /dev/null 2>/dev/null
6
7test:
8 ./install-test
09
=== added directory 'tests/lib'
=== added file 'tests/lib/test-config.yaml'
--- tests/lib/test-config.yaml 1970-01-01 00:00:00 +0000
+++ tests/lib/test-config.yaml 2013-04-29 20:44:30 +0000
@@ -0,0 +1,8 @@
1landscape-client:
2 account-name: foo-account-name
3 registration-key: foo-registration-key
4 tags: foo,bar,baz
5 ping-url: http://foo.example.com/ping
6 url: https://foo.example.com/message-system
7 script-users: ALL
8 include-manager-plugins: ScriptExecution
09
=== added file 'tests/lib/test-helpers.sh'
--- tests/lib/test-helpers.sh 1970-01-01 00:00:00 +0000
+++ tests/lib/test-helpers.sh 2013-04-29 20:44:30 +0000
@@ -0,0 +1,114 @@
1#!/bin/bash
2
3set -eu
4
5# Test setup
6readonly TEST_NAME=$0
7
8# Test counts. Neither skips or errors are necessarily fatal.
9SKIPS=0
10ERRORS=0
11UNHANDLED=0
12
13
14function info() {
15 echo "INFO: $@"
16}
17
18function ok() {
19 echo "PASS: $@"
20}
21
22function skip() {
23 echo "SKIP: $@"
24 (( SKIPS +=1 ))
25}
26
27function error() {
28 echo "FAIL: $@"
29 (( ERRORS += 1 ))
30}
31
32
33function start-test() {
34 readonly DATADIR=$(mktemp -d --tmpdir "${TEST_NAME}.XXXXXXX")
35 info "Executing ${TEST_NAME} with results in $DATADIR: $1"
36 setup
37 trap trapped-teardown EXIT TERM INT
38}
39
40function setup() {
41 # Empty, override in actual test as needed
42 true
43}
44
45
46function end-test() {
47 info "Completed test $TEST_NAME"
48 trap - EXIT
49 test-teardown
50}
51
52
53function teardown() {
54 # Empty, override in actual test as needed
55 true
56}
57
58
59function test-teardown() {
60 teardown
61
62 if [[ "$ERRORS" -gt 0 ]] ; then
63 TEST_RESULT=1
64 elif [[ "$SKIPS" -gt 0 ]] ; then
65 TEST_RESULT=100
66 touch $DATADIR/passed
67 else
68 TEST_RESULT=0
69 touch $DATADIR/passed
70 fi
71
72 if [ -n "$DATADIR" ] ; then
73 if [ -f $DATADIR/passed ]; then
74 info "Passed test results for ${TEST_NAME} in ${DATADIR}, skips=${SKIPS}"
75 # rm -r $DATADIR
76 else
77 info "Failed test results for ${TEST_NAME} in ${DATADIR}, errors=${ERRORS}, skips=${SKIPS}"
78 if [ -f $DATADIR/wget.log ] ; then
79 info "BEGIN wget.log"
80 cat $DATADIR/wget.log
81 info "END wget.log"
82 fi
83 fi
84 fi
85 exit $TEST_RESULT
86}
87
88
89function diagnose() {
90 # Unpack the caller info to get some useful diagnostics for
91 # tracing any assertion issues
92 local data=( $(caller 1) )
93 local lineno=${data[0]}
94 local function_name=${data[1]}
95 local script_name=${data[2]}
96 echo "function $function_name at line $lineno ($script_name)"
97}
98
99function trapped-teardown() {
100 (( UNHANDLED += 1 ))
101 error "Untrapped error in $(diagnose)"
102 test-teardown
103}
104
105function assert() {
106 # The assert function takes two args, such as:
107 # assert "what we are asserting" "non empty result passes"
108 # If the second arg is empty or undefined, the assertion fails
109 if [[ "$#" -lt 2 || -z "$2" ]] ; then
110 error "$1, assertion failed in $(diagnose)"
111 else
112 ok "$1"
113 fi
114}
0115
=== added directory 'tests/precise'
=== added symlink 'tests/precise/landscape-client'
=== target is u'../..'
=== added file 'tests/test.sh'
--- tests/test.sh 1970-01-01 00:00:00 +0000
+++ tests/test.sh 2013-04-29 20:44:30 +0000
@@ -0,0 +1,6 @@
1#!/bin/bash -e
2
3DIR="$( cd "$( dirname "$0" )" && pwd )"
4cd $DIR
5
6run-parts -v --exit-on-error --regex '^.*\.test$' .

Subscribers

People subscribed via source and target branches