8dd2af43c1
Running nova-api-metadata service on mitaka with keystone v3 enabled currently fails to authenticate when querying the neutron server. This is because it is not passing the project and user domain information. this change adds that in as per the Mitaka installation guide. Change-Id: Id6921392a634585f9551e64ec12e42460252d2e5
1076 lines
44 KiB
Python
1076 lines
44 KiB
Python
import amulet
|
|
import os
|
|
import yaml
|
|
import time
|
|
import subprocess
|
|
import json
|
|
|
|
from neutronclient.v2_0 import client as neutronclient
|
|
|
|
from charmhelpers.contrib.openstack.amulet.deployment import (
|
|
OpenStackAmuletDeployment
|
|
)
|
|
|
|
from charmhelpers.contrib.openstack.amulet.utils import (
|
|
OpenStackAmuletUtils,
|
|
DEBUG,
|
|
# ERROR
|
|
)
|
|
|
|
# Use DEBUG to turn on debug logging
|
|
u = OpenStackAmuletUtils(DEBUG)
|
|
|
|
|
|
class NeutronGatewayBasicDeployment(OpenStackAmuletDeployment):
|
|
"""Amulet tests on a basic neutron-gateway deployment."""
|
|
|
|
def __init__(self, series, openstack=None, source=None, git=False,
|
|
stable=False):
|
|
"""Deploy the entire test environment."""
|
|
super(NeutronGatewayBasicDeployment, self).__init__(series, openstack,
|
|
source, stable)
|
|
self.git = git
|
|
self._add_services()
|
|
self._add_relations()
|
|
self._configure_services()
|
|
self._deploy()
|
|
|
|
u.log.info('Waiting on extended status checks...')
|
|
exclude_services = ['mysql']
|
|
self._auto_wait_for_status(exclude_services=exclude_services)
|
|
|
|
self._initialize_tests()
|
|
|
|
def _add_services(self):
|
|
"""Add services
|
|
|
|
Add the services that we're testing, where neutron-gateway is local,
|
|
and the rest of the service are from lp branches that are
|
|
compatible with the local charm (e.g. stable or next).
|
|
"""
|
|
this_service = {'name': 'neutron-gateway'}
|
|
other_services = [{'name': 'mysql'},
|
|
{'name': 'rabbitmq-server'},
|
|
{'name': 'keystone'},
|
|
{'name': 'glance'}, # satisfy workload status
|
|
{'name': 'nova-cloud-controller'},
|
|
{'name': 'nova-compute'}, # satisfy workload stat
|
|
{'name': 'neutron-openvswitch'},
|
|
{'name': 'neutron-api'}]
|
|
|
|
super(NeutronGatewayBasicDeployment, self)._add_services(
|
|
this_service, other_services)
|
|
|
|
def _add_relations(self):
|
|
"""Add all of the relations for the services."""
|
|
relations = {
|
|
'keystone:shared-db': 'mysql:shared-db',
|
|
'neutron-gateway:amqp': 'rabbitmq-server:amqp',
|
|
'nova-cloud-controller:quantum-network-service':
|
|
'neutron-gateway:quantum-network-service',
|
|
'nova-cloud-controller:shared-db': 'mysql:shared-db',
|
|
'nova-cloud-controller:identity-service': 'keystone:'
|
|
'identity-service',
|
|
'nova-cloud-controller:amqp': 'rabbitmq-server:amqp',
|
|
'neutron-api:shared-db': 'mysql:shared-db',
|
|
'neutron-api:amqp': 'rabbitmq-server:amqp',
|
|
'neutron-api:neutron-api': 'nova-cloud-controller:neutron-api',
|
|
'neutron-api:identity-service': 'keystone:identity-service',
|
|
'glance:identity-service': 'keystone:identity-service',
|
|
'glance:shared-db': 'mysql:shared-db',
|
|
'glance:amqp': 'rabbitmq-server:amqp',
|
|
'nova-cloud-controller:cloud-compute': 'nova-compute:'
|
|
'cloud-compute',
|
|
'nova-compute:amqp': 'rabbitmq-server:amqp',
|
|
'nova-compute:neutron-plugin': 'neutron-openvswitch:'
|
|
'neutron-plugin',
|
|
'rabbitmq-server:amqp': 'neutron-openvswitch:amqp',
|
|
'nova-compute:image-service': 'glance:image-service',
|
|
'nova-cloud-controller:image-service': 'glance:image-service',
|
|
}
|
|
super(NeutronGatewayBasicDeployment, self)._add_relations(relations)
|
|
|
|
def _configure_services(self):
|
|
"""Configure all of the services."""
|
|
neutron_gateway_config = {}
|
|
if self.git:
|
|
amulet_http_proxy = os.environ.get('AMULET_HTTP_PROXY')
|
|
|
|
branch = 'stable/' + self._get_openstack_release_string()
|
|
|
|
if self._get_openstack_release() >= self.trusty_kilo:
|
|
openstack_origin_git = {
|
|
'repositories': [
|
|
{'name': 'requirements',
|
|
'repository': 'git://github.com/openstack/requirements', # noqa
|
|
'branch': branch},
|
|
{'name': 'neutron-fwaas',
|
|
'repository': 'git://github.com/openstack/neutron-fwaas', # noqa
|
|
'branch': branch},
|
|
{'name': 'neutron-lbaas',
|
|
'repository': 'git://github.com/openstack/neutron-lbaas', # noqa
|
|
'branch': branch},
|
|
{'name': 'neutron-vpnaas',
|
|
'repository': 'git://github.com/openstack/neutron-vpnaas', # noqa
|
|
'branch': branch},
|
|
{'name': 'neutron',
|
|
'repository': 'git://github.com/openstack/neutron',
|
|
'branch': branch},
|
|
],
|
|
'directory': '/mnt/openstack-git',
|
|
'http_proxy': amulet_http_proxy,
|
|
'https_proxy': amulet_http_proxy,
|
|
}
|
|
else:
|
|
reqs_repo = 'git://github.com/openstack/requirements'
|
|
neutron_repo = 'git://github.com/openstack/neutron'
|
|
if self._get_openstack_release() == self.trusty_icehouse:
|
|
reqs_repo = 'git://github.com/coreycb/requirements'
|
|
neutron_repo = 'git://github.com/coreycb/neutron'
|
|
|
|
openstack_origin_git = {
|
|
'repositories': [
|
|
{'name': 'requirements',
|
|
'repository': reqs_repo,
|
|
'branch': branch},
|
|
{'name': 'neutron',
|
|
'repository': neutron_repo,
|
|
'branch': branch},
|
|
],
|
|
'directory': '/mnt/openstack-git',
|
|
'http_proxy': amulet_http_proxy,
|
|
'https_proxy': amulet_http_proxy,
|
|
}
|
|
|
|
neutron_gateway_config['openstack-origin-git'] = \
|
|
yaml.dump(openstack_origin_git)
|
|
|
|
keystone_config = {'admin-password': 'openstack',
|
|
'admin-token': 'ubuntutesting'}
|
|
nova_cc_config = {'network-manager': 'Neutron'}
|
|
configs = {'neutron-gateway': neutron_gateway_config,
|
|
'keystone': keystone_config,
|
|
'nova-cloud-controller': nova_cc_config}
|
|
super(NeutronGatewayBasicDeployment, self)._configure_services(configs)
|
|
|
|
def _run_action(self, unit_id, action, *args):
|
|
command = ["juju", "action", "do", "--format=json", unit_id, action]
|
|
command.extend(args)
|
|
output = subprocess.check_output(command)
|
|
output_json = output.decode(encoding="UTF-8")
|
|
data = json.loads(output_json)
|
|
action_id = data[u'Action queued with id']
|
|
return action_id
|
|
|
|
def _wait_on_action(self, action_id):
|
|
command = ["juju", "action", "fetch", "--format=json", action_id]
|
|
while True:
|
|
try:
|
|
output = subprocess.check_output(command)
|
|
except Exception as e:
|
|
print(e)
|
|
return False
|
|
output_json = output.decode(encoding="UTF-8")
|
|
data = json.loads(output_json)
|
|
if data[u"status"] == "completed":
|
|
return True
|
|
elif data[u"status"] == "failed":
|
|
return False
|
|
time.sleep(2)
|
|
|
|
def _initialize_tests(self):
|
|
"""Perform final initialization before tests get run."""
|
|
# Access the sentries for inspecting service units
|
|
self.mysql_sentry = self.d.sentry.unit['mysql/0']
|
|
self.keystone_sentry = self.d.sentry.unit['keystone/0']
|
|
self.rmq_sentry = self.d.sentry.unit['rabbitmq-server/0']
|
|
self.nova_cc_sentry = self.d.sentry.unit['nova-cloud-controller/0']
|
|
self.neutron_gateway_sentry = self.d.sentry.unit['neutron-gateway/0']
|
|
self.neutron_api_sentry = self.d.sentry.unit['neutron-api/0']
|
|
|
|
# Authenticate admin with keystone
|
|
self.keystone = u.authenticate_keystone_admin(self.keystone_sentry,
|
|
user='admin',
|
|
password='openstack',
|
|
tenant='admin')
|
|
|
|
# Authenticate admin with neutron
|
|
ep = self.keystone.service_catalog.url_for(service_type='identity',
|
|
endpoint_type='publicURL')
|
|
self.neutron = neutronclient.Client(auth_url=ep,
|
|
username='admin',
|
|
password='openstack',
|
|
tenant_name='admin',
|
|
region_name='RegionOne')
|
|
|
|
def get_private_address(self, unit):
|
|
"""Return the private address of the given sentry unit."""
|
|
address, retcode = unit.run('unit-get private-address')
|
|
assert retcode == 0, 'error retrieving unit private address'
|
|
return address.strip()
|
|
|
|
def test_100_services(self):
|
|
"""Verify the expected services are running on the corresponding
|
|
service units."""
|
|
neutron_services = ['neutron-dhcp-agent',
|
|
'neutron-lbaas-agent',
|
|
'neutron-metadata-agent',
|
|
'neutron-metering-agent',
|
|
'neutron-ovs-cleanup',
|
|
'neutron-plugin-openvswitch-agent']
|
|
|
|
if self._get_openstack_release() <= self.trusty_juno:
|
|
neutron_services.append('neutron-vpn-agent')
|
|
if self._get_openstack_release() >= self.trusty_mitaka:
|
|
# neutron-plugin-openvswitch-agent -> neutron-openvswitch-agent
|
|
neutron_services.remove('neutron-plugin-openvswitch-agent')
|
|
neutron_services.append('neutron-openvswitch-agent')
|
|
|
|
nova_cc_services = ['nova-api-ec2',
|
|
'nova-api-os-compute',
|
|
'nova-objectstore',
|
|
'nova-cert',
|
|
'nova-scheduler',
|
|
'nova-conductor']
|
|
|
|
if self._get_openstack_release_string() >= 'liberty':
|
|
nova_cc_services.remove('nova-api-ec2')
|
|
nova_cc_services.remove('nova-objectstore')
|
|
|
|
commands = {
|
|
self.mysql_sentry: ['mysql'],
|
|
self.keystone_sentry: ['keystone'],
|
|
self.nova_cc_sentry: nova_cc_services,
|
|
self.neutron_gateway_sentry: neutron_services
|
|
}
|
|
|
|
if self._get_openstack_release() >= self.trusty_liberty:
|
|
commands[self.keystone_sentry] = ['apache2']
|
|
|
|
ret = u.validate_services_by_name(commands)
|
|
if ret:
|
|
amulet.raise_status(amulet.FAIL, msg=ret)
|
|
|
|
def test_102_service_catalog(self):
|
|
"""Verify that the service catalog endpoint data is valid."""
|
|
u.log.debug('Checking keystone service catalog...')
|
|
endpoint_check = {
|
|
'adminURL': u.valid_url,
|
|
'id': u.not_null,
|
|
'region': 'RegionOne',
|
|
'publicURL': u.valid_url,
|
|
'internalURL': u.valid_url
|
|
}
|
|
expected = {
|
|
'network': [endpoint_check],
|
|
'compute': [endpoint_check],
|
|
'identity': [endpoint_check]
|
|
}
|
|
actual = self.keystone.service_catalog.get_endpoints()
|
|
|
|
ret = u.validate_svc_catalog_endpoint_data(expected, actual)
|
|
if ret:
|
|
amulet.raise_status(amulet.FAIL, msg=ret)
|
|
|
|
def test_104_network_endpoint(self):
|
|
"""Verify the neutron network endpoint data."""
|
|
u.log.debug('Checking neutron network api endpoint data...')
|
|
endpoints = self.keystone.endpoints.list()
|
|
admin_port = internal_port = public_port = '9696'
|
|
expected = {
|
|
'id': u.not_null,
|
|
'region': 'RegionOne',
|
|
'adminurl': u.valid_url,
|
|
'internalurl': u.valid_url,
|
|
'publicurl': u.valid_url,
|
|
'service_id': u.not_null
|
|
}
|
|
ret = u.validate_endpoint_data(endpoints, admin_port, internal_port,
|
|
public_port, expected)
|
|
|
|
if ret:
|
|
amulet.raise_status(amulet.FAIL,
|
|
msg='glance endpoint: {}'.format(ret))
|
|
|
|
def test_110_users(self):
|
|
"""Verify expected users."""
|
|
u.log.debug('Checking keystone users...')
|
|
expected = [
|
|
{'name': 'admin',
|
|
'enabled': True,
|
|
'tenantId': u.not_null,
|
|
'id': u.not_null,
|
|
'email': 'juju@localhost'},
|
|
{'name': 'neutron',
|
|
'enabled': True,
|
|
'tenantId': u.not_null,
|
|
'id': u.not_null,
|
|
'email': 'juju@localhost'}
|
|
]
|
|
|
|
if self._get_openstack_release() >= self.trusty_kilo:
|
|
# Kilo or later
|
|
expected.append({
|
|
'name': 'nova',
|
|
'enabled': True,
|
|
'tenantId': u.not_null,
|
|
'id': u.not_null,
|
|
'email': 'juju@localhost'
|
|
})
|
|
else:
|
|
# Juno and earlier
|
|
expected.append({
|
|
'name': 's3_ec2_nova',
|
|
'enabled': True,
|
|
'tenantId': u.not_null,
|
|
'id': u.not_null,
|
|
'email': 'juju@localhost'
|
|
})
|
|
|
|
actual = self.keystone.users.list()
|
|
ret = u.validate_user_data(expected, actual)
|
|
if ret:
|
|
amulet.raise_status(amulet.FAIL, msg=ret)
|
|
|
|
def test_202_neutron_gateway_rabbitmq_amqp_relation(self):
|
|
"""Verify the neutron-gateway to rabbitmq-server amqp relation data"""
|
|
u.log.debug('Checking neutron-gateway:rmq amqp relation data...')
|
|
unit = self.neutron_gateway_sentry
|
|
relation = ['amqp', 'rabbitmq-server:amqp']
|
|
expected = {
|
|
'username': 'neutron',
|
|
'private-address': u.valid_ip,
|
|
'vhost': 'openstack'
|
|
}
|
|
|
|
ret = u.validate_relation_data(unit, relation, expected)
|
|
if ret:
|
|
message = u.relation_error('neutron-gateway amqp', ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_203_rabbitmq_neutron_gateway_amqp_relation(self):
|
|
"""Verify the rabbitmq-server to neutron-gateway amqp relation data"""
|
|
u.log.debug('Checking rmq:neutron-gateway amqp relation data...')
|
|
unit = self.rmq_sentry
|
|
relation = ['amqp', 'neutron-gateway:amqp']
|
|
expected = {
|
|
'private-address': u.valid_ip,
|
|
'password': u.not_null,
|
|
'hostname': u.valid_ip
|
|
}
|
|
|
|
ret = u.validate_relation_data(unit, relation, expected)
|
|
if ret:
|
|
message = u.relation_error('rabbitmq amqp', ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_204_neutron_gateway_network_service_relation(self):
|
|
"""Verify the neutron-gateway to nova-cc quantum-network-service
|
|
relation data"""
|
|
u.log.debug('Checking neutron-gateway:nova-cc net svc '
|
|
'relation data...')
|
|
unit = self.neutron_gateway_sentry
|
|
relation = ['quantum-network-service',
|
|
'nova-cloud-controller:quantum-network-service']
|
|
expected = {
|
|
'private-address': u.valid_ip
|
|
}
|
|
|
|
ret = u.validate_relation_data(unit, relation, expected)
|
|
if ret:
|
|
message = u.relation_error('neutron-gateway network-service', ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_205_nova_cc_network_service_relation(self):
|
|
"""Verify the nova-cc to neutron-gateway quantum-network-service
|
|
relation data"""
|
|
u.log.debug('Checking nova-cc:neutron-gateway net svc '
|
|
'relation data...')
|
|
unit = self.nova_cc_sentry
|
|
relation = ['quantum-network-service',
|
|
'neutron-gateway:quantum-network-service']
|
|
expected = {
|
|
'service_protocol': 'http',
|
|
'service_tenant': 'services',
|
|
'quantum_url': u.valid_url,
|
|
'quantum_port': '9696',
|
|
'service_port': '5000',
|
|
'region': 'RegionOne',
|
|
'service_password': u.not_null,
|
|
'quantum_host': u.valid_ip,
|
|
'auth_port': '35357',
|
|
'auth_protocol': 'http',
|
|
'private-address': u.valid_ip,
|
|
'keystone_host': u.valid_ip,
|
|
'quantum_plugin': 'ovs',
|
|
'auth_host': u.valid_ip,
|
|
'service_tenant_name': 'services'
|
|
}
|
|
|
|
if self._get_openstack_release() >= self.trusty_kilo:
|
|
# Kilo or later
|
|
expected['service_username'] = 'nova'
|
|
else:
|
|
# Juno or earlier
|
|
expected['service_username'] = 's3_ec2_nova'
|
|
|
|
ret = u.validate_relation_data(unit, relation, expected)
|
|
if ret:
|
|
message = u.relation_error('nova-cc network-service', ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_206_neutron_api_shared_db_relation(self):
|
|
"""Verify the neutron-api to mysql shared-db relation data"""
|
|
u.log.debug('Checking neutron-api:mysql db relation data...')
|
|
unit = self.neutron_api_sentry
|
|
relation = ['shared-db', 'mysql:shared-db']
|
|
expected = {
|
|
'private-address': u.valid_ip,
|
|
'database': 'neutron',
|
|
'username': 'neutron',
|
|
'hostname': u.valid_ip
|
|
}
|
|
|
|
ret = u.validate_relation_data(unit, relation, expected)
|
|
if ret:
|
|
message = u.relation_error('neutron-api shared-db', ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_207_shared_db_neutron_api_relation(self):
|
|
"""Verify the mysql to neutron-api shared-db relation data"""
|
|
u.log.debug('Checking mysql:neutron-api db relation data...')
|
|
unit = self.mysql_sentry
|
|
relation = ['shared-db', 'neutron-api:shared-db']
|
|
expected = {
|
|
'db_host': u.valid_ip,
|
|
'private-address': u.valid_ip,
|
|
'password': u.not_null,
|
|
'allowed_units': u.not_null,
|
|
}
|
|
|
|
ret = u.validate_relation_data(unit, relation, expected)
|
|
if ret:
|
|
message = u.relation_error('mysql shared-db', ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
relation_data = unit.relation(relation[0], relation[1])
|
|
allowed_units = relation_data['allowed_units'].split()
|
|
if 'neutron-api/0' not in allowed_units:
|
|
message = 'neutron-api/0 not found in allowed_units'
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_208_neutron_api_amqp_relation(self):
|
|
"""Verify the neutron-api to rabbitmq-server amqp relation data"""
|
|
u.log.debug('Checking neutron-api:amqp relation data...')
|
|
unit = self.neutron_api_sentry
|
|
relation = ['amqp', 'rabbitmq-server:amqp']
|
|
expected = {
|
|
'username': 'neutron',
|
|
'private-address': u.valid_ip,
|
|
'vhost': 'openstack'
|
|
}
|
|
|
|
ret = u.validate_relation_data(unit, relation, expected)
|
|
if ret:
|
|
message = u.relation_error('neutron-api amqp', ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_209_amqp_neutron_api_relation(self):
|
|
"""Verify the rabbitmq-server to neutron-api amqp relation data"""
|
|
u.log.debug('Checking amqp:neutron-api relation data...')
|
|
unit = self.rmq_sentry
|
|
relation = ['amqp', 'neutron-api:amqp']
|
|
expected = {
|
|
'hostname': u.valid_ip,
|
|
'private-address': u.valid_ip,
|
|
'password': u.not_null
|
|
}
|
|
|
|
ret = u.validate_relation_data(unit, relation, expected)
|
|
if ret:
|
|
message = u.relation_error('rabbitmq amqp', ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_210_neutron_api_keystone_identity_relation(self):
|
|
"""Verify the neutron-api to keystone identity-service relation data"""
|
|
u.log.debug('Checking neutron-api:keystone id relation data...')
|
|
unit = self.neutron_api_sentry
|
|
relation = ['identity-service', 'keystone:identity-service']
|
|
api_ip = unit.relation('identity-service',
|
|
'keystone:identity-service')['private-address']
|
|
api_endpoint = 'http://{}:9696'.format(api_ip)
|
|
expected = {
|
|
'private-address': u.valid_ip,
|
|
'neutron_region': 'RegionOne',
|
|
'neutron_service': 'neutron',
|
|
'neutron_admin_url': api_endpoint,
|
|
'neutron_internal_url': api_endpoint,
|
|
'neutron_public_url': api_endpoint,
|
|
}
|
|
|
|
ret = u.validate_relation_data(unit, relation, expected)
|
|
if ret:
|
|
message = u.relation_error('neutron-api identity-service', ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_211_keystone_neutron_api_identity_relation(self):
|
|
"""Verify the keystone to neutron-api identity-service relation data"""
|
|
u.log.debug('Checking keystone:neutron-api id relation data...')
|
|
unit = self.keystone_sentry
|
|
relation = ['identity-service', 'neutron-api:identity-service']
|
|
rel_ks_id = unit.relation('identity-service',
|
|
'neutron-api:identity-service')
|
|
id_ip = rel_ks_id['private-address']
|
|
expected = {
|
|
'admin_token': 'ubuntutesting',
|
|
'auth_host': id_ip,
|
|
'auth_port': "35357",
|
|
'auth_protocol': 'http',
|
|
'private-address': id_ip,
|
|
'service_host': id_ip,
|
|
}
|
|
ret = u.validate_relation_data(unit, relation, expected)
|
|
if ret:
|
|
message = u.relation_error('neutron-api identity-service', ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_212_neutron_api_novacc_relation(self):
|
|
"""Verify the neutron-api to nova-cloud-controller relation data"""
|
|
u.log.debug('Checking neutron-api:novacc relation data...')
|
|
unit = self.neutron_api_sentry
|
|
relation = ['neutron-api', 'nova-cloud-controller:neutron-api']
|
|
api_ip = unit.relation('identity-service',
|
|
'keystone:identity-service')['private-address']
|
|
api_endpoint = 'http://{}:9696'.format(api_ip)
|
|
expected = {
|
|
'private-address': api_ip,
|
|
'neutron-plugin': 'ovs',
|
|
'neutron-security-groups': "no",
|
|
'neutron-url': api_endpoint,
|
|
}
|
|
ret = u.validate_relation_data(unit, relation, expected)
|
|
if ret:
|
|
message = u.relation_error('neutron-api neutron-api', ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_213_novacc_neutron_api_relation(self):
|
|
"""Verify the nova-cloud-controller to neutron-api relation data"""
|
|
u.log.debug('Checking novacc:neutron-api relation data...')
|
|
unit = self.nova_cc_sentry
|
|
relation = ['neutron-api', 'neutron-api:neutron-api']
|
|
cc_ip = unit.relation('neutron-api',
|
|
'neutron-api:neutron-api')['private-address']
|
|
cc_endpoint = 'http://{}:8774/v2'.format(cc_ip)
|
|
expected = {
|
|
'private-address': cc_ip,
|
|
'nova_url': cc_endpoint,
|
|
}
|
|
ret = u.validate_relation_data(unit, relation, expected)
|
|
if ret:
|
|
message = u.relation_error('nova-cc neutron-api', ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_300_neutron_config(self):
|
|
"""Verify the data in the neutron config file."""
|
|
u.log.debug('Checking neutron gateway config file data...')
|
|
unit = self.neutron_gateway_sentry
|
|
rmq_ng_rel = self.rmq_sentry.relation(
|
|
'amqp', 'neutron-gateway:amqp')
|
|
|
|
conf = '/etc/neutron/neutron.conf'
|
|
expected = {
|
|
'DEFAULT': {
|
|
'verbose': 'False',
|
|
'debug': 'False',
|
|
'core_plugin': 'ml2',
|
|
'control_exchange': 'neutron',
|
|
'notification_driver': 'neutron.openstack.common.notifier.'
|
|
'list_notifier',
|
|
'list_notifier_drivers': 'neutron.openstack.common.'
|
|
'notifier.rabbit_notifier',
|
|
},
|
|
'agent': {
|
|
'root_helper': 'sudo /usr/bin/neutron-rootwrap '
|
|
'/etc/neutron/rootwrap.conf'
|
|
}
|
|
}
|
|
|
|
if self._get_openstack_release() >= self.trusty_kilo:
|
|
# Kilo or later
|
|
expected['oslo_messaging_rabbit'] = {
|
|
'rabbit_userid': 'neutron',
|
|
'rabbit_virtual_host': 'openstack',
|
|
'rabbit_password': rmq_ng_rel['password'],
|
|
'rabbit_host': rmq_ng_rel['hostname'],
|
|
}
|
|
expected['oslo_concurrency'] = {
|
|
'lock_path': '/var/lock/neutron'
|
|
}
|
|
else:
|
|
# Juno or earlier
|
|
expected['DEFAULT'].update({
|
|
'rabbit_userid': 'neutron',
|
|
'rabbit_virtual_host': 'openstack',
|
|
'rabbit_password': rmq_ng_rel['password'],
|
|
'rabbit_host': rmq_ng_rel['hostname'],
|
|
'lock_path': '/var/lock/neutron',
|
|
})
|
|
|
|
for section, pairs in expected.iteritems():
|
|
ret = u.validate_config_data(unit, conf, section, pairs)
|
|
if ret:
|
|
message = "neutron config error: {}".format(ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_301_neutron_ml2_config(self):
|
|
"""Verify the data in the ml2 config file. This is only available
|
|
since icehouse."""
|
|
u.log.debug('Checking neutron gateway ml2 config file data...')
|
|
if self._get_openstack_release() < self.precise_icehouse:
|
|
return
|
|
|
|
unit = self.neutron_gateway_sentry
|
|
if self._get_openstack_release() < self.trusty_mitaka:
|
|
conf = '/etc/neutron/plugins/ml2/ml2_conf.ini'
|
|
expected = {
|
|
'ml2': {
|
|
'type_drivers': 'gre,vxlan,vlan,flat',
|
|
'tenant_network_types': 'gre,vxlan,vlan,flat',
|
|
'mechanism_drivers': 'openvswitch,hyperv,l2population'
|
|
},
|
|
'ml2_type_gre': {
|
|
'tunnel_id_ranges': '1:1000'
|
|
},
|
|
'ml2_type_vxlan': {
|
|
'vni_ranges': '1001:2000'
|
|
},
|
|
'ovs': {
|
|
'enable_tunneling': 'True',
|
|
'local_ip': self.get_private_address(unit)
|
|
},
|
|
'agent': {
|
|
'tunnel_types': 'gre',
|
|
'l2_population': 'False'
|
|
},
|
|
'securitygroup': {
|
|
'firewall_driver': 'neutron.agent.linux.iptables_firewall.'
|
|
'OVSHybridIptablesFirewallDriver'
|
|
}
|
|
}
|
|
else:
|
|
conf = '/etc/neutron/plugins/ml2/openvswitch_agent.ini'
|
|
expected = {
|
|
'ovs': {
|
|
'enable_tunneling': 'True',
|
|
'local_ip': self.get_private_address(unit)
|
|
},
|
|
'agent': {
|
|
'tunnel_types': 'gre',
|
|
'l2_population': 'False'
|
|
},
|
|
'securitygroup': {
|
|
'firewall_driver': 'neutron.agent.linux.iptables_firewall.'
|
|
'OVSHybridIptablesFirewallDriver'
|
|
}
|
|
}
|
|
|
|
for section, pairs in expected.iteritems():
|
|
ret = u.validate_config_data(unit, conf, section, pairs)
|
|
if ret:
|
|
message = "ml2 config error: {}".format(ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_302_neutron_dhcp_agent_config(self):
|
|
"""Verify the data in the dhcp agent config file."""
|
|
u.log.debug('Checking neutron gateway dhcp agent config file data...')
|
|
unit = self.neutron_gateway_sentry
|
|
conf = '/etc/neutron/dhcp_agent.ini'
|
|
expected = {
|
|
'state_path': '/var/lib/neutron',
|
|
'interface_driver': 'neutron.agent.linux.interface.'
|
|
'OVSInterfaceDriver',
|
|
'dhcp_driver': 'neutron.agent.linux.dhcp.Dnsmasq',
|
|
'root_helper': 'sudo /usr/bin/neutron-rootwrap '
|
|
'/etc/neutron/rootwrap.conf',
|
|
'ovs_use_veth': 'True'
|
|
}
|
|
section = 'DEFAULT'
|
|
|
|
ret = u.validate_config_data(unit, conf, section, expected)
|
|
if ret:
|
|
message = "dhcp agent config error: {}".format(ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_303_neutron_fwaas_driver_config(self):
|
|
"""Verify the data in the fwaas driver config file. This is only
|
|
available since havana."""
|
|
u.log.debug('Checking neutron gateway fwaas config file data...')
|
|
unit = self.neutron_gateway_sentry
|
|
conf = '/etc/neutron/fwaas_driver.ini'
|
|
expected = {
|
|
'enabled': 'True'
|
|
}
|
|
section = 'fwaas'
|
|
|
|
if self._get_openstack_release() >= self.trusty_kilo:
|
|
# Kilo or later
|
|
expected['driver'] = ('neutron_fwaas.services.firewall.drivers.'
|
|
'linux.iptables_fwaas.IptablesFwaasDriver')
|
|
else:
|
|
# Juno or earlier
|
|
expected['driver'] = ('neutron.services.firewall.drivers.linux.'
|
|
'iptables_fwaas.IptablesFwaasDriver')
|
|
|
|
ret = u.validate_config_data(unit, conf, section, expected)
|
|
if ret:
|
|
message = "fwaas driver config error: {}".format(ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_304_neutron_l3_agent_config(self):
|
|
"""Verify the data in the l3 agent config file."""
|
|
u.log.debug('Checking neutron gateway l3 agent config file data...')
|
|
unit = self.neutron_gateway_sentry
|
|
ncc_ng_rel = self.nova_cc_sentry.relation(
|
|
'quantum-network-service',
|
|
'neutron-gateway:quantum-network-service')
|
|
ep = self.keystone.service_catalog.url_for(service_type='identity',
|
|
endpoint_type='publicURL')
|
|
|
|
conf = '/etc/neutron/l3_agent.ini'
|
|
expected = {
|
|
'interface_driver': 'neutron.agent.linux.interface.'
|
|
'OVSInterfaceDriver',
|
|
'auth_url': ep,
|
|
'auth_region': 'RegionOne',
|
|
'admin_tenant_name': 'services',
|
|
'admin_password': ncc_ng_rel['service_password'],
|
|
'root_helper': 'sudo /usr/bin/neutron-rootwrap '
|
|
'/etc/neutron/rootwrap.conf',
|
|
'ovs_use_veth': 'True',
|
|
'handle_internal_only_routers': 'True'
|
|
}
|
|
section = 'DEFAULT'
|
|
|
|
if self._get_openstack_release() >= self.trusty_kilo:
|
|
# Kilo or later
|
|
expected['admin_user'] = 'nova'
|
|
else:
|
|
# Juno or earlier
|
|
expected['admin_user'] = 's3_ec2_nova'
|
|
|
|
ret = u.validate_config_data(unit, conf, section, expected)
|
|
if ret:
|
|
message = "l3 agent config error: {}".format(ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_305_neutron_lbaas_agent_config(self):
|
|
"""Verify the data in the lbaas agent config file. This is only
|
|
available since havana."""
|
|
u.log.debug('Checking neutron gateway lbaas config file data...')
|
|
if self._get_openstack_release() < self.precise_havana:
|
|
return
|
|
|
|
unit = self.neutron_gateway_sentry
|
|
conf = '/etc/neutron/lbaas_agent.ini'
|
|
expected = {
|
|
'DEFAULT': {
|
|
'interface_driver': 'neutron.agent.linux.interface.'
|
|
'OVSInterfaceDriver',
|
|
'periodic_interval': '10',
|
|
'ovs_use_veth': 'False',
|
|
},
|
|
'haproxy': {
|
|
'loadbalancer_state_path': '$state_path/lbaas',
|
|
'user_group': 'nogroup'
|
|
}
|
|
}
|
|
|
|
if self._get_openstack_release() >= self.trusty_kilo:
|
|
# Kilo or later
|
|
expected['DEFAULT']['device_driver'] = \
|
|
('neutron_lbaas.services.loadbalancer.drivers.haproxy.'
|
|
'namespace_driver.HaproxyNSDriver')
|
|
else:
|
|
# Juno or earlier
|
|
expected['DEFAULT']['device_driver'] = \
|
|
('neutron.services.loadbalancer.drivers.haproxy.'
|
|
'namespace_driver.HaproxyNSDriver')
|
|
|
|
for section, pairs in expected.iteritems():
|
|
ret = u.validate_config_data(unit, conf, section, pairs)
|
|
if ret:
|
|
message = "lbaas agent config error: {}".format(ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_306_neutron_metadata_agent_config(self):
|
|
"""Verify the data in the metadata agent config file."""
|
|
u.log.debug('Checking neutron gateway metadata agent '
|
|
'config file data...')
|
|
unit = self.neutron_gateway_sentry
|
|
ep = self.keystone.service_catalog.url_for(service_type='identity',
|
|
endpoint_type='publicURL')
|
|
nova_cc_relation = self.nova_cc_sentry.relation(
|
|
'quantum-network-service',
|
|
'neutron-gateway:quantum-network-service')
|
|
|
|
conf = '/etc/neutron/metadata_agent.ini'
|
|
expected = {
|
|
'auth_url': ep,
|
|
'auth_region': 'RegionOne',
|
|
'admin_tenant_name': 'services',
|
|
'admin_password': nova_cc_relation['service_password'],
|
|
'root_helper': 'sudo neutron-rootwrap '
|
|
'/etc/neutron/rootwrap.conf',
|
|
'state_path': '/var/lib/neutron',
|
|
'nova_metadata_ip': self.get_private_address(unit),
|
|
'nova_metadata_port': '8775',
|
|
'cache_url': 'memory://?default_ttl=5'
|
|
}
|
|
section = 'DEFAULT'
|
|
|
|
if self._get_openstack_release() >= self.trusty_kilo:
|
|
# Kilo or later
|
|
expected['admin_user'] = 'nova'
|
|
else:
|
|
# Juno or earlier
|
|
expected['admin_user'] = 's3_ec2_nova'
|
|
|
|
ret = u.validate_config_data(unit, conf, section, expected)
|
|
if ret:
|
|
message = "metadata agent config error: {}".format(ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_307_neutron_metering_agent_config(self):
|
|
"""Verify the data in the metering agent config file. This is only
|
|
available since havana."""
|
|
u.log.debug('Checking neutron gateway metering agent '
|
|
'config file data...')
|
|
unit = self.neutron_gateway_sentry
|
|
conf = '/etc/neutron/metering_agent.ini'
|
|
expected = {
|
|
'driver': 'neutron.services.metering.drivers.iptables.'
|
|
'iptables_driver.IptablesMeteringDriver',
|
|
'measure_interval': '30',
|
|
'report_interval': '300',
|
|
'interface_driver': 'neutron.agent.linux.interface.'
|
|
'OVSInterfaceDriver',
|
|
'use_namespaces': 'True'
|
|
}
|
|
section = 'DEFAULT'
|
|
|
|
ret = u.validate_config_data(unit, conf, section, expected)
|
|
if ret:
|
|
message = "metering agent config error: {}".format(ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_308_neutron_nova_config(self):
|
|
"""Verify the data in the nova config file."""
|
|
u.log.debug('Checking neutron gateway nova config file data...')
|
|
unit = self.neutron_gateway_sentry
|
|
conf = '/etc/nova/nova.conf'
|
|
|
|
rabbitmq_relation = self.rmq_sentry.relation(
|
|
'amqp', 'neutron-gateway:amqp')
|
|
nova_cc_relation = self.nova_cc_sentry.relation(
|
|
'quantum-network-service',
|
|
'neutron-gateway:quantum-network-service')
|
|
ep = self.keystone.service_catalog.url_for(service_type='identity',
|
|
endpoint_type='publicURL')
|
|
|
|
expected = {
|
|
'DEFAULT': {
|
|
'logdir': '/var/log/nova',
|
|
'state_path': '/var/lib/nova',
|
|
'root_helper': 'sudo nova-rootwrap /etc/nova/rootwrap.conf',
|
|
'verbose': 'False',
|
|
'use_syslog': 'False',
|
|
'api_paste_config': '/etc/nova/api-paste.ini',
|
|
'enabled_apis': 'metadata',
|
|
'multi_host': 'True',
|
|
'network_api_class': 'nova.network.neutronv2.api.API',
|
|
}
|
|
}
|
|
|
|
if self._get_openstack_release() >= self.trusty_kilo:
|
|
# Kilo or later
|
|
expected['oslo_messaging_rabbit'] = {
|
|
'rabbit_userid': 'neutron',
|
|
'rabbit_virtual_host': 'openstack',
|
|
'rabbit_password': rabbitmq_relation['password'],
|
|
'rabbit_host': rabbitmq_relation['hostname'],
|
|
}
|
|
expected['oslo_concurrency'] = {
|
|
'lock_path': '/var/lock/nova'
|
|
}
|
|
if self._get_openstack_release() >= self.trusty_mitaka:
|
|
expected['neutron'] = {
|
|
'url': nova_cc_relation['quantum_url'],
|
|
'auth_type': 'password',
|
|
'project_domain_name': 'default',
|
|
'user_domain_name': 'default',
|
|
'project_name': 'services',
|
|
'username': 'nova',
|
|
'password': nova_cc_relation['service_password'],
|
|
'auth_url': ep.split('/v')[0],
|
|
'region': 'RegionOne',
|
|
'service_metadata_proxy': 'True',
|
|
'metadata_proxy_shared_secret': u.not_null
|
|
}
|
|
else:
|
|
expected['neutron'] = {
|
|
'auth_strategy': 'keystone',
|
|
'url': nova_cc_relation['quantum_url'],
|
|
'admin_tenant_name': 'services',
|
|
'admin_username': 'nova',
|
|
'admin_password': nova_cc_relation['service_password'],
|
|
'admin_auth_url': ep,
|
|
'service_metadata_proxy': 'True',
|
|
'metadata_proxy_shared_secret': u.not_null
|
|
}
|
|
else:
|
|
# Juno or earlier
|
|
expected['DEFAULT'].update({
|
|
'rabbit_userid': 'neutron',
|
|
'rabbit_virtual_host': 'openstack',
|
|
'rabbit_password': rabbitmq_relation['password'],
|
|
'rabbit_host': rabbitmq_relation['hostname'],
|
|
'lock_path': '/var/lock/nova',
|
|
'neutron_auth_strategy': 'keystone',
|
|
'neutron_url': nova_cc_relation['quantum_url'],
|
|
'neutron_admin_tenant_name': 'services',
|
|
'neutron_admin_username': 's3_ec2_nova',
|
|
'neutron_admin_password': nova_cc_relation['service_password'],
|
|
'neutron_admin_auth_url': ep,
|
|
'service_neutron_metadata_proxy': 'True',
|
|
})
|
|
|
|
for section, pairs in expected.iteritems():
|
|
ret = u.validate_config_data(unit, conf, section, pairs)
|
|
if ret:
|
|
message = "nova config error: {}".format(ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_309_neutron_vpn_agent_config(self):
|
|
"""Verify the data in the vpn agent config file. This isn't available
|
|
prior to havana."""
|
|
u.log.debug('Checking neutron gateway vpn agent config file data...')
|
|
unit = self.neutron_gateway_sentry
|
|
conf = '/etc/neutron/vpn_agent.ini'
|
|
expected = {
|
|
'ipsec': {
|
|
'ipsec_status_check_interval': '60'
|
|
}
|
|
}
|
|
|
|
if self._get_openstack_release() >= self.trusty_kilo:
|
|
# Kilo or later
|
|
expected['vpnagent'] = {
|
|
'vpn_device_driver': 'neutron_vpnaas.services.vpn.'
|
|
'device_drivers.ipsec.OpenSwanDriver'
|
|
}
|
|
else:
|
|
# Juno or earlier
|
|
expected['vpnagent'] = {
|
|
'vpn_device_driver': 'neutron.services.vpn.device_drivers.'
|
|
'ipsec.OpenSwanDriver'
|
|
}
|
|
|
|
for section, pairs in expected.iteritems():
|
|
ret = u.validate_config_data(unit, conf, section, pairs)
|
|
if ret:
|
|
message = "vpn agent config error: {}".format(ret)
|
|
amulet.raise_status(amulet.FAIL, msg=message)
|
|
|
|
def test_400_create_network(self):
|
|
"""Create a network, verify that it exists, and then delete it."""
|
|
u.log.debug('Creating neutron network...')
|
|
self.neutron.format = 'json'
|
|
net_name = 'ext_net'
|
|
|
|
# Verify that the network doesn't exist
|
|
networks = self.neutron.list_networks(name=net_name)
|
|
net_count = len(networks['networks'])
|
|
if net_count != 0:
|
|
msg = "Expected zero networks, found {}".format(net_count)
|
|
amulet.raise_status(amulet.FAIL, msg=msg)
|
|
|
|
# Create a network and verify that it exists
|
|
network = {'name': net_name}
|
|
self.neutron.create_network({'network': network})
|
|
|
|
networks = self.neutron.list_networks(name=net_name)
|
|
u.log.debug('Networks: {}'.format(networks))
|
|
net_len = len(networks['networks'])
|
|
if net_len != 1:
|
|
msg = "Expected 1 network, found {}".format(net_len)
|
|
amulet.raise_status(amulet.FAIL, msg=msg)
|
|
|
|
u.log.debug('Confirming new neutron network...')
|
|
network = networks['networks'][0]
|
|
if network['name'] != net_name:
|
|
amulet.raise_status(amulet.FAIL, msg="network ext_net not found")
|
|
|
|
# Cleanup
|
|
u.log.debug('Deleting neutron network...')
|
|
self.neutron.delete_network(network['id'])
|
|
|
|
def test_900_restart_on_config_change(self):
|
|
"""Verify that the specified services are restarted when the
|
|
config is changed."""
|
|
|
|
sentry = self.neutron_gateway_sentry
|
|
juju_service = 'neutron-gateway'
|
|
|
|
# Expected default and alternate values
|
|
set_default = {'debug': 'False'}
|
|
set_alternate = {'debug': 'True'}
|
|
|
|
# Services which are expected to restart upon config change,
|
|
# and corresponding config files affected by the change
|
|
conf_file = '/etc/neutron/neutron.conf'
|
|
services = {
|
|
'neutron-dhcp-agent': conf_file,
|
|
'neutron-lbaas-agent': conf_file,
|
|
'neutron-metadata-agent': conf_file,
|
|
'neutron-metering-agent': conf_file,
|
|
'neutron-openvswitch-agent': conf_file,
|
|
}
|
|
|
|
if self._get_openstack_release() <= self.trusty_juno:
|
|
services.update({'neutron-vpn-agent': conf_file})
|
|
|
|
# Make config change, check for svc restart, conf file mod time change
|
|
u.log.debug('Making config change on {}...'.format(juju_service))
|
|
mtime = u.get_sentry_time(sentry)
|
|
self.d.configure(juju_service, set_alternate)
|
|
|
|
# sleep_time = 90
|
|
for s, conf_file in services.iteritems():
|
|
u.log.debug("Checking that service restarted: {}".format(s))
|
|
if not u.validate_service_config_changed(sentry, mtime, s,
|
|
conf_file):
|
|
self.d.configure(juju_service, set_default)
|
|
msg = "service {} didn't restart after config change".format(s)
|
|
amulet.raise_status(amulet.FAIL, msg=msg)
|
|
|
|
# Only do initial sleep on first service check
|
|
# sleep_time = 0
|
|
|
|
self.d.configure(juju_service, set_default)
|
|
|
|
def test_910_pause_and_resume(self):
|
|
"""The services can be paused and resumed. """
|
|
u.log.debug('Checking pause and resume actions...')
|
|
unit_name = "neutron-gateway/0"
|
|
unit = self.d.sentry.unit[unit_name]
|
|
|
|
assert u.status_get(unit)[0] == "active"
|
|
|
|
action_id = self._run_action(unit_name, "pause")
|
|
assert self._wait_on_action(action_id), "Pause action failed."
|
|
assert u.status_get(unit)[0] == "maintenance"
|
|
|
|
action_id = self._run_action(unit_name, "resume")
|
|
assert self._wait_on_action(action_id), "Resume action failed."
|
|
assert u.status_get(unit)[0] == "active"
|
|
u.log.debug('OK')
|