launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #10236
[Merge] lp:~bac/lpsetup/juju-lxc into lp:lpsetup
Brad Crittenden has proposed merging lp:~bac/lpsetup/juju-lxc into lp:lpsetup.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~bac/lpsetup/juju-lxc/+merge/116529
Provides a new integration test called juju-lxc.py which replaces lxc.py.
Refactored the integration tests more.
Now both tests take an environment name (must exist in ~/.juju/environments.yaml) and can be run against ec2 or in an lxc locally.
The juju-lxc.py test cannot be run locally at present due to bug 924281.
--
https://code.launchpad.net/~bac/lpsetup/juju-lxc/+merge/116529
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~bac/lpsetup/juju-lxc into lp:lpsetup.
=== modified file '.bzrignore'
--- .bzrignore 2012-06-21 14:37:02 +0000
+++ .bzrignore 2012-07-24 18:29:18 +0000
@@ -10,3 +10,5 @@
MANIFEST
parts
tags
+.emacs.desktop*
+*.log
=== modified file 'README.rst'
--- README.rst 2012-07-18 19:27:07 +0000
+++ README.rst 2012-07-24 18:29:18 +0000
@@ -62,9 +62,39 @@
charm repository from lp:~charmers/charms/precise/ubuntu/trunk. The
test expects your Juju repository to be at ~/juju-charms
-The integration tests use a juju environment named "lpsetup-testing" so
-you must create an appropriately configured juju environment with that
-name before running the tests in ~/.juju/environments.yaml.
+The integration tests use two juju environment named
+"lpsetup-testing-ec2" and "lpsetup-testing-lxc", which run in the
+respective environments. You must create an appropriately
+configured juju environment with that name before running the tests in
+~/.juju/environments.yaml. The two stanzas will look something like:
+
+ lpsetup-testing-ec2:
+ type: ec2
+ access-key: <your EC2 access key>
+ secret-key: <your EC2 secret key>
+ control-bucket: <a unique control bucket name>
+ admin-secret: <your admin secret>
+ default-series: precise
+
+ lpsetup-testing-lxc:
+ type: local
+ data-dir: /tmp/juju-local
+ control-bucket: local-bucket
+ admin-secret: <your admin secret>
+ default-series: precise
+ juju-origin: distro
+
+There are two tests provided and each can run in either environment as
+long as you specify using the '-e' command line option. The tests
+are:
+
+lpsetup/tests/integration/non-lxc.py
+lpsetup/tests/integration/juju-lxc.py
+
+The first only tests the *init-host* command but goes no further.
+The second tests *install-lxc*. Due to bug 924281 (supposedly
+*fix-released* but still seen) this test cannot currently be run in an
+lxc container as it would require an lxc inside an lxc.
The tests bootstrap the environment for you and fail if it is already
running.
=== modified file 'lpsetup/subcommands/inithost.py'
--- lpsetup/subcommands/inithost.py 2012-07-20 14:49:59 +0000
+++ lpsetup/subcommands/inithost.py 2012-07-24 18:29:18 +0000
@@ -194,7 +194,7 @@
# Set up bzr and Launchpad authentication.
call('bzr', 'whoami', formataddr([full_name, email]))
if valid_ssh_keys:
- subprocess.call(['bzr', 'lp-login', lpuser])
+ subprocess.call(['bzr', 'launchpad-login', lpuser])
def initialize_lxc():
=== modified file 'lpsetup/tests/integration/common.py'
--- lpsetup/tests/integration/common.py 2012-07-19 20:58:52 +0000
+++ lpsetup/tests/integration/common.py 2012-07-24 18:29:18 +0000
@@ -11,37 +11,113 @@
import argparse
from datetime import datetime
+from email.Utils import formataddr
+import os
+import time
+from subprocess import (
+ check_call as check_call_orig,
+ PIPE,
+ Popen,
+ )
class IntegrationTestBase:
banner_width = 70
test_type = None
+ juju_target = None
+ default_juju_env = None
def __init__(self):
self.parser = argparse.ArgumentParser()
self.parser.add_argument(
'--no-tear-down', action='store_true', default=False,
help='Do not run the tear down method for debugging.')
+
+ self.parser.add_argument(
+ '-e', '--environment', default=self.default_juju_env,
+ help='Juju environment to use as defined in '
+ '~/.juju/environment.yaml')
self.args = self.parser.parse_args()
+ self.juju_env = self.args.environment
def banner(self, msg, width=banner_width):
print '*' * width
print '* ' + msg.ljust(width - 4) + ' *'
print '*' * width
+ def check_call(self, *args):
+ print '-' * 70
+ print "check_call:"
+ print ' '.join(*args)
+ print '-' * 70
+ check_call_orig(*args)
+
+ def on_remote(self, args):
+ if isinstance(args, basestring):
+ args = args.split()
+
+ self.check_call(
+ 'juju ssh {} -o StrictHostKeyChecking=no'
+ ' -o UserKnownHostsFile=/dev/null'
+ ' -e {}'.format(self.juju_target, self.juju_env).split()
+ + list(args))
+
+ def bzr_whoami(self):
+ addr = formataddr(['Not A Real Person', 'no@xxxxxxxxxxx'])
+ self.on_remote('bzr whoami "{}"'.format(addr))
+
def set_up(self):
+ """Set up a juju-managed instance to run the tests on."""
self.banner(
'Setting up the test environment for {}.'.format(self.test_type))
+ self.check_call('juju bootstrap -e {}'.format(self.juju_env).split())
+ # XXX The "ubuntu" charm is broken, so it has to be loaded from the
+ # local repository. Get it from
+ # lp:~charmers/charms/precise/ubuntu/trunk.
+ self.check_call(
+ 'juju deploy local:ubuntu --repository ~/juju-charms'
+ ' -e {}'.format(self.juju_env).split())
+
+ start_time = time.time()
+ while time.time() - start_time < 600:
+ process = Popen(
+ 'juju status -e {}'.format(self.juju_env).split(), stdout=PIPE)
+ stdout, stderr = process.communicate()
+ if 'instance-state: running' in stdout:
+ break
+ else:
+ raise RuntimeError('starting the instance took too long')
+
+ # Even though the instance-state is "running", it's still not ready, so
+ # wait a little while before continuing.
+ time.sleep(30)
+
+ self.on_remote('sudo apt-add-repository --yes ppa:yellow/ppa')
+ self.on_remote('sudo apt-get update')
+ self.on_remote('sudo apt-get install python-shelltoolbox')
+ self.check_call(
+ 'juju scp -o StrictHostKeyChecking=no'
+ ' -o UserKnownHostsFile=/dev/null -e {}'
+ ' -r . {}:lpsetup'.format(self.juju_env, self.juju_target).split())
def tear_down(self):
self.banner('Cleaning up.')
+ code = os.system(
+ 'echo y | juju destroy-environment -e {}'.format(self.juju_env))
+ if code != 0:
+ raise RuntimeError('Destroying the test juju environment failed.')
def check_environment(self):
self.banner('Checking test environment.')
+ code = os.system('juju status -e {}'.format(self.juju_env))
+ if code == 0:
+ # The "juju status" should have failed.
+ raise RuntimeError('A juju environment unexpectedly exists.')
def do_test(self):
self.banner('Running integration tests for {}.'.format(self.test_type))
+ self.bzr_whoami()
def run(self):
start_time = datetime.now()
=== added file 'lpsetup/tests/integration/juju-lxc.py'
--- lpsetup/tests/integration/juju-lxc.py 1970-01-01 00:00:00 +0000
+++ lpsetup/tests/integration/juju-lxc.py 2012-07-24 18:29:18 +0000
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""A simple, end-to-end integration test."""
+
+from StringIO import StringIO
+import sys
+import urlparse
+
+from bzrlib.branch import Branch
+from bzrlib.errors import NotBranchError
+from bzrlib.missing import find_unmerged
+from bzrlib.status import show_tree_status
+from bzrlib.workingtree import WorkingTree
+
+
+from common import IntegrationTestBase
+
+
+class LXCIntegrationTest(IntegrationTestBase):
+
+ test_type = 'local LXC target'
+ default_juju_env = 'lpsetup-testing-lxc'
+ juju_target = 'ubuntu/0'
+ test_type = 'LXC container'
+ repo = '~/launchpad-testing/lp-branches'
+
+ def get_branch(self, dir='.'):
+ branch, _ = Branch.open_containing(dir)
+ return branch
+
+ def get_push_location(self, branch=None):
+ if branch is None:
+ branch = self.get_branch()
+ return branch.get_push_location()
+
+ def check_environment(self):
+ """Be sure the test environment doesn't exist."""
+
+ # We want to be really sure we do not clobber an already-existing juju
+ # environment. Therefore we make sure one doesn't exist before
+ # bootstrapping.
+ super(LXCIntegrationTest, self).check_environment()
+
+ # Ensure the local branch has been pushed.
+ # For some reason 'bzr missing' cannot use a 'lp:' URL. http or
+ # bzr+ssh URLs work.
+ self.branch = self.get_branch()
+ self.push_location = self.get_push_location(self.branch)
+ if self.push_location.startswith('lp:'):
+ raise RuntimeError(
+ "Push location must use http or bzr+ssh "
+ "protocol: {}".format(self.push_location))
+ # Ensure the branch has been pushed and has no missing revisions.
+ try:
+ push_branch = self.get_branch(self.push_location)
+ except NotBranchError:
+ raise RuntimeError(
+ 'The branch has never been pushed to Launchpad.')
+ tree, _ = WorkingTree.open_containing_paths(None)
+ stream = StringIO()
+ show_tree_status(tree, to_file=stream)
+ if stream.getvalue():
+ raise RuntimeError(
+ 'The tree has uncommitted changes. Check them in '
+ 'and push to Launchpad.')
+ near, far = find_unmerged(self.branch, push_branch)
+ if near or far:
+ raise RuntimeError('The local branch and the pushed version '
+ 'have diverged.')
+
+ def set_up(self):
+ super(LXCIntegrationTest, self).set_up()
+ self.on_remote('cd lpsetup; sudo python setup.py install')
+
+ def do_test(self):
+ """Run an end-to-end integration tests of the non-LXC lpsetup story."""
+ # Since the most common scenario is to have bzr whoami setup, we do
+ # that instead of providing the arguments directly to lpsetup.
+ super(LXCIntegrationTest, self).do_test()
+ urlparts = list(urlparse.urlsplit(self.push_location))
+ urlparts[0] = 'http'
+ branch_location = urlparse.urlunsplit(urlparts)
+ cmd = 'lpsetup/lp-setup install-lxc --use-http -B {} -r {}'.format(
+ branch_location, self.repo)
+ self.on_remote(cmd)
+
+
+if __name__ == '__main__':
+ sys.exit(LXCIntegrationTest().run())
=== removed file 'lpsetup/tests/integration/lxc.py'
--- lpsetup/tests/integration/lxc.py 2012-07-19 20:58:52 +0000
+++ lpsetup/tests/integration/lxc.py 1970-01-01 00:00:00 +0000
@@ -1,106 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2012 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""A simple, end-to-end integration test."""
-
-from bzrlib.branch import Branch
-from bzrlib.errors import NotBranchError
-from bzrlib.missing import find_unmerged
-from bzrlib.status import show_tree_status
-from bzrlib.workingtree import WorkingTree
-from StringIO import StringIO
-from subprocess import check_call
-import sys
-
-from shelltoolbox import run
-
-from common import IntegrationTestBase
-
-
-LXC_NAME = 'lpsetup-testing'
-
-
-class LXCIntegrationTest(IntegrationTestBase):
-
- test_type = 'LXC container'
- repo = '~/launchpad-testing/lp-branches'
-
- def get_branch(self, dir='.'):
- branch, _ = Branch.open_containing(dir)
- return branch
-
- def get_push_location(self, branch=None):
- if branch is None:
- branch = self.get_branch()
- return branch.get_push_location()
-
- def check_environment(self):
- """Be sure the test environment doesn't exist."""
- # We want to be really sure we do not clobber an existing LXC
- # container, therefore we make sure one doesn't exist before
- # proceeding.
- super(LXCIntegrationTest, self).check_environment()
- cmd = 'sudo lxc-info -n {}'.format(LXC_NAME)
- results = run(*cmd.split())
- if results.split()[1] == 'RUNNING':
- # The container should not be active.
- raise RuntimeError(
- "An LXC container named '{}' is unexpectedly "
- "running.".format(LXC_NAME))
- # Ensure the local branch has been pushed.
- # For some reason 'bzr missing' cannot use a 'lp:' URL. http or
- # bzr+ssh URLs work.
- self.branch = self.get_branch()
- self.push_location = self.get_push_location(self.branch)
- if self.push_location.startswith('lp:'):
- raise RuntimeError(
- "Push location must use http or bzr+ssh "
- "protocol: {}".format(self.push_location))
- # Ensure the branch has been pushed and has no missing revisions.
- try:
- push_branch = self.get_branch(self.push_location)
- except NotBranchError:
- raise RuntimeError(
- 'The branch has never been pushed to Launchpad.')
- tree, _ = WorkingTree.open_containing_paths(None)
- stream = StringIO()
- show_tree_status(tree, to_file=stream)
- if stream.getvalue():
- raise RuntimeError(
- 'The tree has uncommitted changes. Check them in '
- 'and push to Launchpad.')
- near, far = find_unmerged(self.branch, push_branch)
- if near or far:
- raise RuntimeError('The local branch and the pushed version '
- 'have diverged.')
-
- def set_up(self):
- """Set up the LXC container environment."""
- super(LXCIntegrationTest, self).set_up()
- cmd = 'sudo python setup.py install'
- check_call(cmd.split())
-
- def do_test(self):
- """Run an end-to-end integration tests of the non-LXC lpsetup story."""
- super(LXCIntegrationTest, self).do_test()
- cmd = 'lp-setup install-lxc -B {} -r {} {}'.format(
- self.push_location, self.repo, LXC_NAME)
- check_call(cmd.split())
-
- def tear_down(self):
- super(LXCIntegrationTest, self).tear_down()
-
- def lxc_cmd(cmd_name):
- cmd = 'sudo {} -n {}'.format(cmd_name, LXC_NAME)
- check_call(cmd.split())
-
- try:
- lxc_cmd('lxc-stop')
- lxc_cmd('lxc-destroy')
- except:
- pass
-
-
-if __name__ == '__main__':
- sys.exit(LXCIntegrationTest().run())
=== modified file 'lpsetup/tests/integration/non-lxc.py'
--- lpsetup/tests/integration/non-lxc.py 2012-07-19 18:24:13 +0000
+++ lpsetup/tests/integration/non-lxc.py 2012-07-24 18:29:18 +0000
@@ -4,88 +4,23 @@
"""A simple, end-to-end integration test."""
-import os
import sys
-import time
-
-from subprocess import (
- check_call,
- Popen,
- PIPE,
- )
from common import IntegrationTestBase
class NonLXCIntegrationTest(IntegrationTestBase):
- test_type = 'non-LXC target'
-
- def on_remote(self, args):
- if type(args) == str:
- args = args.split()
-
- check_call('juju ssh 1 -o StrictHostKeyChecking=no'
- ' -o UserKnownHostsFile=/dev/null -e lpsetup-testing'.split()
- + list(args))
-
- def check_environment(self):
- """Be sure the test environment doesn't exist."""
- # We want to be really sure we do not clobber an already-existing juju
- # environment. Therefore we make sure one doesn't exist before
- # bootstrapping.
- super(NonLXCIntegrationTest, self).check_environment()
- code = os.system('juju status -e lpsetup-testing')
- if code == 0:
- # The "juju status" should have failed.
- raise RuntimeError('A juju environment unexpectedly exists.')
-
- def set_up(self):
- """Set up a juju-managed instance to run the tests on."""
- super(NonLXCIntegrationTest, self).set_up()
- check_call('juju bootstrap -e lpsetup-testing'.split())
- # XXX The "ubuntu" charm is broken, so it has to be loaded from the
- # local repository. Get it from
- # lp:~charmers/charms/precise/ubuntu/trunk.
- check_call('juju deploy local:ubuntu --repository ~/juju-charms'
- ' -e lpsetup-testing --constraints instance-type=m1.large'.split())
-
- start_time = time.time()
- while time.time() - start_time < 600:
- process = Popen(
- 'juju status -e lpsetup-testing'.split(), stdout=PIPE)
- stdout, stderr = process.communicate()
- if 'instance-state: running' in stdout:
- break
- else:
- raise RuntimeError('starting the instance took too long')
-
- # Even though the instance-state is "running", it's still not ready, so
- # wait a little while before continuing.
- time.sleep(30)
-
- self.on_remote('sudo apt-add-repository --yes ppa:yellow/ppa')
- self.on_remote('sudo apt-get update')
- self.on_remote('sudo apt-get install python-shelltoolbox')
- check_call('juju scp -o StrictHostKeyChecking=no'
- ' -o UserKnownHostsFile=/dev/null -e lpsetup-testing'
- ' -r . 1:lpsetup'.split())
+ test_type = 'non-LXC tests'
+ default_juju_env = 'lpsetup-testing-ec2'
+ juju_target = 'ubuntu/0'
def do_test(self):
"""Run an end-to-end integration tests of the non-LXC lpsetup story."""
# Since the most common scenario is to have bzr whoami setup, we do
# that instead of providing the arguments directly to lpsetup.
super(NonLXCIntegrationTest, self).do_test()
- self.on_remote(
- ('bzr', 'whoami', '"Not A Real Person <no@xxxxxxxxxxx>"'))
- self.on_remote('cd lpsetup; ./lp-setup init-host'.split())
-
- def tear_down(self):
- super(NonLXCIntegrationTest, self).tear_down()
- code = os.system(
- 'echo y | juju destroy-environment -e lpsetup-testing')
- if code != 0:
- raise RuntimeError('Destroying the test juju environment failed.')
+ self.on_remote('cd lpsetup; ./lp-setup init-host')
if __name__ == '__main__':
Follow ups