diff --git a/devstack/plugin.sh b/devstack/plugin.sh index d99c9a7f12..917718a991 100644 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -285,6 +285,8 @@ EOF # install_trove() - Collect source and prepare function install_trove { + install_package jq + echo "Changing stack user sudoers" echo "stack ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/60_stack_sh_allow_all @@ -541,6 +543,79 @@ manage_etc_hosts: "localhost" EOF } +# Set up Trove management network and make configuration change. +function config_trove_network { + echo "Finalizing Neutron networking for Trove" + echo "Dumping current network parameters:" + echo " SERVICE_HOST: $SERVICE_HOST" + echo " BRIDGE_IP: $BRIDGE_IP" + echo " PUBLIC_NETWORK_GATEWAY: $PUBLIC_NETWORK_GATEWAY" + echo " NETWORK_GATEWAY: $NETWORK_GATEWAY" + echo " IPV4_ADDRS_SAFE_TO_USE: $IPV4_ADDRS_SAFE_TO_USE" + echo " IPV6_ADDRS_SAFE_TO_USE: $IPV6_ADDRS_SAFE_TO_USE" + echo " FIXED_RANGE: $FIXED_RANGE" + echo " FLOATING_RANGE: $FLOATING_RANGE" + echo " SUBNETPOOL_PREFIX_V4: $SUBNETPOOL_PREFIX_V4" + echo " SUBNETPOOL_SIZE_V4: $SUBNETPOOL_SIZE_V4" + echo " SUBNETPOOL_V4_ID: $SUBNETPOOL_V4_ID" + echo " ROUTER_GW_IP: $ROUTER_GW_IP" + echo " TROVE_MGMT_SUBNET_RANGE: ${TROVE_MGMT_SUBNET_RANGE}" + + # Save xtrace setting + local XTRACE + XTRACE=$(set +o | grep xtrace) + set -x + + echo "Creating Trove management network/subnet for Trove service project." + trove_service_project_id=$(openstack project show $SERVICE_PROJECT_NAME -c id -f value) + setup_mgmt_network ${trove_service_project_id} ${TROVE_MGMT_NETWORK_NAME} ${TROVE_MGMT_SUBNET_NAME} ${TROVE_MGMT_SUBNET_RANGE} + mgmt_net_id=$(openstack network show ${TROVE_MGMT_NETWORK_NAME} -c id -f value) + echo "Created Trove management network ${TROVE_MGMT_NETWORK_NAME}(${mgmt_net_id})" + + # Share the private network to other projects for testing purpose. We make + # the private network accessible to control plane below so that we could + # reach the private network for integration tests without floating ips + # associated, no matter which user the tests are using. + shared=$(openstack network show ${PRIVATE_NETWORK_NAME} -c shared -f value) + if [[ "$shared" == "False" ]]; then + openstack network set ${PRIVATE_NETWORK_NAME} --share + fi + sudo ip route replace ${IPV4_ADDRS_SAFE_TO_USE} via $ROUTER_GW_IP + + # Make sure we can reach the management port of the service VM, this + # configuration is only for testing purpose. In production, it's + # recommended to config the router in the cloud infrastructure for the + # communication between Trove control plane and service VMs. + INTERFACE=trove-mgmt + MGMT_PORT_ID=$(openstack port create --project ${trove_service_project_id} --security-group ${TROVE_MGMT_SECURITY_GROUP} --device-owner trove --network ${TROVE_MGMT_NETWORK_NAME} --host=$(hostname) -c id -f value ${INTERFACE}-port) + MGMT_PORT_MAC=$(openstack port show -c mac_address -f value $MGMT_PORT_ID) + MGMT_PORT_IP=$(openstack port show -f value -c fixed_ips $MGMT_PORT_ID) + MGMT_PORT_IP=${MGMT_PORT_IP//u\'/\'} + MGMT_PORT_IP=$(echo ${MGMT_PORT_IP//\'/\"} | jq -r '.[0].ip_address') + sudo ovs-vsctl -- --may-exist add-port ${OVS_BRIDGE:-br-int} $INTERFACE -- set Interface $INTERFACE type=internal -- set Interface $INTERFACE external-ids:iface-status=active -- set Interface $INTERFACE external-ids:attached-mac=$MGMT_PORT_MAC -- set Interface $INTERFACE external-ids:iface-id=$MGMT_PORT_ID -- set Interface $INTERFACE external-ids:skip_cleanup=true + sudo ip link set dev $INTERFACE address $MGMT_PORT_MAC + mask=$(echo ${TROVE_MGMT_SUBNET_RANGE} | awk -F'/' '{print $2}') + sudo ip addr add ${MGMT_PORT_IP}/${mask} dev $INTERFACE + sudo ip link set $INTERFACE up + + echo "Neutron network list:" + openstack network list + echo "Neutron subnet list:" + openstack subnet list + echo "ip route:" + sudo ip route + + # Now make sure the conf settings are right + iniset $TROVE_CONF DEFAULT network_label_regex ${PRIVATE_NETWORK_NAME} + iniset $TROVE_CONF DEFAULT ip_regex "" + iniset $TROVE_CONF DEFAULT black_list_regex "" + iniset $TROVE_CONF DEFAULT management_networks ${mgmt_net_id} + iniset $TROVE_CONF DEFAULT network_driver trove.network.neutron.NeutronDriver + + # Restore xtrace setting + $XTRACE +} + function config_nova_keypair { export SSH_DIR=${SSH_DIR:-"$HOME/.ssh"} diff --git a/trove/dns/designate/driver.py b/trove/dns/designate/driver.py index 13e441dd3b..d25859a36b 100644 --- a/trove/dns/designate/driver.py +++ b/trove/dns/designate/driver.py @@ -21,7 +21,6 @@ import base64 import hashlib from designateclient import client -from designateclient.v1.records import Record from keystoneauth1 import loading from keystoneauth1 import session from oslo_log import log as logging @@ -38,9 +37,6 @@ CONF = cfg.CONF DNS_TENANT_ID = CONF.dns_account_id DNS_AUTH_URL = CONF.dns_auth_url -DNS_ENDPOINT_URL = CONF.dns_endpoint_url -DNS_SERVICE_TYPE = CONF.dns_service_type -DNS_REGION = CONF.dns_region DNS_USERNAME = CONF.dns_username DNS_PASSKEY = CONF.dns_passkey DNS_TTL = CONF.dns_ttl @@ -52,18 +48,6 @@ DNS_PROJECT_DOMAIN_ID = CONF.dns_project_domain_id LOG = logging.getLogger(__name__) -class DesignateObjectConverter(object): - - @staticmethod - def domain_to_zone(domain): - return DesignateDnsZone(id=domain.id, name=domain.name) - - def record_to_entry(self, record, dns_zone): - return driver.DnsEntry(name=record.name, content=record.data, - type=record.type, ttl=record.ttl, - priority=record.priority, dns_zone=dns_zone) - - def create_designate_client(api_version='2'): """Creates a Designate DNSaaS client.""" loader = loading.get_plugin_loader('password') @@ -77,74 +61,6 @@ def create_designate_client(api_version='2'): return client.Client(api_version, session=sesh) -class DesignateDriver(driver.DnsDriver): - - def __init__(self): - self.dns_client = create_designate_client(api_version='1') - self.converter = DesignateObjectConverter() - self.default_dns_zone = DesignateDnsZone(id=DNS_DOMAIN_ID, - name=DNS_DOMAIN_NAME) - - def create_entry(self, entry, content): - """Creates the entry in the driver at the given dns zone.""" - dns_zone = entry.dns_zone or self.default_dns_zone - if not dns_zone.id: - raise TypeError(_("The entry's dns_zone must have an ID " - "specified.")) - name = entry.name - LOG.debug("Creating DNS entry %s.", name) - client = self.dns_client - # Record name has to end with a '.' by dns standard - record = Record(name=entry.name + '.', - type=entry.type, - data=content, - ttl=entry.ttl, - priority=entry.priority) - client.records.create(dns_zone.id, record) - - def delete_entry(self, name, type, dns_zone=None): - """Deletes an entry with the given name and type from a dns zone.""" - dns_zone = dns_zone or self.default_dns_zone - records = self._get_records(dns_zone) - matching_record = [rec for rec in records - if rec.name == name + '.' and rec.type == type] - if not matching_record: - raise exception.DnsRecordNotFound(name=name) - LOG.debug("Deleting DNS entry %s.", name) - self.dns_client.records.delete(dns_zone.id, matching_record[0].id) - - def get_entries_by_content(self, content, dns_zone=None): - """Retrieves all entries in a DNS zone with matching content field.""" - records = self._get_records(dns_zone) - return [self.converter.record_to_entry(record, dns_zone) - for record in records if record.data == content] - - def get_entries_by_name(self, name, dns_zone): - records = self._get_records(dns_zone) - return [self.converter.record_to_entry(record, dns_zone) - for record in records if record.name == name] - - def get_dns_zones(self, name=None): - """Returns all dns zones (optionally filtered by the name argument.""" - domains = self.dns_client.domains.list() - return [self.converter.domain_to_zone(domain) - for domain in domains if not name or domain.name == name] - - def modify_content(self, name, content, dns_zone): - # We dont need this in trove for now - raise NotImplementedError(_("Not implemented for Designate DNS.")) - - def rename_entry(self, content, name, dns_zone): - # We dont need this in trove for now - raise NotImplementedError(_("Not implemented for Designate DNS.")) - - def _get_records(self, dns_zone): - dns_zone = dns_zone or self.default_dns_zone - if not dns_zone: - raise TypeError(_('DNS domain is must be specified')) - return self.dns_client.records.list(dns_zone.id) - - class DesignateDriverV2(driver.DnsDriver): def __init__(self): diff --git a/trove/tests/unittests/domain-name-service/test_designate_driver.py b/trove/tests/unittests/domain-name-service/test_designate_driver.py index 3ab617514d..fd77b4680c 100644 --- a/trove/tests/unittests/domain-name-service/test_designate_driver.py +++ b/trove/tests/unittests/domain-name-service/test_designate_driver.py @@ -14,8 +14,6 @@ import base64 import hashlib -from designateclient.v1.domains import Domain -from designateclient.v1.records import Record from mock import MagicMock from mock import patch import six @@ -26,155 +24,6 @@ from trove.dns import driver as base_driver from trove.tests.unittests import trove_testtools -class DesignateObjectConverterTest(trove_testtools.TestCase): - - def setUp(self): - super(DesignateObjectConverterTest, self).setUp() - - def tearDown(self): - super(DesignateObjectConverterTest, self).tearDown() - - def test_convert_domain_to_zone(self): - name = 'www.example.com' - id = '39413651-3b9e-41f1-a4df-e47d5e9f67be' - email = 'john.smith@openstack.com' - domain = Domain(name=name, id=id, email=email) - converter = driver.DesignateObjectConverter() - converted_domain = converter.domain_to_zone(domain) - self.assertEqual(name, converted_domain.name) - self.assertEqual(id, converted_domain.id) - - def test_convert_record_to_entry(self): - name = 'test.example.com' - id = '4f3439ef-fc8b-4098-a1aa-a66ed01102b9' - domain_id = '39413651-3b9e-41f1-a4df-e47d5e9f67be' - domain_name = 'example.com' - type = 'CNAME' - data = '127.0.0.1' - ttl = 3600 - priority = 1 - zone = driver.DesignateDnsZone(domain_id, domain_name) - record = Record(name=name, id=id, domain_id=domain_id, type=type, - data=data, priority=priority, ttl=ttl) - converter = driver.DesignateObjectConverter() - converted_record = converter.record_to_entry(record, zone) - self.assertEqual(name, converted_record.name) - self.assertEqual(data, converted_record.content) - self.assertEqual(type, converted_record.type) - self.assertEqual(priority, converted_record.priority) - self.assertEqual(ttl, converted_record.ttl) - self.assertEqual(zone, converted_record.dns_zone) - - -class DesignateDriverTest(trove_testtools.TestCase): - - def setUp(self): - super(DesignateDriverTest, self).setUp() - self.domains = [Domain(name='www.example.com', - id='11111111-1111-1111-1111-111111111111', - email='test@example.com'), - Domain(name='www.trove.com', - id='22222222-2222-2222-2222-222222222222', - email='test@trove.com'), - Domain(name='www.openstack.com', - id='33333333-3333-3333-3333-333333333333', - email='test@openstack.com')] - self.records = [Record(name='record1', type='A', data='10.0.0.1', - ttl=3600, priority=1), - Record(name='record2', type='CNAME', data='10.0.0.2', - ttl=1800, priority=2), - Record(name='record3', type='A', data='10.0.0.3', - ttl=3600, priority=1)] - self.create_des_client_patch = patch.object( - driver, 'create_designate_client', MagicMock(return_value=None)) - self.create_des_client_mock = self.create_des_client_patch.start() - self.addCleanup(self.create_des_client_patch.stop) - - def tearDown(self): - super(DesignateDriverTest, self).tearDown() - - def test_get_entries_by_name(self): - zone = driver.DesignateDnsZone('123', 'www.example.com') - with patch.object(driver.DesignateDriver, '_get_records', - MagicMock(return_value=self.records)): - dns_driver = driver.DesignateDriver() - entries = dns_driver.get_entries_by_name('record2', zone) - self.assertEqual(1, len(entries), 'More than one record found') - entry = entries[0] - self.assertEqual('record2', entry.name) - self.assertEqual('CNAME', entry.type) - self.assertEqual('10.0.0.2', entry.content) - self.assertEqual(1800, entry.ttl) - self.assertEqual(2, entry.priority) - zone = entry.dns_zone - self.assertEqual('123', zone.id) - self.assertEqual('www.example.com', zone.name) - - def test_get_entries_by_name_not_found(self): - zone = driver.DesignateDnsZone('123', 'www.example.com') - with patch.object(driver.DesignateDriver, '_get_records', - MagicMock(return_value=self.records)): - dns_driver = driver.DesignateDriver() - entries = dns_driver.get_entries_by_name('record_not_found', zone) - self.assertEqual(0, len(entries), 'Some records were returned') - - def test_get_entries_by_content(self): - zone = driver.DesignateDnsZone('123', 'www.example.com') - with patch.object(driver.DesignateDriver, '_get_records', - MagicMock(return_value=self.records)): - dns_driver = driver.DesignateDriver() - entries = dns_driver.get_entries_by_content('10.0.0.1', zone) - self.assertEqual(1, len(entries), 'More than one record found') - entry = entries[0] - self.assertEqual('record1', entry.name) - self.assertEqual('A', entry.type) - self.assertEqual('10.0.0.1', entry.content) - self.assertEqual(3600, entry.ttl) - self.assertEqual(1, entry.priority) - zone = entry.dns_zone - self.assertEqual('123', zone.id) - self.assertEqual('www.example.com', zone.name) - - def test_get_entries_by_content_not_found(self): - zone = driver.DesignateDnsZone('123', 'www.example.com') - with patch.object(driver.DesignateDriver, '_get_records', - MagicMock(return_value=self.records)): - dns_driver = driver.DesignateDriver() - entries = dns_driver.get_entries_by_content('127.0.0.1', zone) - self.assertEqual(0, len(entries), 'Some records were returned') - - def test_get_dnz_zones(self): - client = MagicMock() - self.create_des_client_mock.return_value = client - client.domains.list = MagicMock(return_value=self.domains) - dns_driver = driver.DesignateDriver() - zones = dns_driver.get_dns_zones() - self.assertEqual(3, len(zones)) - for x in range(0, 3): - self.assertDomainsAreEqual(self.domains[x], zones[x]) - - def test_get_dnz_zones_by_name(self): - client = MagicMock() - self.create_des_client_mock.return_value = client - client.domains.list = MagicMock(return_value=self.domains) - dns_driver = driver.DesignateDriver() - zones = dns_driver.get_dns_zones('www.trove.com') - self.assertEqual(1, len(zones)) - self.assertDomainsAreEqual(self.domains[1], zones[0]) - - def test_get_dnz_zones_not_found(self): - client = MagicMock() - self.create_des_client_mock.return_value = client - client.domains.list = MagicMock(return_value=self.domains) - dns_driver = driver.DesignateDriver() - zones = dns_driver.get_dns_zones('www.notfound.com') - self.assertEqual(0, len(zones)) - - def assertDomainsAreEqual(self, expected, actual): - self.assertEqual(expected.name, actual.name) - self.assertEqual(expected.id, actual.id) - - class DesignateDriverV2Test(trove_testtools.TestCase): def setUp(self):