← Back to team overview

launchpad-reviewers team mailing list archive

[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