diff --git a/.coveragerc b/.coveragerc index 972ccd41..3e345e68 100644 --- a/.coveragerc +++ b/.coveragerc @@ -4,3 +4,4 @@ exclude_lines = if __name__ == .__main__.: include= hooks/keystone_* + actions/actions.py diff --git a/actions.yaml b/actions.yaml index 7de4d63a..81ec284a 100644 --- a/actions.yaml +++ b/actions.yaml @@ -1,2 +1,13 @@ git-reinstall: description: Reinstall keystone from the openstack-origin-git repositories. +pause: + description: | + Pause keystone services. + If the keystone deployment is clustered using the hacluster charm, the + corresponding hacluster unit on the node must first be paused as well. + Not doing so may lead to an interruption of service. +resume: + description: | + Resume keystone services. + If the keystone deployment is clustered using the hacluster charm, the + corresponding hacluster unit on the node must be resumed as well. diff --git a/actions/__init__.py b/actions/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/actions/actions.py b/actions/actions.py new file mode 100755 index 00000000..d14a6211 --- /dev/null +++ b/actions/actions.py @@ -0,0 +1,56 @@ +#!/usr/bin/python + +import sys +import os + +from charmhelpers.core.host import service_pause, service_resume +from charmhelpers.core.hookenv import action_fail, status_set + +from hooks.keystone_utils import services + + +def pause(args): + """Pause all the Keystone services. + + @raises Exception if any services fail to stop + """ + for service in services(): + stopped = service_pause(service) + if not stopped: + raise Exception("{} didn't stop cleanly.".format(service)) + status_set( + "maintenance", "Paused. Use 'resume' action to resume normal service.") + + +def resume(args): + """Resume all the Keystone services. + + @raises Exception if any services fail to start + """ + for service in services(): + started = service_resume(service) + if not started: + raise Exception("{} didn't start cleanly.".format(service)) + status_set("active", "") + + +# A dictionary of all the defined actions to callables (which take +# parsed arguments). +ACTIONS = {"pause": pause, "resume": resume} + + +def main(args): + action_name = os.path.basename(args[0]) + try: + action = ACTIONS[action_name] + except KeyError: + return "Action %s undefined" % action_name + else: + try: + action(args) + except Exception as e: + action_fail(str(e)) + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) diff --git a/actions/charmhelpers b/actions/charmhelpers new file mode 120000 index 00000000..702de734 --- /dev/null +++ b/actions/charmhelpers @@ -0,0 +1 @@ +../charmhelpers \ No newline at end of file diff --git a/actions/git_reinstall.py b/actions/git_reinstall.py index 55d29b33..c2fce797 100755 --- a/actions/git_reinstall.py +++ b/actions/git_reinstall.py @@ -1,8 +1,6 @@ #!/usr/bin/python -import sys -import traceback -sys.path.append('hooks/') +import traceback from charmhelpers.contrib.openstack.utils import ( git_install_requested, @@ -14,11 +12,11 @@ from charmhelpers.core.hookenv import ( config, ) -from keystone_utils import ( +from hooks.keystone_utils import ( git_install, ) -from keystone_hooks import ( +from hooks.keystone_hooks import ( config_changed, ) diff --git a/actions/hooks b/actions/hooks new file mode 120000 index 00000000..f631275e --- /dev/null +++ b/actions/hooks @@ -0,0 +1 @@ +../hooks \ No newline at end of file diff --git a/actions/pause b/actions/pause new file mode 120000 index 00000000..405a394e --- /dev/null +++ b/actions/pause @@ -0,0 +1 @@ +actions.py \ No newline at end of file diff --git a/actions/resume b/actions/resume new file mode 120000 index 00000000..405a394e --- /dev/null +++ b/actions/resume @@ -0,0 +1 @@ +actions.py \ No newline at end of file diff --git a/charm-helpers-hooks.yaml b/charm-helpers-hooks.yaml index 322a2ab7..1c2d6c0a 100644 --- a/charm-helpers-hooks.yaml +++ b/charm-helpers-hooks.yaml @@ -1,5 +1,5 @@ branch: lp:charm-helpers -destination: hooks/charmhelpers +destination: charmhelpers include: - core - cli diff --git a/hooks/charmhelpers/__init__.py b/charmhelpers/__init__.py similarity index 100% rename from hooks/charmhelpers/__init__.py rename to charmhelpers/__init__.py diff --git a/hooks/charmhelpers/cli/__init__.py b/charmhelpers/cli/__init__.py similarity index 100% rename from hooks/charmhelpers/cli/__init__.py rename to charmhelpers/cli/__init__.py diff --git a/hooks/charmhelpers/cli/benchmark.py b/charmhelpers/cli/benchmark.py similarity index 100% rename from hooks/charmhelpers/cli/benchmark.py rename to charmhelpers/cli/benchmark.py diff --git a/hooks/charmhelpers/cli/commands.py b/charmhelpers/cli/commands.py similarity index 100% rename from hooks/charmhelpers/cli/commands.py rename to charmhelpers/cli/commands.py diff --git a/hooks/charmhelpers/cli/hookenv.py b/charmhelpers/cli/hookenv.py similarity index 100% rename from hooks/charmhelpers/cli/hookenv.py rename to charmhelpers/cli/hookenv.py diff --git a/hooks/charmhelpers/cli/host.py b/charmhelpers/cli/host.py similarity index 100% rename from hooks/charmhelpers/cli/host.py rename to charmhelpers/cli/host.py diff --git a/hooks/charmhelpers/cli/unitdata.py b/charmhelpers/cli/unitdata.py similarity index 100% rename from hooks/charmhelpers/cli/unitdata.py rename to charmhelpers/cli/unitdata.py diff --git a/hooks/charmhelpers/contrib/__init__.py b/charmhelpers/contrib/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/__init__.py rename to charmhelpers/contrib/__init__.py diff --git a/hooks/charmhelpers/contrib/charmsupport/__init__.py b/charmhelpers/contrib/charmsupport/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/charmsupport/__init__.py rename to charmhelpers/contrib/charmsupport/__init__.py diff --git a/hooks/charmhelpers/contrib/charmsupport/nrpe.py b/charmhelpers/contrib/charmsupport/nrpe.py similarity index 100% rename from hooks/charmhelpers/contrib/charmsupport/nrpe.py rename to charmhelpers/contrib/charmsupport/nrpe.py diff --git a/hooks/charmhelpers/contrib/charmsupport/volumes.py b/charmhelpers/contrib/charmsupport/volumes.py similarity index 100% rename from hooks/charmhelpers/contrib/charmsupport/volumes.py rename to charmhelpers/contrib/charmsupport/volumes.py diff --git a/hooks/charmhelpers/contrib/hahelpers/__init__.py b/charmhelpers/contrib/hahelpers/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/hahelpers/__init__.py rename to charmhelpers/contrib/hahelpers/__init__.py diff --git a/hooks/charmhelpers/contrib/hahelpers/apache.py b/charmhelpers/contrib/hahelpers/apache.py similarity index 100% rename from hooks/charmhelpers/contrib/hahelpers/apache.py rename to charmhelpers/contrib/hahelpers/apache.py diff --git a/hooks/charmhelpers/contrib/hahelpers/cluster.py b/charmhelpers/contrib/hahelpers/cluster.py similarity index 100% rename from hooks/charmhelpers/contrib/hahelpers/cluster.py rename to charmhelpers/contrib/hahelpers/cluster.py diff --git a/hooks/charmhelpers/contrib/network/__init__.py b/charmhelpers/contrib/network/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/network/__init__.py rename to charmhelpers/contrib/network/__init__.py diff --git a/hooks/charmhelpers/contrib/network/ip.py b/charmhelpers/contrib/network/ip.py similarity index 100% rename from hooks/charmhelpers/contrib/network/ip.py rename to charmhelpers/contrib/network/ip.py diff --git a/hooks/charmhelpers/contrib/openstack/__init__.py b/charmhelpers/contrib/openstack/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/openstack/__init__.py rename to charmhelpers/contrib/openstack/__init__.py diff --git a/hooks/charmhelpers/contrib/openstack/alternatives.py b/charmhelpers/contrib/openstack/alternatives.py similarity index 100% rename from hooks/charmhelpers/contrib/openstack/alternatives.py rename to charmhelpers/contrib/openstack/alternatives.py diff --git a/hooks/charmhelpers/contrib/openstack/amulet/__init__.py b/charmhelpers/contrib/openstack/amulet/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/openstack/amulet/__init__.py rename to charmhelpers/contrib/openstack/amulet/__init__.py diff --git a/hooks/charmhelpers/contrib/openstack/amulet/deployment.py b/charmhelpers/contrib/openstack/amulet/deployment.py similarity index 100% rename from hooks/charmhelpers/contrib/openstack/amulet/deployment.py rename to charmhelpers/contrib/openstack/amulet/deployment.py diff --git a/hooks/charmhelpers/contrib/openstack/amulet/utils.py b/charmhelpers/contrib/openstack/amulet/utils.py similarity index 100% rename from hooks/charmhelpers/contrib/openstack/amulet/utils.py rename to charmhelpers/contrib/openstack/amulet/utils.py diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/charmhelpers/contrib/openstack/context.py similarity index 100% rename from hooks/charmhelpers/contrib/openstack/context.py rename to charmhelpers/contrib/openstack/context.py diff --git a/hooks/charmhelpers/contrib/openstack/files/__init__.py b/charmhelpers/contrib/openstack/files/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/openstack/files/__init__.py rename to charmhelpers/contrib/openstack/files/__init__.py diff --git a/hooks/charmhelpers/contrib/openstack/files/check_haproxy.sh b/charmhelpers/contrib/openstack/files/check_haproxy.sh similarity index 100% rename from hooks/charmhelpers/contrib/openstack/files/check_haproxy.sh rename to charmhelpers/contrib/openstack/files/check_haproxy.sh diff --git a/hooks/charmhelpers/contrib/openstack/files/check_haproxy_queue_depth.sh b/charmhelpers/contrib/openstack/files/check_haproxy_queue_depth.sh similarity index 100% rename from hooks/charmhelpers/contrib/openstack/files/check_haproxy_queue_depth.sh rename to charmhelpers/contrib/openstack/files/check_haproxy_queue_depth.sh diff --git a/hooks/charmhelpers/contrib/openstack/ip.py b/charmhelpers/contrib/openstack/ip.py similarity index 100% rename from hooks/charmhelpers/contrib/openstack/ip.py rename to charmhelpers/contrib/openstack/ip.py diff --git a/hooks/charmhelpers/contrib/openstack/neutron.py b/charmhelpers/contrib/openstack/neutron.py similarity index 100% rename from hooks/charmhelpers/contrib/openstack/neutron.py rename to charmhelpers/contrib/openstack/neutron.py diff --git a/hooks/charmhelpers/contrib/openstack/templates/__init__.py b/charmhelpers/contrib/openstack/templates/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/openstack/templates/__init__.py rename to charmhelpers/contrib/openstack/templates/__init__.py diff --git a/hooks/charmhelpers/contrib/openstack/templates/ceph.conf b/charmhelpers/contrib/openstack/templates/ceph.conf similarity index 100% rename from hooks/charmhelpers/contrib/openstack/templates/ceph.conf rename to charmhelpers/contrib/openstack/templates/ceph.conf diff --git a/hooks/charmhelpers/contrib/openstack/templates/git.upstart b/charmhelpers/contrib/openstack/templates/git.upstart similarity index 100% rename from hooks/charmhelpers/contrib/openstack/templates/git.upstart rename to charmhelpers/contrib/openstack/templates/git.upstart diff --git a/hooks/charmhelpers/contrib/openstack/templates/haproxy.cfg b/charmhelpers/contrib/openstack/templates/haproxy.cfg similarity index 100% rename from hooks/charmhelpers/contrib/openstack/templates/haproxy.cfg rename to charmhelpers/contrib/openstack/templates/haproxy.cfg diff --git a/hooks/charmhelpers/contrib/openstack/templates/openstack_https_frontend b/charmhelpers/contrib/openstack/templates/openstack_https_frontend similarity index 100% rename from hooks/charmhelpers/contrib/openstack/templates/openstack_https_frontend rename to charmhelpers/contrib/openstack/templates/openstack_https_frontend diff --git a/hooks/charmhelpers/contrib/openstack/templates/openstack_https_frontend.conf b/charmhelpers/contrib/openstack/templates/openstack_https_frontend.conf similarity index 100% rename from hooks/charmhelpers/contrib/openstack/templates/openstack_https_frontend.conf rename to charmhelpers/contrib/openstack/templates/openstack_https_frontend.conf diff --git a/hooks/charmhelpers/contrib/openstack/templates/section-keystone-authtoken b/charmhelpers/contrib/openstack/templates/section-keystone-authtoken similarity index 100% rename from hooks/charmhelpers/contrib/openstack/templates/section-keystone-authtoken rename to charmhelpers/contrib/openstack/templates/section-keystone-authtoken diff --git a/hooks/charmhelpers/contrib/openstack/templates/section-rabbitmq-oslo b/charmhelpers/contrib/openstack/templates/section-rabbitmq-oslo similarity index 100% rename from hooks/charmhelpers/contrib/openstack/templates/section-rabbitmq-oslo rename to charmhelpers/contrib/openstack/templates/section-rabbitmq-oslo diff --git a/hooks/charmhelpers/contrib/openstack/templates/section-zeromq b/charmhelpers/contrib/openstack/templates/section-zeromq similarity index 100% rename from hooks/charmhelpers/contrib/openstack/templates/section-zeromq rename to charmhelpers/contrib/openstack/templates/section-zeromq diff --git a/hooks/charmhelpers/contrib/openstack/templating.py b/charmhelpers/contrib/openstack/templating.py similarity index 100% rename from hooks/charmhelpers/contrib/openstack/templating.py rename to charmhelpers/contrib/openstack/templating.py diff --git a/hooks/charmhelpers/contrib/openstack/utils.py b/charmhelpers/contrib/openstack/utils.py similarity index 100% rename from hooks/charmhelpers/contrib/openstack/utils.py rename to charmhelpers/contrib/openstack/utils.py diff --git a/hooks/charmhelpers/contrib/peerstorage/__init__.py b/charmhelpers/contrib/peerstorage/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/peerstorage/__init__.py rename to charmhelpers/contrib/peerstorage/__init__.py diff --git a/hooks/charmhelpers/contrib/python/__init__.py b/charmhelpers/contrib/python/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/python/__init__.py rename to charmhelpers/contrib/python/__init__.py diff --git a/hooks/charmhelpers/contrib/python/debug.py b/charmhelpers/contrib/python/debug.py similarity index 100% rename from hooks/charmhelpers/contrib/python/debug.py rename to charmhelpers/contrib/python/debug.py diff --git a/hooks/charmhelpers/contrib/python/packages.py b/charmhelpers/contrib/python/packages.py similarity index 100% rename from hooks/charmhelpers/contrib/python/packages.py rename to charmhelpers/contrib/python/packages.py diff --git a/hooks/charmhelpers/contrib/python/rpdb.py b/charmhelpers/contrib/python/rpdb.py similarity index 100% rename from hooks/charmhelpers/contrib/python/rpdb.py rename to charmhelpers/contrib/python/rpdb.py diff --git a/hooks/charmhelpers/contrib/python/version.py b/charmhelpers/contrib/python/version.py similarity index 100% rename from hooks/charmhelpers/contrib/python/version.py rename to charmhelpers/contrib/python/version.py diff --git a/hooks/charmhelpers/contrib/storage/__init__.py b/charmhelpers/contrib/storage/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/storage/__init__.py rename to charmhelpers/contrib/storage/__init__.py diff --git a/hooks/charmhelpers/contrib/storage/linux/__init__.py b/charmhelpers/contrib/storage/linux/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/storage/linux/__init__.py rename to charmhelpers/contrib/storage/linux/__init__.py diff --git a/hooks/charmhelpers/contrib/storage/linux/ceph.py b/charmhelpers/contrib/storage/linux/ceph.py similarity index 100% rename from hooks/charmhelpers/contrib/storage/linux/ceph.py rename to charmhelpers/contrib/storage/linux/ceph.py diff --git a/hooks/charmhelpers/contrib/storage/linux/loopback.py b/charmhelpers/contrib/storage/linux/loopback.py similarity index 100% rename from hooks/charmhelpers/contrib/storage/linux/loopback.py rename to charmhelpers/contrib/storage/linux/loopback.py diff --git a/hooks/charmhelpers/contrib/storage/linux/lvm.py b/charmhelpers/contrib/storage/linux/lvm.py similarity index 100% rename from hooks/charmhelpers/contrib/storage/linux/lvm.py rename to charmhelpers/contrib/storage/linux/lvm.py diff --git a/hooks/charmhelpers/contrib/storage/linux/utils.py b/charmhelpers/contrib/storage/linux/utils.py similarity index 100% rename from hooks/charmhelpers/contrib/storage/linux/utils.py rename to charmhelpers/contrib/storage/linux/utils.py diff --git a/hooks/charmhelpers/contrib/unison/__init__.py b/charmhelpers/contrib/unison/__init__.py similarity index 100% rename from hooks/charmhelpers/contrib/unison/__init__.py rename to charmhelpers/contrib/unison/__init__.py diff --git a/hooks/charmhelpers/core/__init__.py b/charmhelpers/core/__init__.py similarity index 100% rename from hooks/charmhelpers/core/__init__.py rename to charmhelpers/core/__init__.py diff --git a/hooks/charmhelpers/core/decorators.py b/charmhelpers/core/decorators.py similarity index 100% rename from hooks/charmhelpers/core/decorators.py rename to charmhelpers/core/decorators.py diff --git a/hooks/charmhelpers/core/files.py b/charmhelpers/core/files.py similarity index 100% rename from hooks/charmhelpers/core/files.py rename to charmhelpers/core/files.py diff --git a/hooks/charmhelpers/core/fstab.py b/charmhelpers/core/fstab.py similarity index 100% rename from hooks/charmhelpers/core/fstab.py rename to charmhelpers/core/fstab.py diff --git a/hooks/charmhelpers/core/hookenv.py b/charmhelpers/core/hookenv.py similarity index 100% rename from hooks/charmhelpers/core/hookenv.py rename to charmhelpers/core/hookenv.py diff --git a/hooks/charmhelpers/core/host.py b/charmhelpers/core/host.py similarity index 100% rename from hooks/charmhelpers/core/host.py rename to charmhelpers/core/host.py diff --git a/hooks/charmhelpers/core/hugepage.py b/charmhelpers/core/hugepage.py similarity index 100% rename from hooks/charmhelpers/core/hugepage.py rename to charmhelpers/core/hugepage.py diff --git a/hooks/charmhelpers/core/services/__init__.py b/charmhelpers/core/services/__init__.py similarity index 100% rename from hooks/charmhelpers/core/services/__init__.py rename to charmhelpers/core/services/__init__.py diff --git a/hooks/charmhelpers/core/services/base.py b/charmhelpers/core/services/base.py similarity index 100% rename from hooks/charmhelpers/core/services/base.py rename to charmhelpers/core/services/base.py diff --git a/hooks/charmhelpers/core/services/helpers.py b/charmhelpers/core/services/helpers.py similarity index 100% rename from hooks/charmhelpers/core/services/helpers.py rename to charmhelpers/core/services/helpers.py diff --git a/hooks/charmhelpers/core/strutils.py b/charmhelpers/core/strutils.py similarity index 100% rename from hooks/charmhelpers/core/strutils.py rename to charmhelpers/core/strutils.py diff --git a/hooks/charmhelpers/core/sysctl.py b/charmhelpers/core/sysctl.py similarity index 100% rename from hooks/charmhelpers/core/sysctl.py rename to charmhelpers/core/sysctl.py diff --git a/hooks/charmhelpers/core/templating.py b/charmhelpers/core/templating.py similarity index 100% rename from hooks/charmhelpers/core/templating.py rename to charmhelpers/core/templating.py diff --git a/hooks/charmhelpers/core/unitdata.py b/charmhelpers/core/unitdata.py similarity index 100% rename from hooks/charmhelpers/core/unitdata.py rename to charmhelpers/core/unitdata.py diff --git a/hooks/charmhelpers/fetch/__init__.py b/charmhelpers/fetch/__init__.py similarity index 100% rename from hooks/charmhelpers/fetch/__init__.py rename to charmhelpers/fetch/__init__.py diff --git a/hooks/charmhelpers/fetch/archiveurl.py b/charmhelpers/fetch/archiveurl.py similarity index 100% rename from hooks/charmhelpers/fetch/archiveurl.py rename to charmhelpers/fetch/archiveurl.py diff --git a/hooks/charmhelpers/fetch/bzrurl.py b/charmhelpers/fetch/bzrurl.py similarity index 100% rename from hooks/charmhelpers/fetch/bzrurl.py rename to charmhelpers/fetch/bzrurl.py diff --git a/hooks/charmhelpers/fetch/giturl.py b/charmhelpers/fetch/giturl.py similarity index 100% rename from hooks/charmhelpers/fetch/giturl.py rename to charmhelpers/fetch/giturl.py diff --git a/hooks/charmhelpers/payload/__init__.py b/charmhelpers/payload/__init__.py similarity index 100% rename from hooks/charmhelpers/payload/__init__.py rename to charmhelpers/payload/__init__.py diff --git a/hooks/charmhelpers/payload/execd.py b/charmhelpers/payload/execd.py similarity index 100% rename from hooks/charmhelpers/payload/execd.py rename to charmhelpers/payload/execd.py diff --git a/hooks/__init__.py b/hooks/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/hooks/charmhelpers b/hooks/charmhelpers new file mode 120000 index 00000000..702de734 --- /dev/null +++ b/hooks/charmhelpers @@ -0,0 +1 @@ +../charmhelpers \ No newline at end of file diff --git a/hooks/keystone_utils.py b/hooks/keystone_utils.py index ea8efe56..8d3aa006 100644 --- a/hooks/keystone_utils.py +++ b/hooks/keystone_utils.py @@ -14,6 +14,7 @@ import time import urlparse import uuid +from itertools import chain from base64 import b64encode from collections import OrderedDict from copy import deepcopy @@ -150,11 +151,6 @@ GIT_PACKAGE_BLACKLIST = [ 'keystone', ] -API_PORTS = { - 'keystone-admin': config('admin-port'), - 'keystone-public': config('service-port') -} - KEYSTONE_CONF = "/etc/keystone/keystone.conf" KEYSTONE_LOGGER_CONF = "/etc/keystone/logging.conf" KEYSTONE_CONF_DIR = os.path.dirname(KEYSTONE_CONF) @@ -178,7 +174,6 @@ SSH_USER = 'juju_keystone' CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt' SSL_SYNC_SEMAPHORE = threading.Semaphore() SSL_DIRS = [SSL_DIR, APACHE_SSL_DIR, CA_CERT_PATH] - BASE_RESOURCE_MAP = OrderedDict([ (KEYSTONE_CONF, { 'services': BASE_SERVICES, @@ -321,11 +316,8 @@ def restart_map(): def services(): - """Returns a list of services associate with this charm""" - _services = [] - for v in restart_map().values(): - _services = _services + v - return list(set(_services)) + """Returns a list of (unique) services associated with this charm""" + return list(set(chain(*restart_map().values()))) def determine_ports(): @@ -335,23 +327,20 @@ def determine_ports(): def api_port(service): - return API_PORTS[service] + return { + 'keystone-admin': config('admin-port'), + 'keystone-public': config('service-port') + }[service] def determine_packages(): # currently all packages match service names - packages = [] + BASE_PACKAGES - for k, v in resource_map().iteritems(): - packages.extend(v['services']) - + packages = set(services()).union(BASE_PACKAGES) if git_install_requested(): - packages.extend(BASE_GIT_PACKAGES) - # don't include packages that will be installed from git - packages = list(set(packages)) - for p in GIT_PACKAGE_BLACKLIST: - packages.remove(p) + packages |= set(BASE_GIT_PACKAGES) + packages -= set(GIT_PACKAGE_BLACKLIST) - return list(set(packages)) + return sorted(packages) def save_script_rc(): diff --git a/tests/basic_deployment.py b/tests/basic_deployment.py index 164aaac7..795cfb2d 100644 --- a/tests/basic_deployment.py +++ b/tests/basic_deployment.py @@ -38,6 +38,21 @@ class KeystoneBasicDeployment(OpenStackAmuletDeployment): self._deploy() self._initialize_tests() + def _assert_services(self, should_run): + u.get_unit_process_ids( + {self.keystone_sentry: ("keystone-all", "apache2", "haproxy")}, + expect_success=should_run) + + def get_service_overrides(self, unit): + """ + Return a dict mapping service names to a boolean indicating whether + an override file exists for that service. + """ + init_contents = unit.directory_contents("/etc/init/") + return { + service: "{}.override".format(service) in init_contents["files"] + for service in ("keystone", "apache2", "haproxy")} + def _add_services(self): """Add services @@ -462,4 +477,23 @@ class KeystoneBasicDeployment(OpenStackAmuletDeployment): amulet.raise_status(amulet.FAIL, msg=msg) self.d.configure(juju_service, set_default) + u.log.debug('OK') + + def test_901_pause_resume(self): + """Test pause and resume actions.""" + unit_name = "keystone/0" + unit = self.d.sentry.unit[unit_name] + self._assert_services(should_run=True) + action_id = u.run_action(unit, "pause") + assert u.wait_on_action(action_id), "Pause action failed." + + self._assert_services(should_run=False) + assert all(self.get_service_overrides(unit).itervalues()), \ + "Not all override files were created." + + action_id = u.run_action(unit, "resume") + assert u.wait_on_action(action_id), "Resume action failed" + assert not any(self.get_service_overrides(unit).itervalues()), \ + "Not all override files were removed." + self._assert_services(should_run=True) diff --git a/unit_tests/test_actions.py b/unit_tests/test_actions.py new file mode 100644 index 00000000..a9ce3ec2 --- /dev/null +++ b/unit_tests/test_actions.py @@ -0,0 +1,150 @@ +import mock + +from test_utils import CharmTestCase + +import actions.actions + + +class PauseTestCase(CharmTestCase): + + def setUp(self): + super(PauseTestCase, self).setUp( + actions.actions, ["service_pause", "status_set"]) + + def test_pauses_services(self): + """Pause action pauses all Keystone services.""" + pause_calls = [] + + def fake_service_pause(svc): + pause_calls.append(svc) + return True + + self.service_pause.side_effect = fake_service_pause + + actions.actions.pause([]) + self.assertEqual(pause_calls, ['haproxy', 'keystone', 'apache2']) + + def test_bails_out_early_on_error(self): + """Pause action fails early if there are errors stopping a service.""" + pause_calls = [] + + def maybe_kill(svc): + if svc == "keystone": + return False + else: + pause_calls.append(svc) + return True + + self.service_pause.side_effect = maybe_kill + self.assertRaisesRegexp( + Exception, "keystone didn't stop cleanly.", + actions.actions.pause, []) + self.assertEqual(pause_calls, ['haproxy']) + + def test_status_mode(self): + """Pause action sets the status to maintenance.""" + status_calls = [] + self.status_set.side_effect = lambda state, msg: status_calls.append( + state) + + actions.actions.pause([]) + self.assertEqual(status_calls, ["maintenance"]) + + def test_status_message(self): + """Pause action sets a status message reflecting that it's paused.""" + status_calls = [] + self.status_set.side_effect = lambda state, msg: status_calls.append( + msg) + + actions.actions.pause([]) + self.assertEqual( + status_calls, ["Paused. " + "Use 'resume' action to resume normal service."]) + + +class ResumeTestCase(CharmTestCase): + + def setUp(self): + super(ResumeTestCase, self).setUp( + actions.actions, ["service_resume", "status_set"]) + + def test_resumes_services(self): + """Resume action resumes all Keystone services.""" + resume_calls = [] + + def fake_service_resume(svc): + resume_calls.append(svc) + return True + + self.service_resume.side_effect = fake_service_resume + actions.actions.resume([]) + self.assertEqual(resume_calls, ['haproxy', 'keystone', 'apache2']) + + def test_bails_out_early_on_error(self): + """Resume action fails early if there are errors starting a service.""" + resume_calls = [] + + def maybe_kill(svc): + if svc == "keystone": + return False + else: + resume_calls.append(svc) + return True + + self.service_resume.side_effect = maybe_kill + self.assertRaisesRegexp( + Exception, "keystone didn't start cleanly.", + actions.actions.resume, []) + self.assertEqual(resume_calls, ['haproxy']) + + def test_status_mode(self): + """Resume action sets the status to maintenance.""" + status_calls = [] + self.status_set.side_effect = lambda state, msg: status_calls.append( + state) + + actions.actions.resume([]) + self.assertEqual(status_calls, ["active"]) + + def test_status_message(self): + """Resume action sets an empty status message.""" + status_calls = [] + self.status_set.side_effect = lambda state, msg: status_calls.append( + msg) + + actions.actions.resume([]) + self.assertEqual(status_calls, [""]) + + +class MainTestCase(CharmTestCase): + + def setUp(self): + super(MainTestCase, self).setUp(actions.actions, ["action_fail"]) + + def test_invokes_action(self): + dummy_calls = [] + + def dummy_action(args): + dummy_calls.append(True) + + with mock.patch.dict(actions.actions.ACTIONS, {"foo": dummy_action}): + actions.actions.main(["foo"]) + self.assertEqual(dummy_calls, [True]) + + def test_unknown_action(self): + """Unknown actions aren't a traceback.""" + exit_string = actions.actions.main(["foo"]) + self.assertEqual("Action foo undefined", exit_string) + + def test_failing_action(self): + """Actions which traceback trigger action_fail() calls.""" + dummy_calls = [] + + self.action_fail.side_effect = dummy_calls.append + + def dummy_action(args): + raise ValueError("uh oh") + + with mock.patch.dict(actions.actions.ACTIONS, {"foo": dummy_action}): + actions.actions.main(["foo"]) + self.assertEqual(dummy_calls, ["uh oh"]) diff --git a/unit_tests/test_actions_git_reinstall.py b/unit_tests/test_actions_git_reinstall.py index 3daea91c..6deaf82a 100644 --- a/unit_tests/test_actions_git_reinstall.py +++ b/unit_tests/test_actions_git_reinstall.py @@ -4,8 +4,8 @@ with patch('charmhelpers.core.hookenv.config') as config: config.return_value = 'keystone' import keystone_utils as utils # noqa -with patch('keystone_utils.register_configs') as register_configs: - import git_reinstall + with patch('keystone_utils.register_configs') as register_configs: + import git_reinstall from test_utils import ( CharmTestCase @@ -36,8 +36,10 @@ class TestKeystoneActions(CharmTestCase): @patch.object(git_reinstall, 'action_fail') @patch.object(git_reinstall, 'git_install') @patch.object(git_reinstall, 'config_changed') - def test_git_reinstall(self, config_changed, git_install, action_fail, - action_set): + @patch('charmhelpers.contrib.openstack.utils.config') + def test_git_reinstall(self, config, config_changed, git_install, + action_fail, action_set): + config.return_value = openstack_origin_git self.test_config.set('openstack-origin-git', openstack_origin_git) git_reinstall.git_reinstall() diff --git a/unit_tests/test_keystone_contexts.py b/unit_tests/test_keystone_contexts.py index 2196e4cf..ef732648 100644 --- a/unit_tests/test_keystone_contexts.py +++ b/unit_tests/test_keystone_contexts.py @@ -1,3 +1,5 @@ +import os + import keystone_context as context from mock import patch, MagicMock @@ -45,6 +47,7 @@ class TestKeystoneContexts(CharmTestCase): self.assertTrue(mock_ensure_permissions.called) self.assertFalse(mock_get_ca.called) + @patch('keystone_utils.determine_ports') @patch('keystone_utils.is_ssl_cert_master') @patch('keystone_utils.is_ssl_enabled') @patch('charmhelpers.contrib.openstack.context.config') @@ -60,7 +63,8 @@ class TestKeystoneContexts(CharmTestCase): mock_is_clustered, mock_config, mock_is_ssl_enabled, - mock_is_ssl_cert_master): + mock_is_ssl_cert_master, + mock_determine_ports): mock_is_ssl_enabled.return_value = True mock_is_ssl_cert_master.return_value = True mock_https.return_value = True @@ -69,6 +73,7 @@ class TestKeystoneContexts(CharmTestCase): mock_determine_apache_port.return_value = '34' mock_is_clustered.return_value = False mock_config.return_value = None + mock_determine_ports.return_value = ['12'] ctxt = context.ApacheSSLContext() ctxt.enable_modules = MagicMock() @@ -83,6 +88,7 @@ class TestKeystoneContexts(CharmTestCase): self.assertTrue(mock_https.called) mock_unit_get.assert_called_with('private-address') + @patch('keystone_utils.api_port') @patch('charmhelpers.contrib.openstack.context.get_netmask_for_address') @patch('charmhelpers.contrib.openstack.context.get_address_in_network') @patch('charmhelpers.contrib.openstack.context.config') @@ -95,7 +101,10 @@ class TestKeystoneContexts(CharmTestCase): def test_haproxy_context_service_enabled( self, mock_open, mock_log, mock_relation_get, mock_related_units, mock_unit_get, mock_relation_ids, mock_config, - mock_get_address_in_network, mock_get_netmask_for_address): + mock_get_address_in_network, mock_get_netmask_for_address, + mock_api_port): + os.environ['JUJU_UNIT_NAME'] = 'keystone' + mock_relation_ids.return_value = ['identity-service:0', ] mock_unit_get.return_value = '1.2.3.4' mock_relation_get.return_value = '10.0.0.0' @@ -104,19 +113,20 @@ class TestKeystoneContexts(CharmTestCase): mock_get_address_in_network.return_value = None mock_get_netmask_for_address.return_value = '255.255.255.0' self.determine_apache_port.return_value = '34' + mock_api_port.return_value = '12' ctxt = context.HAProxyContext() self.maxDiff = None self.assertEquals( ctxt(), - {'listen_ports': {'admin_port': 'keystone', - 'public_port': 'keystone'}, + {'listen_ports': {'admin_port': '12', + 'public_port': '12'}, 'local_host': '127.0.0.1', 'haproxy_host': '0.0.0.0', 'stat_port': ':8888', - 'service_ports': {'admin-port': ['keystone', '34'], - 'public-port': ['keystone', '34']}, + 'service_ports': {'admin-port': ['12', '34'], + 'public-port': ['12', '34']}, 'default_backend': '1.2.3.4', 'frontends': {'1.2.3.4': { 'network': '1.2.3.4/255.255.255.0', diff --git a/unit_tests/test_keystone_hooks.py b/unit_tests/test_keystone_hooks.py index d43260bd..fc2625d5 100644 --- a/unit_tests/test_keystone_hooks.py +++ b/unit_tests/test_keystone_hooks.py @@ -92,9 +92,9 @@ class KeystoneRelationTests(CharmTestCase): self.configure_installation_source.assert_called_with(repo) self.assertTrue(self.apt_update.called) self.apt_install.assert_called_with( - ['haproxy', 'unison', 'python-keystoneclient', - 'uuid', 'python-mysqldb', 'openssl', 'apache2', - 'pwgen', 'python-six', 'keystone', 'python-psycopg2'], fatal=True) + ['apache2', 'haproxy', 'keystone', 'openssl', 'pwgen', + 'python-keystoneclient', 'python-mysqldb', 'python-psycopg2', + 'python-six', 'unison', 'uuid'], fatal=True) self.git_install.assert_called_with(None) @patch.object(utils, 'git_install_requested') @@ -120,12 +120,12 @@ class KeystoneRelationTests(CharmTestCase): self.configure_installation_source.assert_called_with(repo) self.assertTrue(self.apt_update.called) self.apt_install.assert_called_with( - ['haproxy', 'unison', 'python-setuptools', 'python-keystoneclient', - 'uuid', 'python-mysqldb', 'libmysqlclient-dev', 'libssl-dev', - 'openssl', 'libffi-dev', 'apache2', 'python-pip', 'pwgen', - 'python-six', 'libxslt1-dev', 'python-psycopg2', 'libyaml-dev', - 'zlib1g-dev', 'python-dev', 'libxml2-dev'], - fatal=True) + ['apache2', 'haproxy', 'libffi-dev', 'libmysqlclient-dev', + 'libssl-dev', 'libxml2-dev', 'libxslt1-dev', 'libyaml-dev', + 'openssl', 'pwgen', 'python-dev', 'python-keystoneclient', + 'python-mysqldb', 'python-pip', 'python-psycopg2', + 'python-setuptools', 'python-six', 'unison', 'uuid', + 'zlib1g-dev'], fatal=True) self.git_install.assert_called_with(projects_yaml) mod_ch_openstack_utils = 'charmhelpers.contrib.openstack.utils' diff --git a/unit_tests/test_keystone_utils.py b/unit_tests/test_keystone_utils.py index ebfdafc8..940a18de 100644 --- a/unit_tests/test_keystone_utils.py +++ b/unit_tests/test_keystone_utils.py @@ -281,11 +281,13 @@ class TestKeystoneUtils(CharmTestCase): self.relation_set.assert_called_with(relation_id=relation_id, **filtered) + @patch('charmhelpers.contrib.openstack.ip.config') @patch.object(utils, 'ensure_valid_service') @patch.object(utils, 'add_endpoint') @patch.object(manager, 'KeystoneManager') def test_add_service_to_keystone_nosubset( - self, KeystoneManager, add_endpoint, ensure_valid_service): + self, KeystoneManager, add_endpoint, ensure_valid_service, + ip_config): relation_id = 'identity-service:0' remote_unit = 'unit/0'