diff --git a/Makefile b/Makefile index adf4df7c..0574b23e 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ PYTHON := /usr/bin/env python lint: - @flake8 --exclude hooks/charmhelpers hooks unit_tests tests + @flake8 --exclude hooks/charmhelpers actions hooks unit_tests tests @charm proof unit_test: @@ -25,7 +25,8 @@ test: # 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 \ - 16-basic-trusty-juno + 16-basic-trusty-icehouse-git 17-basic-trusty-juno \ + 18-basic-trusty-juno-git publish: lint unit_test bzr push lp:charms/neutron-api diff --git a/README.md b/README.md index 973e2251..190c51eb 100644 --- a/README.md +++ b/README.md @@ -25,98 +25,90 @@ This charm also supports scale out and high availability using the hacluster cha # 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: - "{'neutron': - {'repository': 'git://git.openstack.org/openstack/neutron.git', - 'branch': 'stable/icehouse'}}" + "repositories: + - {name: requirements, + repository: 'git://git.openstack.org/openstack/requirements', + branch: stable/juno} + - {name: neutron, + repository: 'git://git.openstack.org/openstack/neutron', + 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 'neutron'. These repositories must correspond to these 'name' values. +Additionally, the requirements repository must be specified first and the +neutron 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'}, - 'neutron': - {'repository': 'git://git.openstack.org/openstack/neutron.git', - 'branch': 'master'}}" - -Note that there are only two key values the charm knows about for the outermost -dictionary: 'neutron' and 'requirements'. These repositories must correspond to -these keys. If the requirements repository is specified, it will be installed -first. The neutron 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'}, - 'neutron-fwaas': - {'repository': 'git://git.openstack.org/openstack/neutron-fwaas.git', - 'branch': 'master'}, - 'neutron-lbaas': - {'repository: 'git://git.openstack.org/openstack/neutron-lbaas.git', - 'branch': 'master'}, - 'neutron-vpnaas': - {'repository: 'git://git.openstack.org/openstack/neutron-vpnaas.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-context': - {'repository': 'git://git.openstack.org/openstack/oslo.context.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-middleware: - {'repository': 'git://git.openstack.org/openstack/oslo.middleware.git', - 'branch': 'master'}, - 'oslo-rootwrap': - {'repository': 'git://git.openstack.org/openstack/oslo.rootwrap.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'}, - '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-neutronclient': - {'repository': 'git://git.openstack.org/openstack/python-neutronclient.git', - 'branch: 'master'}, - 'python-novaclient': - {'repository': 'git://git.openstack.org/openstack/python-novaclient.git', - 'branch: 'master'}, - 'stevedore': - {'repository': 'git://git.openstack.org/openstack/stevedore.git', - 'branch: 'master'}, - 'neutron': - {'repository': 'git://git.openstack.org/openstack/neutron.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-context, + repository: 'git://git.openstack.org/openstack/oslo.context.git', + 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.git', + branch: master} + - {name: oslo-middleware, + repository': 'git://git.openstack.org/openstack/oslo.middleware.git', + branch: master} + - {name: oslo-rootwrap', + repository: 'git://git.openstack.org/openstack/oslo.rootwrap.git', + 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: pbr, + repository: 'git://git.openstack.org/openstack-dev/pbr', + branch: master} + - {name: stevedore, + repository: 'git://git.openstack.org/openstack/stevedore.git', + branch: 'master'} + - {name: python-keystoneclient, + repository: 'git://git.openstack.org/openstack/python-keystoneclient', + branch: master} + - {name: python-neutronclient, + repository: 'git://git.openstack.org/openstack/python-neutronclient.git', + branch: master} + - {name: python-novaclient, + repository': 'git://git.openstack.org/openstack/python-novaclient.git', + branch: master} + - {name: keystonemiddleware, + repository: 'git://git.openstack.org/openstack/keystonemiddleware', + branch: master} + - {name: neutron-fwaas, + repository': 'git://git.openstack.org/openstack/neutron-fwaas.git', + branch: master} + - {name: neutron-lbaas, + repository: 'git://git.openstack.org/openstack/neutron-lbaas.git', + branch: master} + - {name: neutron-vpnaas, + repository: 'git://git.openstack.org/openstack/neutron-vpnaas.git', + branch: master} + - {name: neutron, + repository: 'git://git.openstack.org/openstack/neutron', + branch: master}" # Restrictions diff --git a/actions.yaml b/actions.yaml new file mode 100644 index 00000000..27ef55b8 --- /dev/null +++ b/actions.yaml @@ -0,0 +1,2 @@ +git-reinstall: + description: Reinstall neutron-api 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..5f05b47a --- /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 neutron_api_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 714fd5d9..917cf211 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 91c807cf..aae7e153 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. rabbit-user: default: neutron diff --git a/hooks/neutron_api_hooks.py b/hooks/neutron_api_hooks.py index aaeb7c4c..1ab82453 100755 --- a/hooks/neutron_api_hooks.py +++ b/hooks/neutron_api_hooks.py @@ -29,6 +29,7 @@ from charmhelpers.fetch import ( ) from charmhelpers.contrib.openstack.utils import ( + config_value_changed, configure_installation_source, git_install_requested, openstack_upgrade_available, @@ -106,8 +107,7 @@ def install(): apt_install(determine_packages(config('openstack-origin')), 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" @@ -129,7 +129,10 @@ def config_changed(): config('database-user')) global CONFIGS - 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('neutron-server'): do_openstack_upgrade(CONFIGS) configure_https() diff --git a/hooks/neutron_api_utils.py b/hooks/neutron_api_utils.py index 2ea595f6..5f94ab54 100644 --- a/hooks/neutron_api_utils.py +++ b/hooks/neutron_api_utils.py @@ -14,6 +14,7 @@ from charmhelpers.contrib.openstack.utils import ( get_os_codename_install_source, git_install_requested, git_clone_and_install, + git_src_dir, configure_installation_source, ) @@ -286,16 +287,12 @@ 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() - # NOTE(coreycb): charm-helpers needs support to take array of - # core_projects. That would allow all neutron* projects to be - # installed last. - core = ['neutron-fwaas', 'neutron-lbaas', 'neutron-vpnaas', 'neutron'] - git_clone_and_install(yaml.load(projects), core_projects=core) - git_post_install() + git_clone_and_install(projects_yaml, core_project='neutron') + git_post_install(projects_yaml) def git_pre_install(): @@ -324,9 +321,9 @@ def git_pre_install(): write_file(l, '', owner='neutron', group='neutron', perms=0600) -def git_post_install(): +def git_post_install(projects_yaml): """Perform post-install setup.""" - src_etc = os.path.join(charm_dir(), '/mnt/openstack-git/neutron-api.git/etc') + src_etc = os.path.join(git_src_dir(projects_yaml, 'neutron'), 'etc') configs = { 'api-paste': { 'src': os.path.join(src_etc, 'api-paste.ini'), @@ -358,6 +355,7 @@ def git_post_install(): 'process_name': 'neutron-server', } + # NOTE(coreycb): Needs systemd support render('upstart/neutron-server.upstart', '/etc/init/neutron.conf', neutron_api_context, perms=0o644) diff --git a/tests/16-basic-trusty-icehouse-git b/tests/16-basic-trusty-icehouse-git new file mode 100755 index 00000000..51517017 --- /dev/null +++ b/tests/16-basic-trusty-icehouse-git @@ -0,0 +1,9 @@ +#!/usr/bin/python + +"""Amulet tests on a basic neutron-api git deployment on trusty-icehouse.""" + +from basic_deployment import NeutronAPIBasicDeployment + +if __name__ == '__main__': + deployment = NeutronAPIBasicDeployment(series='trusty', git=True) + deployment.run_tests() diff --git a/tests/16-basic-trusty-juno b/tests/17-basic-trusty-juno similarity index 100% rename from tests/16-basic-trusty-juno rename to tests/17-basic-trusty-juno diff --git a/tests/18-basic-trusty-juno-git b/tests/18-basic-trusty-juno-git new file mode 100755 index 00000000..91c9bdbd --- /dev/null +++ b/tests/18-basic-trusty-juno-git @@ -0,0 +1,12 @@ +#!/usr/bin/python + +"""Amulet tests on a basic neutron-api git deployment on trusty-juno.""" + +from basic_deployment import NeutronAPIBasicDeployment + +if __name__ == '__main__': + deployment = NeutronAPIBasicDeployment(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 9a2ca1be..e7fca7a8 100644 --- a/tests/basic_deployment.py +++ b/tests/basic_deployment.py @@ -19,10 +19,12 @@ u = OpenStackAmuletUtils(ERROR) class NeutronAPIBasicDeployment(OpenStackAmuletDeployment): """Amulet tests on a basic neutron-api deployment.""" - def __init__(self, series, openstack=None, source=None, stable=False): + def __init__(self, series, openstack=None, source=None, git=False, + stable=False): """Deploy the entire test environment.""" super(NeutronAPIBasicDeployment, self).__init__(series, openstack, source, stable) + self.git = git self._add_services() self._add_relations() self._configure_services() @@ -65,11 +67,21 @@ class NeutronAPIBasicDeployment(OpenStackAmuletDeployment): def _configure_services(self): """Configure all of the services.""" - # NOTE(coreycb): Added the following temporarily to test deploy from source - neutron_api_config = {'openstack-origin-git': - "{'neutron':" - " {'repository': 'git://git.openstack.org/openstack/neutron.git'," - " 'branch': 'stable/icehouse'}}"} + neutron_api_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': 'neutron', + 'repository': 'git://git.openstack.org/openstack/neutron', + 'branch': branch}, + ], + 'directory': '/mnt/openstack-git', + } + neutron_api_config['openstack-origin-git'] = yaml.dump(openstack_origin_git) keystone_config = {'admin-password': 'openstack', 'admin-token': 'ubuntutesting'} nova_cc_config = {'network-manager': 'Quantum', diff --git a/unit_tests/__init__.py b/unit_tests/__init__.py index 415b2110..43aa3614 100644 --- a/unit_tests/__init__.py +++ b/unit_tests/__init__.py @@ -1,2 +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..f23514a1 --- /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 = 'neutron' + import neutron_api_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: neutron, + repository: 'git://git.openstack.org/openstack/neutron', + branch: stable/juno}""" + + +class TestNeutronAPIActions(CharmTestCase): + + def setUp(self): + super(TestNeutronAPIActions, 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})