diff --git a/Makefile b/Makefile index d0636a9e..3b45e0fc 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ PYTHON := /usr/bin/env python lint: @echo "Running flake8 tests: " - @flake8 --exclude hooks/charmhelpers hooks unit_tests tests + @flake8 --exclude hooks/charmhelpers actions hooks unit_tests tests @echo "OK" @echo "Running charm proof: " @charm proof @@ -27,7 +27,9 @@ test: # raise_status() messages to stderr: # https://bugs.launchpad.net/amulet/+bug/1320357 @juju test -v -p AMULET_HTTP_PROXY --timeout 900 \ - 00-setup 14-basic-precise-icehouse 15-basic-trusty-icehouse + 00-setup 14-basic-precise-icehouse 15-basic-trusty-icehouse \ + 16-basic-trusty-icehouse-git 17-basic-trusty-juno \ + 18-basic-trusty-juno-git publish: lint unit_test bzr push lp:charms/glance diff --git a/README.md b/README.md index 6645ecaa..ec1b348b 100644 --- a/README.md +++ b/README.md @@ -84,92 +84,84 @@ Swift providing backing image storage. Deploying from source --------------------- -The minimal openstack-origin-git config required to deploy from source is: +The minimum openstack-origin-git config required to deploy from source is: openstack-origin-git: - "{'glance': - {'repository': 'git://git.openstack.org/openstack/glance.git', - 'branch': 'stable/icehouse'}}" + "repositories: + - {name: requirements, + repository: 'git://git.openstack.org/openstack/requirements', + branch: stable/juno} + - {name: glance, + repository: 'git://git.openstack.org/openstack/glance', + branch: stable/juno}" -If you specify a 'requirements' repository, it will be used to update the -requirements.txt files of all other git repos that it applies to, before -they are installed: +Note that there are only two 'name' values the charm knows about: 'requirements' +and 'glance'. These repositories must correspond to these 'name' values. +Additionally, the requirements repository must be specified first and the +glance repository must be specified last. All other repostories are installed +in the order in which they are specified. + +The following is a full list of current tip repos (may not be up-to-date): openstack-origin-git: - "{'requirements': - {'repository': 'git://git.openstack.org/openstack/requirements.git', - 'branch': 'master'}, - 'glance': - {'repository': 'git://git.openstack.org/openstack/glance.git', - 'branch': 'master'}}" - -Note that there are only two key values the charm knows about for the outermost -dictionary: 'glance' and 'requirements'. These repositories must correspond to -these keys. If the requirements repository is specified, it will be installed -first. The glance repository is always installed last. All other repostories -will be installed in between. - -NOTE(coreycb): The following is temporary to keep track of the full list of -current tip repos (may not be up-to-date). - - openstack-origin-git: - "{'requirements': - {'repository': 'git://git.openstack.org/openstack/requirements.git', - 'branch': 'master'}, - 'glance-store': - {'repository': 'git://git.openstack.org/openstack/glance_store.git', - 'branch': 'master'}, - 'keystonemiddleware: - {'repository': 'git://git.openstack.org/openstack/keystonemiddleware.git', - 'branch: 'master'}, - 'oslo-concurrency': - {'repository': 'git://git.openstack.org/openstack/oslo.concurrency.git', - 'branch: 'master'}, - 'oslo-config': - {'repository': 'git://git.openstack.org/openstack/oslo.config.git', - 'branch: 'master'}, - 'oslo-db': - {'repository': 'git://git.openstack.org/openstack/oslo.db.git', - 'branch: 'master'}, - 'oslo-i18n': - {'repository': 'git://git.openstack.org/openstack/oslo.i18n.git', - 'branch: 'master'}, - 'oslo-messaging': - {'repository': 'git://git.openstack.org/openstack/oslo.messaging.git', - 'branch: 'master'}, - 'oslo-serialization': - {'repository': 'git://git.openstack.org/openstack/oslo.serialization.git', - 'branch: 'master'}, - 'oslo-utils': - {'repository': 'git://git.openstack.org/openstack/oslo.utils.git', - 'branch: 'master'}, - 'oslo-vmware': - {'repository': 'git://git.openstack.org/openstack/oslo.vmware.git', - 'branch: 'master'}, - 'osprofiler': - {'repository': 'git://git.openstack.org/stackforge/osprofiler.git', - 'branch: 'master'}, - 'pbr': - {'repository': 'git://git.openstack.org/openstack-dev/pbr.git', - 'branch: 'master'}, - 'python-keystoneclient': - {'repository': 'git://git.openstack.org/openstack/python-keystoneclient.git', - 'branch: 'master'}, - 'python-swiftclient': - {'repository': 'git://git.openstack.org/openstack/python-swiftclient.git', - 'branch: 'master'}, - 'stevedore': - {'repository': 'git://git.openstack.org/openstack/stevedore.git', - 'branch: 'master'}, - 'sqlalchemy-migrate': - {'repository': 'git://git.openstack.org/stackforge/sqlalchemy-migrate.git', - 'branch: 'master'}, - 'wsme': - {'repository': 'git://git.openstack.org/stackforge/wsme.git', - 'branch': 'master'}, - 'glance': - {'repository': 'git://git.openstack.org/openstack/glance.git', - 'branch': 'master'}}" + "repositories: + - {name: requirements, + repository: 'git://git.openstack.org/openstack/requirements', + branch: master} + - {name: oslo-concurrency, + repository: 'git://git.openstack.org/openstack/oslo.concurrency', + branch: master} + - {name: oslo-config, + repository: 'git://git.openstack.org/openstack/oslo.config', + branch: master} + - {name: oslo-db, + repository: 'git://git.openstack.org/openstack/oslo.db', + branch: master} + - {name: oslo-i18n, + repository: 'git://git.openstack.org/openstack/oslo.i18n', + branch: master} + - {name: oslo-messaging, + repository: 'git://git.openstack.org/openstack/oslo.messaging', + branch: master} + - {name: oslo-serialization, + repository: 'git://git.openstack.org/openstack/oslo.serialization', + branch: master} + - {name: oslo-utils, + repository: 'git://git.openstack.org/openstack/oslo.utils', + branch: master} + - {name: oslo-vmware, + repository: 'git://git.openstack.org/openstack/oslo.vmware', + branch: master} + - {name: osprofiler, + repository: 'git://git.openstack.org/stackforge/osprofiler', + branch: master} + - {name: pbr, + repository: 'git://git.openstack.org/openstack-dev/pbr', + branch: master} + - {name: python-keystoneclient, + repository: 'git://git.openstack.org/openstack/python-keystoneclient', + branch: master} + - {name: python-swiftclient, + repository: 'git://git.openstack.org/openstack/python-swiftclient', + branch: master} + - {name: sqlalchemy-migrate, + repository: 'git://git.openstack.org/stackforge/sqlalchemy-migrate', + branch: master} + - {name: stevedore, + repository: 'git://git.openstack.org/openstack/stevedore', + branch: master} + - {name: wsme, + repository: 'git://git.openstack.org/stackforge/wsme', + branch: master} + - {name: keystonemiddleware, + repository: 'git://git.openstack.org/openstack/keystonemiddleware', + branch: master} + - {name: glance-store, + repository: 'git://git.openstack.org/openstack/glance_store', + branch: master} + - {name: glance, + repository: 'git://git.openstack.org/openstack/glance', + branch: master}" Contact Information ------------------- diff --git a/actions.yaml b/actions.yaml new file mode 100644 index 00000000..7872146c --- /dev/null +++ b/actions.yaml @@ -0,0 +1,2 @@ +git-reinstall: + description: Reinstall glance from the openstack-origin-git repositories. diff --git a/actions/git-reinstall b/actions/git-reinstall new file mode 120000 index 00000000..ff684984 --- /dev/null +++ b/actions/git-reinstall @@ -0,0 +1 @@ +git_reinstall.py \ No newline at end of file diff --git a/actions/git_reinstall.py b/actions/git_reinstall.py new file mode 100755 index 00000000..a143d5dc --- /dev/null +++ b/actions/git_reinstall.py @@ -0,0 +1,40 @@ +#!/usr/bin/python +import sys +import traceback + +sys.path.append('hooks/') + +from charmhelpers.contrib.openstack.utils import ( + git_install_requested, +) + +from charmhelpers.core.hookenv import ( + action_set, + action_fail, + config, +) + +from glance_utils import ( + git_install, +) + + +def git_reinstall(): + """Reinstall from source and restart services. + + If the openstack-origin-git config option was used to install openstack + from source git repositories, then this action can be used to reinstall + from updated git repositories, followed by a restart of services.""" + if not git_install_requested(): + action_fail('openstack-origin-git is not configured') + return + + try: + git_install(config('openstack-origin-git')) + except: + action_set({'traceback': traceback.format_exc()}) + action_fail('git-reinstall resulted in an unexpected error') + + +if __name__ == '__main__': + git_reinstall() diff --git a/charm-helpers-hooks.yaml b/charm-helpers-hooks.yaml index 1053fa5f..c73186f1 100644 --- a/charm-helpers-hooks.yaml +++ b/charm-helpers-hooks.yaml @@ -1,5 +1,4 @@ -#branch: lp:charm-helpers -branch: /home/corey/src/charms/git/charm-helpers +branch: lp:charm-helpers destination: hooks/charmhelpers include: - core diff --git a/charm-helpers-tests.yaml b/charm-helpers-tests.yaml index aaa21c31..48b12f6f 100644 --- a/charm-helpers-tests.yaml +++ b/charm-helpers-tests.yaml @@ -1,5 +1,4 @@ -#branch: lp:charm-helpers -branch: /home/corey/src/charms/git/charm-helpers +branch: lp:charm-helpers destination: tests/charmhelpers include: - contrib.amulet diff --git a/config.yaml b/config.yaml index 20bd6929..9d086b40 100644 --- a/config.yaml +++ b/config.yaml @@ -15,23 +15,20 @@ options: provide a later version of OpenStack will trigger a software upgrade. - Note that when openstack-origin-git is specified, openstack-specific - packages will be installed from source rather than from the - openstack-origin repository. + Note that when openstack-origin-git is specified, openstack + specific packages will be installed from source rather than + from the openstack-origin repository. openstack-origin-git: default: None type: string description: | - Specifies a YAML-formatted two-dimensional array listing the git - repositories and branches from which to install OpenStack and its - dependencies. + Specifies a YAML-formatted dictionary listing the git + repositories and branches from which to install OpenStack and + its dependencies. Note that the installed config files will be determined based on the OpenStack release of the openstack-origin option. - Note also that this option is processed for the initial install - only. Setting this option after deployment is not supported. - For more details see README.md. database-user: default: glance diff --git a/hooks/glance_relations.py b/hooks/glance_relations.py index 1771408d..b95e38e3 100755 --- a/hooks/glance_relations.py +++ b/hooks/glance_relations.py @@ -105,8 +105,7 @@ def install_hook(): apt_update(fatal=True) apt_install(determine_packages(), fatal=True) - # NOTE(coreycb): This is temporary for sstack proxy, unless we decide - # we need to code proxy support into the charms. + # NOTE(coreycb): This is temporary until bug #1431286 is fixed. os.environ["http_proxy"] = "http://squid.internal:3128" os.environ["https_proxy"] = "https://squid.internal:3128" @@ -325,7 +324,10 @@ def config_changed(): sync_db_with_multi_ipv6_addresses(config('database'), config('database-user')) - if not git_install_requested(): + if git_install_requested(): + if config_value_changed('openstack-origin-git'): + git_install(config('openstack-origin-git')) + else: if openstack_upgrade_available('glance-common'): juju_log('Upgrading OpenStack release') do_openstack_upgrade(CONFIGS) diff --git a/hooks/glance_utils.py b/hooks/glance_utils.py index f0e9e1cd..3f00ebdd 100755 --- a/hooks/glance_utils.py +++ b/hooks/glance_utils.py @@ -47,6 +47,7 @@ from charmhelpers.contrib.openstack.utils import ( get_os_codename_package, git_install_requested, git_clone_and_install, + git_src_dir, configure_installation_source, os_release, ) @@ -302,16 +303,16 @@ def setup_ipv6(): apt_install('haproxy/trusty-backports', fatal=True) -def git_install(projects): +def git_install(projects_yaml): """Perform setup, and install git repos specified in yaml parameter.""" if git_install_requested(): git_pre_install() - git_clone_and_install(yaml.load(projects), core_project='glance') - git_post_install() + git_clone_and_install(projects_yaml, core_project='glance') + git_post_install(projects_yaml) def git_pre_install(): - """Perform pre glance installation setup.""" + """Perform glance pre-install setup.""" dirs = [ '/var/lib/glance', '/var/lib/glance/images', @@ -339,26 +340,10 @@ def git_pre_install(): write_file(l, '', owner='glance', group='glance', perms=0600) -def git_post_install(): - """Perform post glance installation setup.""" - src_etc = os.path.join(charm_dir(), '/mnt/openstack-git/glance.git/etc/') +def git_post_install(projects_yaml): + """Perform glance post-install setup.""" + src_etc = os.path.join(git_src_dir(projects_yaml, 'glance'), 'etc') configs = { - 'glance-api-paste': { - 'src': os.path.join(src_etc, 'glance-api-paste.ini'), - 'dest': '/etc/glance/glance-api-paste.ini', - }, - 'glance-api': { - 'src': os.path.join(src_etc, 'glance-api.conf'), - 'dest': '/etc/glance/glance-api.conf', - }, - 'glance-registry-paste': { - 'src': os.path.join(src_etc, 'glance-registry-paste.ini'), - 'dest': '/etc/glance/glance-registry-paste.ini', - }, - 'glance-registry': { - 'src': os.path.join(src_etc, 'glance-registry.conf'), - 'dest': '/etc/glance/glance-registry.conf', - }, 'glance-cache': { 'src': os.path.join(src_etc, 'glance-cache.conf'), 'dest': '/etc/glance/glance-cache.conf', @@ -398,10 +383,13 @@ def git_post_install(): 'executable_name': '/usr/local/bin/glance-registry', } - render('upstart/glance.upstart', '/etc/init/glance-api.conf', - glance_api_context, perms=0o644) - render('upstart/glance.upstart', '/etc/init/glance-registry.conf', - glance_registry_context, perms=0o644) + # NOTE(coreycb): Needs systemd support + templates_dir = 'hooks/charmhelpers/contrib/openstack/templates' + templates_dir = os.path.join(charm_dir(), templates_dir) + render('git.upstart', '/etc/init/glance-api.conf', + glance_api_context, perms=0o644, templates_dir=templates_dir) + render('git.upstart', '/etc/init/glance-registry.conf', + glance_registry_context, perms=0o644, templates_dir=templates_dir) service_start('glance-api') service_start('glance-registry') diff --git a/templates/upstart/glance.upstart b/templates/upstart/glance.upstart deleted file mode 100644 index e5f39741..00000000 --- a/templates/upstart/glance.upstart +++ /dev/null @@ -1,11 +0,0 @@ -description "{{ service_description }}" -author "Juju {{ service_name }} Charm " - -start on runlevel [2345] -stop on runlevel [!2345] - -respawn - -exec start-stop-daemon --start --chuid {{ user_name }} \ - --chdir {{ start_dir }} --name {{ process_name }} \ - --exec {{ executable_name }} diff --git a/tests/10-basic-precise-essex b/tests/10-basic-precise-essex deleted file mode 100755 index 5869c57a..00000000 --- a/tests/10-basic-precise-essex +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/python - -"""Amulet tests on a basic glance deployment on precise-essex.""" - -from basic_deployment import GlanceBasicDeployment - -if __name__ == '__main__': - deployment = GlanceBasicDeployment(series='precise') - deployment.run_tests() diff --git a/tests/11-basic-precise-folsom b/tests/11-basic-precise-folsom deleted file mode 100755 index 5549f601..00000000 --- a/tests/11-basic-precise-folsom +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/python - -"""Amulet tests on a basic glance deployment on precise-folsom.""" - -from basic_deployment import GlanceBasicDeployment - -if __name__ == '__main__': - deployment = GlanceBasicDeployment(series='precise', - openstack='cloud:precise-folsom', - source='cloud:precise-updates/folsom') - deployment.run_tests() diff --git a/tests/12-basic-precise-grizzly b/tests/12-basic-precise-grizzly deleted file mode 100755 index 03a93cb3..00000000 --- a/tests/12-basic-precise-grizzly +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/python - -"""Amulet tests on a basic glance deployment on precise-grizzly.""" - -from basic_deployment import GlanceBasicDeployment - -if __name__ == '__main__': - deployment = GlanceBasicDeployment(series='precise', - openstack='cloud:precise-grizzly', - source='cloud:precise-updates/grizzly') - deployment.run_tests() diff --git a/tests/13-basic-precise-havana b/tests/13-basic-precise-havana deleted file mode 100755 index 0ceaf36d..00000000 --- a/tests/13-basic-precise-havana +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/python - -"""Amulet tests on a basic glance deployment on precise-havana.""" - -from basic_deployment import GlanceBasicDeployment - -if __name__ == '__main__': - deployment = GlanceBasicDeployment(series='precise', - openstack='cloud:precise-havana', - source='cloud:precise-updates/havana') - deployment.run_tests() diff --git a/tests/16-basic-trusty-icehouse-git b/tests/16-basic-trusty-icehouse-git new file mode 100755 index 00000000..562a8486 --- /dev/null +++ b/tests/16-basic-trusty-icehouse-git @@ -0,0 +1,9 @@ +#!/usr/bin/python + +"""Amulet tests on a basic Glance git deployment on trusty-icehouse.""" + +from basic_deployment import GlanceBasicDeployment + +if __name__ == '__main__': + deployment = GlanceBasicDeployment(series='trusty', git=True) + deployment.run_tests() diff --git a/tests/17-basic-trusty-juno b/tests/17-basic-trusty-juno new file mode 100755 index 00000000..7a726c48 --- /dev/null +++ b/tests/17-basic-trusty-juno @@ -0,0 +1,11 @@ +#!/usr/bin/python + +"""Amulet tests on a basic Glance deployment on trusty-juno.""" + +from basic_deployment import GlanceBasicDeployment + +if __name__ == '__main__': + deployment = GlanceBasicDeployment(series='trusty', + openstack='cloud:trusty-juno', + source='cloud:trusty-updates/juno') + deployment.run_tests() diff --git a/tests/18-basic-trusty-juno-git b/tests/18-basic-trusty-juno-git new file mode 100755 index 00000000..54f0dc77 --- /dev/null +++ b/tests/18-basic-trusty-juno-git @@ -0,0 +1,12 @@ +#!/usr/bin/python + +"""Amulet tests on a basic Glance git deployment on trusty-juno.""" + +from basic_deployment import GlanceBasicDeployment + +if __name__ == '__main__': + deployment = GlanceBasicDeployment(series='trusty', + openstack='cloud:trusty-juno', + source='cloud:trusty-updates/juno', + git=True) + deployment.run_tests() diff --git a/tests/basic_deployment.py b/tests/basic_deployment.py index 427bb665..458a766f 100755 --- a/tests/basic_deployment.py +++ b/tests/basic_deployment.py @@ -23,9 +23,11 @@ class GlanceBasicDeployment(OpenStackAmuletDeployment): # * Add tests with different storage back ends # * Resolve Essex->Havana juju set charm bug - def __init__(self, series=None, openstack=None, source=None, stable=False): + def __init__(self, series=None, openstack=None, source=None, git=False, + stable=False): '''Deploy the entire test environment.''' super(GlanceBasicDeployment, self).__init__(series, openstack, source, stable) + self.git = git self._add_services() self._add_relations() self._configure_services() @@ -56,13 +58,24 @@ class GlanceBasicDeployment(OpenStackAmuletDeployment): def _configure_services(self): '''Configure all of the services.''' # NOTE(coreycb): Added the following temporarily to test deploy from source - glance_config = {'openstack-origin-git': - "{'glance':" - " {'repository': 'git://git.openstack.org/openstack/glance.git'," - " 'branch': 'stable/icehouse'}}"} + glance_config = {} + if self.git: + branch = 'stable/' + self._get_openstack_release_string() + openstack_origin_git = { + 'repositories': [ + {'name': 'requirements', + 'repository': 'git://git.openstack.org/openstack/requirements', + 'branch': branch}, + {'name': 'glance', + 'repository': 'git://git.openstack.org/openstack/glance', + 'branch': branch}, + ], + 'directory': '/mnt/openstack-git', + } + glance_config['openstack-origin-git'] = yaml.dump(openstack_origin_git) + keystone_config = {'admin-password': 'openstack', 'admin-token': 'ubuntutesting'} - mysql_config = {'dataset-size': '50%'} configs = {'glance': glance_config, 'keystone': keystone_config, diff --git a/unit_tests/__init__.py b/unit_tests/__init__.py index afaed60c..43aa3614 100644 --- a/unit_tests/__init__.py +++ b/unit_tests/__init__.py @@ -1,3 +1,4 @@ import sys +sys.path.append('actions/') sys.path.append('hooks/') diff --git a/unit_tests/test_actions_git_reinstall.py b/unit_tests/test_actions_git_reinstall.py new file mode 100644 index 00000000..c0d6b696 --- /dev/null +++ b/unit_tests/test_actions_git_reinstall.py @@ -0,0 +1,85 @@ +from mock import patch + +with patch('charmhelpers.core.hookenv.config') as config: + config.return_value = 'glance' + import glance_utils as utils # noqa + +import git_reinstall + +from test_utils import ( + CharmTestCase +) + +TO_PATCH = [ + 'config', +] + + +openstack_origin_git = \ + """repositories: + - {name: requirements, + repository: 'git://git.openstack.org/openstack/requirements', + branch: stable/juno} + - {name: glance, + repository: 'git://git.openstack.org/openstack/glance', + branch: stable/juno}""" + + +class TestKeystoneActions(CharmTestCase): + + def setUp(self): + super(TestKeystoneActions, self).setUp(git_reinstall, TO_PATCH) + self.config.side_effect = self.test_config.get + + @patch.object(git_reinstall, 'action_set') + @patch.object(git_reinstall, 'action_fail') + @patch.object(git_reinstall, 'git_install') + def test_git_reinstall(self, git_install, action_fail, action_set): + self.test_config.set('openstack-origin-git', openstack_origin_git) + + git_reinstall.git_reinstall() + + git_install.assert_called_with(openstack_origin_git) + self.assertTrue(git_install.called) + self.assertFalse(action_set.called) + self.assertFalse(action_fail.called) + + @patch.object(git_reinstall, 'action_set') + @patch.object(git_reinstall, 'action_fail') + @patch.object(git_reinstall, 'git_install') + @patch('charmhelpers.contrib.openstack.utils.config') + def test_git_reinstall_not_configured(self, _config, git_install, + action_fail, action_set): + _config.return_value = 'none' + + git_reinstall.git_reinstall() + + msg = 'openstack-origin-git is not configured' + action_fail.assert_called_with(msg) + self.assertFalse(git_install.called) + self.assertFalse(action_set.called) + + @patch.object(git_reinstall, 'action_set') + @patch.object(git_reinstall, 'action_fail') + @patch.object(git_reinstall, 'git_install') + @patch('charmhelpers.contrib.openstack.utils.config') + def test_git_reinstall_exception(self, _config, git_install, + action_fail, action_set): + _config.return_value = openstack_origin_git + e = OSError('something bad happened') + git_install.side_effect = e + traceback = ( + "Traceback (most recent call last):\n" + " File \"actions/git_reinstall.py\", line 33, in git_reinstall\n" + " git_install(config(\'openstack-origin-git\'))\n" + " File \"/usr/lib/python2.7/dist-packages/mock.py\", line 964, in __call__\n" # noqa + " return _mock_self._mock_call(*args, **kwargs)\n" + " File \"/usr/lib/python2.7/dist-packages/mock.py\", line 1019, in _mock_call\n" # noqa + " raise effect\n" + "OSError: something bad happened\n") + + git_reinstall.git_reinstall() + + msg = 'git-reinstall resulted in an unexpected error' + action_fail.assert_called_with(msg) + action_set.assert_called_with({'traceback': traceback})