diff --git a/hooks/cinder_hooks.py b/hooks/cinder_hooks.py index e7828131..8851c536 100755 --- a/hooks/cinder_hooks.py +++ b/hooks/cinder_hooks.py @@ -116,6 +116,8 @@ from charmhelpers.contrib.storage.linux.ceph import ( delete_keyring, ) +from charmhelpers.contrib.hahelpers.apache import install_ca_cert + from charmhelpers.contrib.hahelpers.cluster import ( is_clustered, is_elected_leader, @@ -168,13 +170,15 @@ def install(): apt_update() apt_install(determine_packages(), fatal=True) - if run_in_apache(): - disable_package_apache_site() - # call the policy overrides handler which will install any policy overrides - maybe_do_policyd_overrides( - os_release('cinder-common'), - 'cinder', - restart_handler=lambda: service_restart('cinder-api')) + if service_enabled('api'): + if run_in_apache(): + disable_package_apache_site() + # call the policy overrides handler which will install any policy + # overrides + maybe_do_policyd_overrides( + os_release('cinder-common'), + 'cinder', + restart_handler=lambda: service_restart('cinder-api')) @hooks.hook('config-changed') @@ -220,9 +224,10 @@ def config_changed(): service_restart('cinder-volume') CONFIGS.write_all() - configure_https() + if service_enabled('api'): + configure_https() + open_port(config('api-listening-port')) update_nrpe_config() - open_port(config('api-listening-port')) for rid in relation_ids('cluster'): cluster_joined(relation_id=rid) @@ -236,11 +241,13 @@ def config_changed(): for rid in relation_ids('identity-service'): identity_joined(rid=rid) - # call the policy overrides handler which will install any policy overrides - maybe_do_policyd_overrides_on_config_changed( - os_release('cinder-common'), - 'cinder', - restart_handler=lambda: service_restart('cinder-api')) + if service_enabled('api'): + # call the policy overrides handler which will install any policy + # overrides + maybe_do_policyd_overrides_on_config_changed( + os_release('cinder-common'), + 'cinder', + restart_handler=lambda: service_restart('cinder-api')) @hooks.hook('storage.real') @@ -436,8 +443,9 @@ def identity_changed(): if 'identity-service' not in CONFIGS.complete_contexts(): juju_log('identity-service relation incomplete. Peer not ready?') return - CONFIGS.write(CINDER_API_CONF) - configure_https() + if service_enabled('api'): + CONFIGS.write(CINDER_API_CONF) + configure_https() @hooks.hook('ceph-relation-joined') @@ -602,11 +610,14 @@ def upgrade_charm(): juju_log("Package purge detected, restarting services") for s in services(): service_restart(s) - # call the policy overrides handler which will install any policy overrides - maybe_do_policyd_overrides( - os_release('cinder-common'), - 'cinder', - restart_handler=lambda: service_restart('cinder-api')) + + if service_enabled('api'): + # call the policy overrides handler which will install any policy + # overrides + maybe_do_policyd_overrides( + os_release('cinder-common'), + 'cinder', + restart_handler=lambda: service_restart('cinder-api')) @hooks.hook('storage-backend-relation-changed') @@ -633,7 +644,11 @@ def update_nrpe_config(): nrpe_setup = nrpe.NRPE(hostname=hostname) nrpe.copy_nrpe_checks() nrpe.add_init_service_checks(nrpe_setup, services(), current_unit) - nrpe.add_haproxy_checks(nrpe_setup, current_unit) + if service_enabled('api'): + nrpe.add_haproxy_checks(nrpe_setup, current_unit) + else: + nrpe.remove_deprecated_check(nrpe_setup, + ["haproxy_servers", "haproxy_queue"]) nrpe_setup.write() @@ -653,6 +668,13 @@ def certs_joined(relation_id=None): @hooks.hook('certificates-relation-changed') @restart_on_change(restart_map()) def certs_changed(relation_id=None, unit=None): + if not service_enabled('api'): + # Install CA cert to communicate with Keystone and Glance + data = relation_get(rid=relation_id, unit=unit) + ca = data.get('ca') + if ca: + install_ca_cert(ca.encode()) + return process_certificates('cinder', relation_id, unit) configure_https() diff --git a/hooks/cinder_utils.py b/hooks/cinder_utils.py index b7ff9d6e..fb91729f 100644 --- a/hooks/cinder_utils.py +++ b/hooks/cinder_utils.py @@ -118,10 +118,8 @@ import cinder_contexts from cinder_contexts import ceph_config_file COMMON_PACKAGES = [ - 'apache2', 'cinder-common', 'gdisk', - 'haproxy', 'librbd1', # bug 1440948 vol-from-img 'python-jinja2', 'python-keystoneclient', @@ -137,10 +135,15 @@ PY3_PACKAGES = [ 'python3-memcache', 'python3-rados', 'python3-rbd', - 'libapache2-mod-wsgi-py3', ] -API_PACKAGES = ['cinder-api'] +PY3_API_PACKAGES = ['libapache2-mod-wsgi-py3'] + +API_PACKAGES = [ + 'apache2', + 'cinder-api', + 'haproxy', +] VOLUME_PACKAGES = ['cinder-volume'] SCHEDULER_PACKAGES = ['cinder-scheduler'] @@ -156,6 +159,7 @@ CINDER_DB_INIT_ECHO_RKEY = 'cinder-db-initialised-echo' class CinderCharmError(Exception): pass + CINDER_CONF_DIR = "/etc/cinder" CINDER_CONF = '%s/cinder.conf' % CINDER_CONF_DIR CINDER_API_CONF = '%s/api-paste.ini' % CINDER_CONF_DIR @@ -320,7 +324,18 @@ def resource_map(release=None): 'contexts': [context.MemcacheContext()], 'services': ['memcached']} - if run_in_apache(): + if not service_enabled('api'): + # haproxy and apache2 are related to cinder-api + cfg_files = { + CINDER_API_CONF, + HAPROXY_CONF, + APACHE_SITE_CONF, + APACHE_SITE_24_CONF, + APACHE_PORTS_CONF, + } + for cfg in cfg_files.intersection(resource_map.keys()): + resource_map.pop(cfg) + elif run_in_apache(): for cfile in resource_map: svcs = resource_map[cfile]['services'] if 'cinder-api' in svcs: @@ -347,9 +362,13 @@ def filter_services(svcs): @param svcs: List of services @returns : List of enabled services ''' + deps = { + 'haproxy': 'api', + 'apache2': 'api', + } return [s for s in svcs if service_enabled(s.lstrip('cinder-')) or - not s.startswith('cinder')] + (deps.get(s) and service_enabled(deps[s]))] def juju_log(msg): @@ -373,6 +392,8 @@ def determine_packages(): if CompareOpenStackReleases(os_release('cinder')) >= 'rocky': pkgs = [p for p in pkgs if not p.startswith('python-')] pkgs.extend(PY3_PACKAGES) + if service_enabled('api'): + pkgs.extend(PY3_API_PACKAGES) return pkgs @@ -798,7 +819,7 @@ def do_openstack_upgrade(configs=None): configs.set_release(openstack_release=new_os_rel) configs.write_all() - if run_in_apache(): + if service_enabled('api') and run_in_apache(): disable_package_apache_site() # Stop/start services and migrate DB if leader diff --git a/tests/bundles/focal-ussuri-volume-only.yaml b/tests/bundles/focal-ussuri-volume-only.yaml new file mode 100644 index 00000000..741c736e --- /dev/null +++ b/tests/bundles/focal-ussuri-volume-only.yaml @@ -0,0 +1,293 @@ +variables: + openstack-origin: &openstack-origin distro + +series: focal + +comment: +- 'machines section to decide order of deployment. database sooner = faster' +machines: + '0': + constraints: mem=3072M + '1': + constraints: mem=3072M + '2': + constraints: mem=3072M + '3': + '4': + '5': + '6': + '7': + '8': + '9': + '10': + '11': + '12': + '13': + '14': + +applications: + + nova-cloud-controller-mysql-router: + charm: cs:~openstack-charmers-next/mysql-router + placement-mysql-router: + charm: cs:~openstack-charmers-next/mysql-router + keystone-mysql-router: + charm: cs:~openstack-charmers-next/mysql-router + glance-mysql-router: + charm: cs:~openstack-charmers-next/mysql-router + neutron-api-mysql-router: + charm: cs:~openstack-charmers-next/mysql-router + cinder-mysql-router: + charm: cs:~openstack-charmers-next/mysql-router + + mysql-innodb-cluster: + charm: cs:~openstack-charmers-next/mysql-innodb-cluster + num_units: 3 + options: + source: *openstack-origin + to: + - '0' + - '1' + - '2' + + rabbitmq-server: + charm: cs:~openstack-charmers-next/rabbitmq-server + num_units: 1 + options: + source: *openstack-origin + to: + - '3' + + nova-cloud-controller: + charm: cs:~openstack-charmers-next/nova-cloud-controller + num_units: 1 + options: + network-manager: Neutron + debug: true + openstack-origin: *openstack-origin + to: + - '4' + + placement: + charm: cs:~openstack-charmers-next/placement + num_units: 1 + constraints: mem=1G + options: + openstack-origin: *openstack-origin + to: + - '5' + + neutron-api: + charm: cs:~openstack-charmers-next/neutron-api + num_units: 1 + options: + flat-network-providers: physnet1 + neutron-security-groups: true + manage-neutron-plugin-legacy-mode: true + openstack-origin: *openstack-origin + to: + - '6' + + keystone: + charm: cs:~openstack-charmers-next/keystone + num_units: 1 + options: + openstack-origin: *openstack-origin + to: + - '7' + + neutron-gateway: + charm: cs:~openstack-charmers-next/neutron-gateway + num_units: 1 + options: + bridge-mappings: physnet1:br-ex + openstack-origin: *openstack-origin + to: + - '8' + + glance: + charm: cs:~openstack-charmers-next/glance + num_units: 1 + options: + openstack-origin: *openstack-origin + to: + - '9' + + neutron-openvswitch: + charm: cs:~openstack-charmers-next/neutron-openvswitch + + nova-compute: + charm: cs:~openstack-charmers-next/nova-compute + num_units: 1 + constraints: mem=4G cores=4 + storage: + ephemeral-device: '10G' + options: + config-flags: auto_assign_floating_ip=False + enable-live-migration: false + aa-profile-mode: enforce + #ephemeral-device: /dev/vdb + #ephemeral-unmount: /mnt + debug: true + openstack-origin: *openstack-origin + to: + - '10' + + cinder: + num_units: 1 + options: + openstack-origin: *openstack-origin + glance-api-version: 2 + enabled-services: 'api,scheduler' + to: + - '11' + + cinder-volume: + charm: ../../. + num_units: 2 + storage: + block-devices: '40G' + options: + openstack-origin: *openstack-origin + glance-api-version: 2 + block-device: None + overwrite: "true" + enabled-services: 'volume' + to: + - '12' + - '13' + + vault-mysql-router: + charm: cs:~openstack-charmers-next/mysql-router + vault: + charm: cs:~openstack-charmers-next/vault + num_units: 1 + to: + - '14' + +relations: + + - - 'nova-compute:image-service' + - 'glance:image-service' + + - - 'nova-compute:amqp' + - 'rabbitmq-server:amqp' + + - - 'nova-cloud-controller:shared-db' + - 'nova-cloud-controller-mysql-router:shared-db' + - - 'nova-cloud-controller-mysql-router:db-router' + - 'mysql-innodb-cluster:db-router' + + - - 'nova-cloud-controller:identity-service' + - 'keystone:identity-service' + + - - 'nova-cloud-controller:amqp' + - 'rabbitmq-server:amqp' + + - - 'nova-cloud-controller:cloud-compute' + - 'nova-compute:cloud-compute' + + - - 'nova-cloud-controller:image-service' + - 'glance:image-service' + + - - 'placement:shared-db' + - 'placement-mysql-router:shared-db' + - - 'placement-mysql-router:db-router' + - 'mysql-innodb-cluster:db-router' + + - - 'placement:identity-service' + - 'keystone:identity-service' + + - - 'placement:placement' + - 'nova-cloud-controller:placement' + + - - 'keystone:shared-db' + - 'keystone-mysql-router:shared-db' + - - 'keystone-mysql-router:db-router' + - 'mysql-innodb-cluster:db-router' + + - - 'glance:identity-service' + - 'keystone:identity-service' + + - - 'glance:shared-db' + - 'glance-mysql-router:shared-db' + - - 'glance-mysql-router:db-router' + - 'mysql-innodb-cluster:db-router' + + - - 'glance:amqp' + - 'rabbitmq-server:amqp' + + - - 'neutron-gateway:amqp' + - 'rabbitmq-server:amqp' + + - - 'nova-cloud-controller:quantum-network-service' + - 'neutron-gateway:quantum-network-service' + + - - 'neutron-api:shared-db' + - 'neutron-api-mysql-router:shared-db' + - - 'neutron-api-mysql-router:db-router' + - 'mysql-innodb-cluster:db-router' + + - - 'neutron-api:amqp' + - 'rabbitmq-server:amqp' + + - - 'neutron-api:neutron-api' + - 'nova-cloud-controller:neutron-api' + + - - 'neutron-api:identity-service' + - 'keystone:identity-service' + + - - 'nova-compute:neutron-plugin' + - 'neutron-openvswitch:neutron-plugin' + + - - 'rabbitmq-server:amqp' + - 'neutron-openvswitch:amqp' + + - - 'cinder:shared-db' + - 'cinder-mysql-router:shared-db' + - - 'cinder-mysql-router:db-router' + - 'mysql-innodb-cluster:db-router' + + - - 'cinder:identity-service' + - 'keystone:identity-service' + + - - 'cinder:amqp' + - 'rabbitmq-server:amqp' + + - - 'cinder:image-service' + - 'glance:image-service' + + - - 'cinder-volume:identity-service' + - 'keystone:identity-service' + + - - 'cinder-volume:amqp' + - 'rabbitmq-server:amqp' + + - - 'cinder-volume:image-service' + - 'glance:image-service' + + - - 'cinder-volume:shared-db' + - 'cinder-mysql-router:shared-db' + + - - 'vault-mysql-router:db-router' + - 'mysql-innodb-cluster:db-router' + - - 'vault:shared-db' + - 'vault-mysql-router:shared-db' + + - - 'nova-cloud-controller:certificates' + - 'vault:certificates' + + - - 'neutron-api:certificates' + - 'vault:certificates' + + - - 'keystone:certificates' + - 'vault:certificates' + + - - 'glance:certificates' + - 'vault:certificates' + + - - 'cinder:certificates' + - 'vault:certificates' + + - - 'cinder-volume:certificates' + - 'vault:certificates' diff --git a/tests/tests.yaml b/tests/tests.yaml index e5b4e612..32e46468 100644 --- a/tests/tests.yaml +++ b/tests/tests.yaml @@ -3,6 +3,7 @@ smoke_bundles: - bionic-train gate_bundles: - focal-ussuri +- vault: focal-ussuri-volume-only - bionic-ussuri - bionic-train - bionic-stein @@ -15,6 +16,10 @@ gate_bundles: - trusty-mitaka dev_bundles: - focal-ussuri +target_deploy_status: + vault: + workload-status: blocked + workload-status-message: Vault needs to be initialized configure: - zaza.openstack.charm_tests.glance.setup.add_cirros_image - zaza.openstack.charm_tests.glance.setup.add_lts_image @@ -22,6 +27,8 @@ configure: - zaza.openstack.charm_tests.neutron.setup.basic_overcloud_network - zaza.openstack.charm_tests.nova.setup.create_flavors - zaza.openstack.charm_tests.nova.setup.manage_ssh_key +- vault: + - zaza.openstack.charm_tests.vault.setup.auto_initialize tests: - zaza.openstack.charm_tests.cinder.tests.CinderTests - zaza.openstack.charm_tests.cinder.tests.SecurityTests @@ -29,5 +36,3 @@ tests: tests_options: policyd: service: cinder - force_deploy: - - focal-ussuri diff --git a/unit_tests/test_cinder_utils.py b/unit_tests/test_cinder_utils.py index cd9d3593..f0d803ee 100644 --- a/unit_tests/test_cinder_utils.py +++ b/unit_tests/test_cinder_utils.py @@ -164,7 +164,8 @@ class TestCinderUtils(CharmTestCase): cinder_utils.VOLUME_PACKAGES + cinder_utils.API_PACKAGES + cinder_utils.SCHEDULER_PACKAGES + - cinder_utils.PY3_PACKAGES)) + cinder_utils.PY3_PACKAGES + + cinder_utils.PY3_API_PACKAGES)) @patch('cinder_utils.service_enabled') def test_determine_packages_subset(self, service_enabled): @@ -236,12 +237,8 @@ class TestCinderUtils(CharmTestCase): self.ceph_config_file.return_value = self.charm_ceph_conf self.relation_ids.return_value = [] ex_map = OrderedDict([ - ('/etc/cinder/cinder.conf', ['cinder-volume', 'cinder-scheduler', - 'haproxy']), - ('/etc/cinder/api-paste.ini', []), - ('/etc/haproxy/haproxy.cfg', ['haproxy']), - ('/etc/apache2/sites-available/openstack_https_frontend.conf', - ['apache2']), + ('/etc/cinder/cinder.conf', ['cinder-volume', + 'cinder-scheduler']), ]) for cfg in ex_map.keys(): self.assertEqual(cinder_utils.resource_map()[cfg]['services'], @@ -355,7 +352,7 @@ class TestCinderUtils(CharmTestCase): self.assertEqual( cinder_utils.filter_services(['cinder-api', 'cinder-volume', 'haproxy']), - ['cinder-volume', 'haproxy'] + ['cinder-volume'] ) @patch('cinder_utils.service_enabled') @@ -763,12 +760,13 @@ class TestCinderUtils(CharmTestCase): out.write('env CEPH_ARGS="--id %s"\n' % service) """ + @patch.object(cinder_utils, 'service_enabled') @patch.object(cinder_utils, 'register_configs') @patch.object(cinder_utils, 'services') @patch.object(cinder_utils, 'migrate_database') @patch.object(cinder_utils, 'determine_packages') def test_openstack_upgrade_leader(self, pkgs, migrate, services, - mock_register_configs): + mock_register_configs, service_enabled): pkgs.return_value = ['mypackage'] self.os_release.return_value = 'havana' self.config.side_effect = None @@ -777,6 +775,7 @@ class TestCinderUtils(CharmTestCase): self.is_elected_leader.return_value = True self.get_os_codename_install_source.return_value = 'havana' configs = mock_register_configs.return_value + service_enabled.return_value = True cinder_utils.do_openstack_upgrade(configs) self.assertTrue(mock_register_configs.called) self.assertTrue(configs.write_all.called) @@ -786,12 +785,14 @@ class TestCinderUtils(CharmTestCase): configs.set_release.assert_called_with(openstack_release='havana') self.assertTrue(migrate.called) + @patch.object(cinder_utils, 'service_enabled') @patch.object(cinder_utils, 'register_configs') @patch.object(cinder_utils, 'services') @patch.object(cinder_utils, 'migrate_database') @patch.object(cinder_utils, 'determine_packages') def test_openstack_upgrade_not_leader(self, pkgs, migrate, services, - mock_register_configs): + mock_register_configs, + service_enabled): pkgs.return_value = ['mypackage'] self.os_release.return_value = 'havana' self.config.side_effect = None @@ -800,6 +801,7 @@ class TestCinderUtils(CharmTestCase): self.is_elected_leader.return_value = False self.get_os_codename_install_source.return_value = 'havana' configs = mock_register_configs.return_value + service_enabled.return_value = True cinder_utils.do_openstack_upgrade(configs) self.assertTrue(mock_register_configs.called) self.assertTrue(configs.write_all.called) @@ -809,12 +811,14 @@ class TestCinderUtils(CharmTestCase): configs.set_release.assert_called_with(openstack_release='havana') self.assertFalse(migrate.called) + @patch.object(cinder_utils, 'service_enabled') @patch.object(cinder_utils, 'register_configs') @patch.object(cinder_utils, 'services') @patch.object(cinder_utils, 'migrate_database') @patch.object(cinder_utils, 'determine_packages') def test_openstack_upgrade_rocky(self, pkgs, migrate, services, - mock_register_configs): + mock_register_configs, + service_enabled): pkgs.return_value = ['mypackage'] self.os_release.return_value = 'rocky' self.config.side_effect = None @@ -823,6 +827,7 @@ class TestCinderUtils(CharmTestCase): self.is_elected_leader.return_value = True self.get_os_codename_install_source.return_value = 'rocky' configs = mock_register_configs.return_value + service_enabled.return_value = True self.filter_missing_packages.return_value = [ 'python-cinder', ]