Merge ~mthaddon/charm-test/+git/charm-test:python3 into charm-test:master

Proposed by Tom Haddon
Status: Merged
Approved by: Tom Haddon
Approved revision: b14673a92e1676f35cab077296022381075e5774
Merged at revision: d882026f697f9aaac50ec38c0c946cc6c913c6e6
Proposed branch: ~mthaddon/charm-test/+git/charm-test:python3
Merge into: charm-test:master
Diff against target: 282 lines (+153/-108)
3 files modified
Makefile (+2/-0)
charm-test (+150/-108)
charm-test.py (+1/-0)
Reviewer Review Type Date Requested Status
Stuart Bishop (community) Approve
Review via email: mp+345155@code.launchpad.net

Commit message

Rewrite in python3

Description of the change

Rewrite in python3

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
Stuart Bishop (stub) wrote :

Comments inline.

All landable as is, with tweaks from comments in future branches.

review: Approve
Revision history for this message
Tom Haddon (mthaddon) :
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision d882026f697f9aaac50ec38c0c946cc6c913c6e6

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/Makefile b/Makefile
2new file mode 100644
3index 0000000..f8db829
4--- /dev/null
5+++ b/Makefile
6@@ -0,0 +1,2 @@
7+lint:
8+ @find . -name \*.py -exec python /usr/bin/flake8 --config=/dev/null --max-line-length=120 --max-complexity=10 --hang-closing {} +
9diff --git a/charm-test b/charm-test
10index e290ccb..97be0ca 100755
11--- a/charm-test
12+++ b/charm-test
13@@ -1,111 +1,153 @@
14-#!/bin/bash
15-
16-# Script to run lint and test suite inside LXC. Expects to be run from the
17-# root of a charm directory.
18-
19-function usage() {
20- echo "$0 [controller-name] [container-name] [juju-model-name]"
21- echo ""
22- echo " controller-name: the name of a pre-configured Juju 2 controller to"
23- echo " run tests against (defaults to currently selected)"
24- echo " container-name: optional name of LXC container to create (defaults"
25- echo " to charm-test)"
26- echo " juju-model-name: optional name of juju model to create and use"
27- echo " (defaults to charm-test)"
28- echo ""
29- echo " Examples:"
30- echo " $0"
31- echo " $0 my-aws-controller"
32- echo " $0 my-aws-controller my-graylog-container"
33- echo " $0 my-aws-controller my-graylog-container my-juju-model"
34- echo ""
35- echo "This script will:"
36- echo " 1. Create an LXC, install all bundletester dependencies."
37- echo " 2. Copy charm source into LXC."
38- echo " 3. Run charm build in LXC."
39- echo " 4. Copy Juju credentials into the LXC."
40- echo " 5. Run bundletester tests on the specified Juju controller from"
41- echo " within the LXC. This includes creating a Juju model to run"
42- echo " tests against."
43- echo ""
44- exit 1
45-}
46-
47-if [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]]; then
48- usage
49-fi
50-
51-set -eu
52-
53-CONTROLLER_NAME=${1:-$(juju switch | cut -d: -f1)}
54-CONTAINER_NAME=${2:-charm-test}
55-JUJU_MODEL_NAME=${3:-charm-test}
56-
57-function log_info() {
58- echo "$(date '+%Y-%m-%d %H:%M:%S') INFO: $1"
59-}
60-
61-function lxc_run() {
62- cmd=$1
63- log_info "Running command \"${cmd}\" in container \"${CONTAINER_NAME}\" as root"
64- lxc exec ${CONTAINER_NAME} -- bash -c "${cmd}"
65-}
66-
67-function lxc_run_as_ubuntu() {
68- cmd=$1
69- log_info "Running command \"${cmd}\" in container \"${CONTAINER_NAME}\" as ubuntu"
70- lxc exec ${CONTAINER_NAME} -- sudo -u ubuntu -i -- ${cmd}
71-}
72-
73-function recreate_lxc() {
74- set +e
75- log_info "Checking if container exists"
76- lxc list | grep ${CONTAINER_NAME}
77- if [ $? -eq 0 ]; then
78- log_info "Found old container, deleting"
79- lxc delete --force ${CONTAINER_NAME}
80- fi
81- set -e
82- lxc launch ubuntu:16.04 ${CONTAINER_NAME}
83- # We shouldn't need to just wait here, but there doesn't appear to be an
84- # lxc wait command.
85- log_info "Sleeping for 20 seconds while LXC comes up with networking"
86- sleep 20
87- # First of all, copy the current charm directory into the LXC.
88- lxc_run_as_ubuntu "mkdir -p /home/ubuntu/charmsrc"
89- tar cf - . | lxc exec ${CONTAINER_NAME} -- tar xvf - -C /home/ubuntu/charmsrc
90+#!/usr/bin/python3
91+
92+# Copyright (c) 2018 Canonical Ltd
93+# License: GPLv3
94+# Author: Tom Haddon <tom.haddon@canonical.com>
95+
96+import argparse
97+import datetime
98+import os
99+import subprocess
100+import time
101+import yaml
102+
103+# Script to run lint and test suite inside LXC in a stanardized way.
104+# This script will:
105+# 1. Create an LXC, install test dependencies as defined by the charm's
106+# Makefile.
107+# 2. Copy charm source into the LXC.
108+# 3. Run charm build in the LXC.
109+# 4. Copy Juju credentials into the LXC.
110+# 5. Run make test. Any Juju operations will use the specified Juju contoller.
111+
112+
113+def _get_default_controller():
114+ """If we don't specify a controller, return currently selected"""
115+ output_list = subprocess.check_output(['juju', 'switch'], universal_newlines=True).split(":")
116+ if len(output_list) != 2:
117+ raise Exception("Unexpected output from juju switch: {}".format(":".join(output_list)))
118+ return output_list[0]
119+
120+
121+def print_log(msg, level="INFO"):
122+ print("{} {} {}".format(level, datetime.datetime.now(), msg))
123+
124+
125+def find_charm(args):
126+ metadata_yaml = os.path.join(args.charm_directory, 'metadata.yaml')
127+ if not os.path.exists(metadata_yaml):
128+ raise Exception("Unable to find metadata.yaml in directory, got: {}".format(metadata_yaml))
129+ parsed_metadata = yaml.safe_load(open(metadata_yaml, 'r').read())
130+ return parsed_metadata["name"]
131+
132+
133+def lxc_run(cmd, args):
134+ print_log('Running command "{}" in container "{}" as root'.format(" ".join(cmd), args.container_name))
135+ lxc_cmd = ['lxc', 'exec', args.container_name, '--'] + cmd
136+ lxc_run = subprocess.check_output(lxc_cmd, universal_newlines=True)
137+ if lxc_run:
138+ print_log("Output of command: {}".format(lxc_run))
139+
140+
141+def lxc_run_as_ubuntu(cmd, args):
142+ print_log('Running command "{}" in container "{}" as ubuntu'.format(" ".join(cmd), args.container_name))
143+ lxc_cmd = ['lxc', 'exec', args.container_name, '--', 'sudo', '-u', 'ubuntu', '-i', '--'] + cmd
144+ lxc_run = subprocess.check_output(lxc_cmd, universal_newlines=True)
145+ if lxc_run:
146+ print_log("Output of command: {}".format(lxc_run))
147+
148+
149+def recreate_lxc(args):
150+ print_log("Checking if container exists")
151+ lxc_list = subprocess.check_output(['lxc', 'list', args.container_name], universal_newlines=True)
152+ if args.container_name in lxc_list:
153+ print_log("Found old container, deleting...")
154+ deleted = subprocess.check_output(['lxc', 'delete', '--force', args.container_name], universal_newlines=True)
155+ if deleted:
156+ print_log("Output from deletion: {}".format(deleted))
157+ lxc_launch = subprocess.check_output(['lxc', 'launch', 'ubuntu:16.04', args.container_name],
158+ universal_newlines=True)
159+ if lxc_launch:
160+ print_log("Output from LXC creation: {}".format(lxc_launch))
161+ print_log("Sleeping for 20 seconds while LXC comes up with networking")
162+ time.sleep(20)
163+ # Copy the charm directory into the LXC
164+ os.chdir(args.charm_directory)
165+ lxc_run_as_ubuntu(["mkdir", "-p", "/home/ubuntu/charmsrc"], args)
166+ copy_charm_cmd = "tar cf - . | lxc exec {} -- tar xvf - -C /home/ubuntu/charmsrc".format(args.container_name)
167+ copy_charm = subprocess.Popen(copy_charm_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
168+ universal_newlines=True)
169+ output = copy_charm.communicate()[0]
170+ print_log("Output from charm copy: {}".format(output))
171 # Install test dependencies.
172- lxc_run "apt-get update"
173- lxc_run "apt-get install make"
174- lxc_run_as_ubuntu "make -C /home/ubuntu/charmsrc testdeps"
175+ lxc_run(["apt-get", "update"], args)
176+ lxc_run(["apt-get", "install", "make"], args)
177+ lxc_run_as_ubuntu(["make", "-C", "/home/ubuntu/charmsrc", "testdeps"], args)
178 # Build the charm inside the LXC.
179- lxc_run_as_ubuntu "make -C /home/ubuntu/charmsrc charmbuild BUILDDEST=/home/ubuntu/charmbuilt"
180+ lxc_run_as_ubuntu(["make", "-C", "/home/ubuntu/charmsrc", "charmbuild", "BUILDDEST=/home/ubuntu/charmbuilt"],
181+ args)
182 # Copy config for Juju access.
183- lxc_run "mkdir -p /home/ubuntu/.local/share/juju/"
184- cd ~/.local/share/juju && tar cf - . | lxc exec ${CONTAINER_NAME} -- tar xvf - -C /home/ubuntu/.local/share/juju
185- lxc_run "chown -R ubuntu:ubuntu /home/ubuntu/.local/share/juju"
186-}
187-
188-FOUND_CHARM=$(find . -maxdepth 1 -name metadata.yaml | xargs grep '^name' | awk '{print $2}')
189-log_info "About to run charm-test against the \"${FOUND_CHARM}\" charm"
190-
191-log_info "Recreating container \"${CONTAINER_NAME}\""
192-recreate_lxc
193-
194-# Provide a visual break so it's more obvious set up has finished and you're
195-# now looking at output you care about
196-log_info ""
197-log_info "--------------------------------------------"
198-log_info "Set up complete, about to run lint and tests"
199-log_info "--------------------------------------------"
200-log_info ""
201-
202-lxc_run_as_ubuntu "juju add-model -c ${CONTROLLER_NAME} ${JUJU_MODEL_NAME}"
203-# Even though we're running this in the charmsrc directory, because we're
204-# passing in the BUILDDEST variable it'll run tests inside the charm we've
205-# built above.
206-lxc_run_as_ubuntu "make -C /home/ubuntu/charmsrc test BUILDDEST=/home/ubuntu/charmbuilt JUJU_MODEL=${CONTROLLER_NAME}:${JUJU_MODEL_NAME}"
207-
208-log_info "Cleaning up"
209-lxc_run_as_ubuntu "juju destroy-model -y ${CONTROLLER_NAME}:${JUJU_MODEL_NAME}"
210-lxc delete --force ${CONTAINER_NAME}
211+ lxc_run(["mkdir", "-p", "/home/ubuntu/.local/share/juju/"], args)
212+ os.chdir(os.path.expanduser('~/.local/share/juju'))
213+ copy_juju_config_cmd = "tar cf - . | lxc exec {} -- tar xvf - -C /home/ubuntu/.local/share/juju".format(
214+ args.container_name)
215+ copy_juju_config = subprocess.Popen(copy_juju_config_cmd, shell=True, stdout=subprocess.PIPE,
216+ stderr=subprocess.STDOUT, universal_newlines=True)
217+ output = copy_juju_config.communicate()[0]
218+ print_log("Output from Juju config copy: {}".format(output))
219+ lxc_run(["chown", "-R", "ubuntu:ubuntu", "/home/ubuntu/.local/share/juju"], args)
220+
221+
222+def visual_break():
223+ print_log("")
224+ print_log("--------------------------------------------")
225+ print_log("Set up complete, about to run lint and tests")
226+ print_log("--------------------------------------------")
227+ print_log("")
228+
229+
230+def add_juju_model(args):
231+ lxc_run_as_ubuntu(["juju", "add-model", "-c", args.controller_name, args.juju_model_name], args)
232+
233+
234+def run_tests(args):
235+ lxc_run_as_ubuntu(["make", "-C", "/home/ubuntu/charmsrc", "test", "BUILDDEST=/home/ubuntu/charmbuilt",
236+ "JUJU_MODEL={}:{}".format(args.controller_name, args.juju_model_name)], args)
237+
238+
239+def clean_up(args):
240+ print_log("Cleaning up")
241+ lxc_run_as_ubuntu(["juju", "destroy-model", "-y" "{}:{}".format(args.controller_name, args.juju_model_name)],
242+ args)
243+ lxc_delete = subprocess.check_output(['lxc', 'delete', '--force', args.container_name], universal_newlines=True)
244+ if lxc_delete:
245+ print_log("Output of LXC delete: {}".format(lxc_delete))
246+
247+
248+def parse_args():
249+ parser = argparse.ArgumentParser()
250+ parser.add_argument("-d", "--charm-directory", default=".", help="Directory of charm to run tests from (defaults to"
251+ "current working directory).")
252+ parser.add_argument("--controller-name", default=_get_default_controller(),
253+ help="The name of a pre-configured Juju 2 controller to run tests against (defaults to "
254+ "currently selected).")
255+ parser.add_argument("--container-name", default="charm-test", help="optional name of LXC container to create "
256+ "(defaults to 'charm-test')")
257+ parser.add_argument("-j", "--juju-model-name", default="charm-test",
258+ help="optional name of juju model to create and use (defaults to 'charm-test')")
259+ return parser.parse_args()
260+
261+
262+def main():
263+ args = parse_args()
264+ charm = find_charm(args)
265+ print_log("About to run charm-test against the '{}' charm".format(charm))
266+ recreate_lxc(args)
267+ visual_break()
268+ add_juju_model(args)
269+ run_tests(args)
270+ clean_up(args)
271+
272+
273+if __name__ == "__main__":
274+ main()
275diff --git a/charm-test.py b/charm-test.py
276new file mode 120000
277index 0000000..a024413
278--- /dev/null
279+++ b/charm-test.py
280@@ -0,0 +1 @@
281+charm-test
282\ No newline at end of file

Subscribers

People subscribed via source and target branches