diff --git a/hooks/nova_cc_utils.py b/hooks/nova_cc_utils.py index 0aa4ac8a..0b87b6df 100644 --- a/hooks/nova_cc_utils.py +++ b/hooks/nova_cc_utils.py @@ -321,10 +321,14 @@ SERIAL_CONSOLE = { } -def resource_map(return_services=True): +def resource_map(actual_services=True): ''' Dynamically generate a map of resources that will be managed for a single hook execution. + + :param actual_services: Whether to return the actual services that run on a + unit (ie. apache2) or the services defined in BASE_SERVICES + (ie.nova-placement-api). ''' resource_map = deepcopy(BASE_RESOURCE_MAP) @@ -367,7 +371,7 @@ def resource_map(return_services=True): 'contexts': [context.MemcacheContext()], 'services': ['memcached']} - if return_services and placement_api_enabled(): + if actual_services and placement_api_enabled(): for cfile in resource_map: svcs = resource_map[cfile]['services'] if 'nova-placement-api' in svcs: @@ -399,10 +403,18 @@ def register_configs(release=None): return configs -def restart_map(): - return OrderedDict([(cfg, v['services']) - for cfg, v in resource_map().iteritems() - if v['services']]) +def restart_map(actual_services=True): + ''' + Constructs a restart map of config files and corresponding services + + :param actual_services: Whether to return the actual services that run on a + unit (ie. apache2) or the services defined in BASE_SERVICES + (ie.nova-placement-api). + ''' + return OrderedDict( + [(cfg, v['services']) + for cfg, v in resource_map(actual_services).iteritems() + if v['services']]) def services(): @@ -416,7 +428,7 @@ def services(): def determine_ports(): '''Assemble a list of API ports for services we are managing''' ports = [] - for services in restart_map().values(): + for services in restart_map(actual_services=False).values(): for svc in services: try: ports.append(API_PORTS[svc]) @@ -453,7 +465,7 @@ def console_attributes(attr, proto=None): def determine_packages(): # currently all packages match service names packages = deepcopy(BASE_PACKAGES) - for v in resource_map(return_services=False).values(): + for v in resource_map(actual_services=False).values(): packages.extend(v['services']) if console_attributes('packages'): packages.extend(console_attributes('packages')) diff --git a/test-requirements.txt b/test-requirements.txt index 06972943..04ca6238 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -11,13 +11,13 @@ requests==2.6.0 # Liberty client lower constraints amulet>=1.14.3,<2.0 bundletester>=0.6.1,<1.0 -python-ceilometerclient>=1.5.0,<2.0 -python-cinderclient>=1.4.0,<2.0 -python-glanceclient>=1.1.0,<2.0 -python-heatclient>=0.8.0,<1.0 -python-novaclient>=2.30.1,<3.0 -python-openstackclient>=1.7.0,<2.0 -python-swiftclient>=2.6.0,<3.0 +python-ceilometerclient>=1.5.0 +python-cinderclient>=1.4.0 +python-glanceclient>=1.1.0 +python-heatclient>=0.8.0 +python-novaclient>=2.30.1 +python-openstackclient>=1.7.0 +python-swiftclient>=2.6.0 pika>=0.10.0,<1.0 distro-info # END: Amulet OpenStack Charm Helper Requirements diff --git a/tests/basic_deployment.py b/tests/basic_deployment.py index cd826eb7..c959aa34 100644 --- a/tests/basic_deployment.py +++ b/tests/basic_deployment.py @@ -90,6 +90,13 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment): {'name': 'glance'}, {'name': 'percona-cluster', 'constraints': {'mem': '3072M'}}, ] + if self._get_openstack_release() >= self.xenial_ocata: + other_ocata_services = [ + {'name': 'neutron-gateway'}, + {'name': 'neutron-api'}, + {'name': 'neutron-openvswitch'}, + ] + other_services += other_ocata_services super(NovaCCBasicDeployment, self)._add_services(this_service, other_services) @@ -109,8 +116,22 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment): 'keystone:shared-db': 'percona-cluster:shared-db', 'glance:identity-service': 'keystone:identity-service', 'glance:shared-db': 'percona-cluster:shared-db', - 'glance:amqp': 'rabbitmq-server:amqp' + 'glance:amqp': 'rabbitmq-server:amqp', } + if self._get_openstack_release() >= self.xenial_ocata: + ocata_relations = { + 'neutron-gateway:amqp': 'rabbitmq-server:amqp', + 'nova-cloud-controller:quantum-network-service': + 'neutron-gateway:quantum-network-service', + 'neutron-api:shared-db': 'percona-cluster:shared-db', + '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', + } + relations.update(ocata_relations) super(NovaCCBasicDeployment, self)._add_relations(relations) def _configure_services(self): @@ -159,6 +180,9 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment): nova_cc_config['api-rate-limit-rules'] = \ "( POST, '*', .*, 9999, MINUTE );" + if self._get_openstack_release() >= self.xenial_ocata: + nova_cc_config['network-manager'] = 'Neutron' + keystone_config = {'admin-password': 'openstack', 'admin-token': 'ubuntutesting'} @@ -259,6 +283,10 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment): if self._get_openstack_release() >= self.trusty_liberty: services[self.keystone_sentry] = ['apache2'] + if self._get_openstack_release() >= self.xenial_ocata: + services[self.nova_compute_sentry].remove('nova-network') + services[self.nova_compute_sentry].remove('nova-api') + ret = u.validate_services_by_name(services) if ret: amulet.raise_status(amulet.FAIL, msg=ret) @@ -423,6 +451,13 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment): expected['ec2_region'] = 'RegionOne' expected['ec2_service'] = 'ec2' + if self._get_openstack_release() >= self.xenial_ocata: + expected['placement_service'] = 'placement' + expected['placement_internal_url'] = u.valid_url + expected['placement_public_url'] = u.valid_url + expected['placement_admin_url'] = u.valid_url + expected['placement_region'] = 'RegionOne' + ret = u.validate_relation_data(unit, relation, expected) if ret: message = u.relation_error('nova-cc identity-service', ret) @@ -451,6 +486,9 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment): if self._get_openstack_release() >= self.trusty_kilo: expected['service_username'] = 'nova' + if self._get_openstack_release() >= self.xenial_ocata: + expected['service_username'] = 'placement_nova' + ret = u.validate_relation_data(unit, relation, expected) if ret: message = u.relation_error('keystone identity-service', ret) @@ -502,6 +540,8 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment): 'private-address': u.valid_ip, 'restart_trigger': u.not_null } + if self._get_openstack_release() >= self.xenial_ocata: + expected['network_manager'] = 'neutron' ret = u.validate_relation_data(unit, relation, expected) if ret: @@ -706,6 +746,10 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment): 'enabled_apis': 'osapi_compute,metadata', }) + if self._get_openstack_release() >= self.xenial_ocata: + expected['DEFAULT']['use_neutron'] = 'True' + del expected['DEFAULT']['network_manager'] + for section, pairs in expected.iteritems(): ret = u.validate_config_data(unit, conf, section, pairs) if ret: diff --git a/tests/charmhelpers/contrib/openstack/amulet/utils.py b/tests/charmhelpers/contrib/openstack/amulet/utils.py index 401c0328..1f4cf42e 100644 --- a/tests/charmhelpers/contrib/openstack/amulet/utils.py +++ b/tests/charmhelpers/contrib/openstack/amulet/utils.py @@ -32,6 +32,7 @@ from keystoneclient.v3 import client as keystone_client_v3 from novaclient import exceptions import novaclient.client as nova_client +import novaclient import pika import swiftclient @@ -434,9 +435,14 @@ class OpenStackAmuletUtils(AmuletUtils): self.log.debug('Authenticating nova user ({})...'.format(user)) ep = keystone.service_catalog.url_for(service_type='identity', endpoint_type='publicURL') - return nova_client.Client(NOVA_CLIENT_VERSION, - username=user, api_key=password, - project_id=tenant, auth_url=ep) + if novaclient.__version__[0] >= "7": + return nova_client.Client(NOVA_CLIENT_VERSION, + username=user, password=password, + project_name=tenant, auth_url=ep) + else: + return nova_client.Client(NOVA_CLIENT_VERSION, + username=user, api_key=password, + project_id=tenant, auth_url=ep) def authenticate_swift_user(self, keystone, user, password, tenant): """Authenticates a regular user with swift api.""" diff --git a/tests/gate-basic-xenial-ocata b/tests/gate-basic-xenial-ocata old mode 100644 new mode 100755 diff --git a/unit_tests/test_nova_cc_utils.py b/unit_tests/test_nova_cc_utils.py index b4bde45c..6d171eaa 100644 --- a/unit_tests/test_nova_cc_utils.py +++ b/unit_tests/test_nova_cc_utils.py @@ -115,7 +115,7 @@ RESTART_MAP_ICEHOUSE = OrderedDict([ ('/etc/haproxy/haproxy.cfg', ['haproxy']), ('/etc/apache2/sites-available/openstack_https_frontend', ['apache2']), ]) -RESTART_MAP_OCATA = OrderedDict([ +RESTART_MAP_OCATA_ACTUAL = OrderedDict([ ('/etc/nova/nova.conf', [ 'nova-api-ec2', 'nova-api-os-compute', 'nova-objectstore', 'nova-cert', 'nova-scheduler', 'nova-conductor', 'apache2' @@ -127,6 +127,17 @@ RESTART_MAP_OCATA = OrderedDict([ ('/etc/apache2/sites-available/openstack_https_frontend', ['apache2']), ('/etc/apache2/sites-enabled/wsgi-openstack-api.conf', ['apache2']), ]) +RESTART_MAP_OCATA_BASE = OrderedDict([ + ('/etc/nova/nova.conf', [ + 'nova-api-ec2', 'nova-api-os-compute', 'nova-placement-api', + 'nova-objectstore', 'nova-cert', 'nova-scheduler', 'nova-conductor' + ]), + ('/etc/nova/api-paste.ini', [ + 'nova-api-ec2', 'nova-api-os-compute', 'nova-placement-api' + ]), + ('/etc/haproxy/haproxy.cfg', ['haproxy']), + ('/etc/apache2/sites-available/openstack_https_frontend', ['apache2']) +]) DPKG_OPTS = [ @@ -267,8 +278,8 @@ class NovaCCUtilsTests(CharmTestCase): @patch('charmhelpers.contrib.openstack.neutron.os_release') @patch('os.path.exists') @patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext') - def test_restart_map_api_before_frontends_ocata(self, subcontext, - _exists, _os_release): + def test_restart_map_api_actual_ocata(self, subcontext, + _exists, _os_release): _os_release.return_value = 'ocata' self.os_release.return_value = 'ocata' _exists.return_value = False @@ -276,7 +287,21 @@ class NovaCCUtilsTests(CharmTestCase): self._resource_map() _map = utils.restart_map() self.assertIsInstance(_map, OrderedDict) - self.assertEquals(_map, RESTART_MAP_OCATA) + self.assertEquals(_map, RESTART_MAP_OCATA_ACTUAL) + + @patch('charmhelpers.contrib.openstack.neutron.os_release') + @patch('os.path.exists') + @patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext') + def test_restart_map_api_ocata_base(self, subcontext, + _exists, _os_release): + _os_release.return_value = 'ocata' + self.os_release.return_value = 'ocata' + _exists.return_value = False + self.enable_memcache.return_value = False + self._resource_map() + _map = utils.restart_map(actual_services=False) + self.assertIsInstance(_map, OrderedDict) + self.assertEquals(_map, RESTART_MAP_OCATA_BASE) @patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext') @patch('os.path.exists')