diff --git a/vmware_nsx_tempest_plugin/common/constants.py b/vmware_nsx_tempest_plugin/common/constants.py index aaf3e75..f025cd6 100644 --- a/vmware_nsx_tempest_plugin/common/constants.py +++ b/vmware_nsx_tempest_plugin/common/constants.py @@ -79,6 +79,8 @@ REJECT = "REJECT" AUDIT_WAIT_TIME = 300 # ZONE Designate ZONE_WAIT_TIME = 120 +REGION_NAME = "RegionOne" +ZONE_NAME = 'tempest-dns-network.com.' # VPN PEER_ID = "172.24.4.12" PFS = "group14" diff --git a/vmware_nsx_tempest_plugin/lib/appliance_manager.py b/vmware_nsx_tempest_plugin/lib/appliance_manager.py index 6e1cf87..941cce2 100644 --- a/vmware_nsx_tempest_plugin/lib/appliance_manager.py +++ b/vmware_nsx_tempest_plugin/lib/appliance_manager.py @@ -193,6 +193,40 @@ class ApplianceManager(manager.NetworkScenarioTest): self.topology_networks[network_name] = network return network + def create_provider_network(self, net_type, + zone_name, + admin_state_up=True, + tz_id=None, + vlan_id_unique=None): + networks_client = self.cmgr_adm.networks_client + if net_type == constants.VXLAN_TYPE: + name = "provider_network_vxlan" + body = {"provider:physical_network": tz_id, + "provider:network_type": net_type, + "admin_state_up": admin_state_up, + "dns_domain": zone_name} + elif net_type == constants.VLAN_TYPE: + name = "provider_network_vlan" + if vlan_id_unique is not None: + vlan_id_no = vlan_id_unique + else: + vlan_id_no = constants.VLAN + if tz_id is None: + body = {"provider:segmentation_id": vlan_id_no, + "provider:network_type": net_type, + "admin_state_up": admin_state_up, + "dns_domain": zone_name} + else: + body = {"provider:segmentation_id": vlan_id_no, + "provider:network_type": net_type, + "provider:physical_network": tz_id, + "admin_state_up": admin_state_up, + "dns_domain": zone_name} + network = self.create_topology_network(name, + networks_client=networks_client, + **body) + return network + def update_topology_network( self, network_id, networks_client=None, **update_kwargs): if not networks_client: diff --git a/vmware_nsx_tempest_plugin/lib/feature_manager.py b/vmware_nsx_tempest_plugin/lib/feature_manager.py index 3b43441..86390a7 100644 --- a/vmware_nsx_tempest_plugin/lib/feature_manager.py +++ b/vmware_nsx_tempest_plugin/lib/feature_manager.py @@ -124,6 +124,12 @@ class FeatureManager(traffic_manager.IperfManager, net_client.region, net_client.endpoint_type, **_params) + cls.ptr_client = openstack_network_clients.DesignatePtrClient( + net_client.auth_provider, + net_client.service, + net_client.region, + net_client.endpoint_type, + **_params) # # FwaasV2 base class @@ -944,14 +950,12 @@ class FeatureManager(traffic_manager.IperfManager, return email_id def create_zone(self, name=None, email=None, description=None, - wait_until=False): + wait_until=False, tenant_id=None): """Create a zone with the specified parameters. :param name: The name of the zone. Default: Random Value :param email: The email for the zone. Default: Random Value - :param ttl: The ttl for the zone. - Default: Random Value :param description: A description of the zone. Default: Random Value :param wait_until: Block until the zone reaches the desired status @@ -967,7 +971,6 @@ class FeatureManager(traffic_manager.IperfManager, _, body = self.zones_v2_client.create_zone(wait_until, **zone) self.addCleanup(test_utils.call_and_ignore_notfound_exc, self.delete_zone, body['id']) - # Create Zone should Return a HTTP 202 return body def delete_zone(self, uuid): @@ -991,30 +994,18 @@ class FeatureManager(traffic_manager.IperfManager, """ return self.zones_v2_client.list_zones() - def update_zone(self, uuid, email=None, ttl=None, - description=None, wait_until=False): - """Update a zone with the specified parameters. - :param uuid: The unique identifier of the zone. - :param email: The email for the zone. - Default: Random Value - :param ttl: The ttl for the zone. - Default: Random Value - :param description: A description of the zone. - Default: Random Value - :param wait_until: Block until the zone reaches the desiered status - :return: A tuple with the server response and the updated zone. - """ - zone = { - 'email': email or self.rand_email(), - 'ttl': ttl or self.rand_ttl(), - 'description': description or self.rand_name('test-zone'), - } - _, body = self.zones_v2_client.update_zone(uuid, wait_until, **zone) - return body - - def list_record_set_zone(self, uuid): + def list_record_set_zone(self, uuid, user=None): """list recordsets of a zone. :param uuid: The unique identifier of the zone. """ body = self.zones_v2_client.list_recordset_zone(uuid) + self.assertGreater(len(body), 0) + return body + + def show_ptr_record(self, region, fip_id, user=None): + """list ptr recordsets associated with floating ip. + :param fip_id: Unique FloatingIP ID. + """ + ptr_id = region + ":" + fip_id + body = self.ptr_client.show_ptr_record(ptr_id) return body diff --git a/vmware_nsx_tempest_plugin/services/openstack_network_clients.py b/vmware_nsx_tempest_plugin/services/openstack_network_clients.py index 9478702..8138cff 100644 --- a/vmware_nsx_tempest_plugin/services/openstack_network_clients.py +++ b/vmware_nsx_tempest_plugin/services/openstack_network_clients.py @@ -12,6 +12,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + from oslo_log import log from tempest import config @@ -475,3 +476,17 @@ class ZonesV2Client(designate_base.DnsClientBase): request = self.resource_base_path + '/' + zone_id + '/recordsets' resp, body = self._list_request(request) return resp, body + + +class DesignatePtrClient(designate_base.DnsClientBase): + """ + Request resources via API for Designate PTR RecordSet Client + PTR recordset show request + """ + path = "v2/reverse/floatingips/" + + def show_ptr_record(self, ptr_id): + """ + Show FloatingIP PTR record + """ + return self._show_request(self.path, ptr_id) diff --git a/vmware_nsx_tempest_plugin/tests/api/test_v2_designate.py b/vmware_nsx_tempest_plugin/tests/api/test_v2_designate.py deleted file mode 100644 index 8cc8e12..0000000 --- a/vmware_nsx_tempest_plugin/tests/api/test_v2_designate.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2017 VMware, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -from oslo_log import log as logging - -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -from vmware_nsx_tempest_plugin.lib import feature_manager - - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class TestZonesV2Ops(feature_manager.FeatureManager): - - @classmethod - def skip_checks(cls): - super(TestZonesV2Ops, cls).skip_checks() - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - cls.admin_mgr = cls.get_client_manager('admin') - super(TestZonesV2Ops, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - """ - Create various client connections. Such as NSX. - """ - super(TestZonesV2Ops, cls).setup_clients() - - -class TestZones(TestZonesV2Ops): - - excluded_keys = ['created_at', 'updated_at', 'version', 'links', - 'status', 'action'] - - @decorators.idempotent_id('e26cf8c6-164d-4097-b066-4e2100382d53') - def test_create_zone(self): - """Creating a v2 Zone""" - LOG.info('Create a zone') - zone = self.create_zone(wait_until=True) - LOG.info('Ensure we respond with CREATE+PENDING') - self.assertEqual('CREATE', zone['action']) - self.assertEqual('PENDING', zone['status']) - - @decorators.idempotent_id('76586e1f-7466-4dd1-bcdf-b6805c63731c') - def test_delete_zone(self): - LOG.info('Create a zone') - zone = self.create_zone() - LOG.info('Delete the zone') - body = self.delete_zone(zone['id']) - LOG.info('Ensure we respond with DELETE+PENDING') - self.assertEqual('DELETE', body['action']) - self.assertEqual('PENDING', body['status']) - - @decorators.idempotent_id('3fa18ce7-ac47-425f-a1d1-2baa5ead0ed1') - def test_show_zone(self): - LOG.info('Create a zone') - zone = self.create_zone() - LOG.info('Fetch the zone') - body = self.show_zone(zone['id']) - LOG.info('Ensure the fetched response matches the created zone') - self.assertEqual(zone['links'], body[1]['links']) - self.assertEqual(zone['name'], body[1]['name']) - self.assertEqual(zone['email'], body[1]['email']) - self.assertEqual(zone['ttl'], body[1]['ttl']) - - @decorators.idempotent_id('7e35c62c-5baf-4d32-b3e8-59e76ea6571f') - def test_list_zones(self): - LOG.info('Create a zone') - self.create_zone() - LOG.info('List zones') - body = self.list_zones() - self.assertGreater(len(body[1]['zones']), 0) - - @decorators.idempotent_id('55ca3fc8-6652-4f00-9af8-c01ea5bae5a0') - def test_update_zone(self): - LOG.info('Create a zone') - zone = self.create_zone() - # Generate a random description - description = data_utils.rand_name() - LOG.info('Update the zone') - zone = self.update_zone( - zone['id'], email=zone['email'], ttl=zone['ttl'], - description=description, wait_until=True) - LOG.info('Ensure we respond with UPDATE+PENDING') - self.assertEqual('UPDATE', zone['action']) - self.assertEqual('PENDING', zone['status']) - LOG.info('Ensure we respond with updated values') - self.assertEqual(description, zone['description']) diff --git a/vmware_nsx_tempest_plugin/tests/scenario/test_designate.py b/vmware_nsx_tempest_plugin/tests/scenario/test_designate.py index 1ad57cc..ae631a2 100644 --- a/vmware_nsx_tempest_plugin/tests/scenario/test_designate.py +++ b/vmware_nsx_tempest_plugin/tests/scenario/test_designate.py @@ -24,6 +24,7 @@ from tempest.lib import exceptions as lib_exc from vmware_nsx_tempest_plugin.common import constants as const from vmware_nsx_tempest_plugin.lib import feature_manager +from vmware_nsx_tempest_plugin.services import nsxv3_client CONF = config.CONF @@ -45,6 +46,25 @@ class TestZonesV2Ops(feature_manager.FeatureManager): super(TestZonesV2Ops, cls).setup_clients() cls.cmgr_adm = cls.get_client_manager('admin') + @classmethod + def resource_setup(cls): + super(TestZonesV2Ops, cls).resource_setup() + cls.nsx = nsxv3_client.NSXV3Client(CONF.nsxv3.nsx_manager, + CONF.nsxv3.nsx_user, + CONF.nsxv3.nsx_password) + out = cls.nsx.get_transport_zones() + vlan_flag = 0 + vxlan_flag = 0 + for tz in out: + if "transport_type" in tz.keys() and (vlan_flag == 0 + or vxlan_flag == 0): + if vxlan_flag == 0 and tz['transport_type'] == "OVERLAY": + cls.overlay_id = tz['id'] + vxlan_flag = 1 + if vlan_flag == 0 and tz['transport_type'] == "VLAN": + cls.vlan_id = tz['id'] + vlan_flag = 1 + def define_security_groups(self, tenant_id): sec_rule_client = self.os_admin.security_group_rules_client sec_client = self.os_admin.security_groups_client @@ -62,13 +82,28 @@ class TestZonesV2Ops(feature_manager.FeatureManager): ruleclient=sec_rule_client, secclient=sec_client, tenant_id=tenant_id) - def create_designate_zone(self): - LOG.info('Create a zone') - zone = self.create_zone(wait_until=True) - LOG.info('Ensure we respond with CREATE+PENDING') - self.assertEqual('CREATE', zone['action']) - self.assertEqual('PENDING', zone['status']) - return zone + def create_zone_provider_vlan_vxlan_topology(self, network_type, + zone_name): + if network_type == 'vlan': + network_designate = self.create_provider_network( + const.VLAN_TYPE, + zone_name, + tz_id=self.vlan_id) + elif network_type == 'vxlan': + network_designate = self.create_provider_network( + const.VXLAN_TYPE, + zone_name, + tz_id=self.overlay_id) + tenant_id = network_designate['tenant_id'] + self.define_security_groups(tenant_id) + subnet_client = self.os_adm.subnets_client + routers_client = self.os_adm.routers_client + router_designate = self.create_topology_router("router_designate", + routers_client=routers_client) + self.create_topology_subnet("subnet_designate", + network_designate, subnets_client=subnet_client, + routers_client=routers_client, router_id=router_designate['id']) + return network_designate def create_zone_topology(self, zone_name): networks_client = self.cmgr_adm.networks_client @@ -129,7 +164,7 @@ class TestZonesScenario(TestZonesV2Ops): Verify recordset only has SOA and NS record types """ image_id = self.get_glance_image_id(['cirros', 'esx']) - zone = self.create_designate_zone() + zone = self.create_zone() network_designate = self.create_zone_topology(zone['name']) self.assertEqual(network_designate['dns_domain'], zone['name']) LOG.info('Show recordset of the zone') @@ -144,6 +179,58 @@ class TestZonesScenario(TestZonesV2Ops): recordset = self.list_record_set_zone(zone['id']) self.verify_recordset(recordset, 2) + @decorators.idempotent_id('6cb8ce24-f19f-466d-9386-ae0d45ed518f') + def test_zone_list_without_fip_instance_provider_vxlan(self): + """ + Create a zone, check zone exits + Create a network and subnet + Update network with the zone + Boot a VM + Verify recordset only has SOA and NS record types + """ + image_id = self.get_glance_image_id(['cirros', 'esx']) + zone = self.create_zone() + network_designate = self.create_zone_provider_vlan_vxlan_topology( + 'vxlan', zone['name']) + self.assertEqual(network_designate['dns_domain'], zone['name']) + LOG.info('Show recordset of the zone') + recordset = self.list_record_set_zone(zone['id']) + self.verify_recordset(recordset, 2) + self.create_topology_instance( + "dns_vm", [network_designate], + security_groups=[{'name': self.designate_sg['name']}], + clients=self.os_adm, + create_floating_ip=False, image_id=image_id) + LOG.info('Show recordset of the zone') + recordset = self.list_record_set_zone(zone['id']) + self.verify_recordset(recordset, 3) + + @decorators.idempotent_id('35ad8341-e96a-49ba-8463-54465051c7a4') + def test_zone_list_without_fip_instance_provider_vlan(self): + """ + Create a zone, check zone exits + Create a network and subnet + Update network with the zone + Boot a VM + Verify recordset only has SOA and NS record types + """ + image_id = self.get_glance_image_id(['cirros', 'esx']) + zone = self.create_zone() + network_designate = self.create_zone_provider_vlan_vxlan_topology( + 'vxlan', zone['name']) + self.assertEqual(network_designate['dns_domain'], zone['name']) + LOG.info('Show recordset of the zone') + recordset = self.list_record_set_zone(zone['id']) + self.verify_recordset(recordset, 2) + self.create_topology_instance( + "dns_vm", [network_designate], + security_groups=[{'name': self.designate_sg['name']}], + clients=self.os_adm, + create_floating_ip=False, image_id=image_id) + LOG.info('Show recordset of the zone') + recordset = self.list_record_set_zone(zone['id']) + self.verify_recordset(recordset, 3) + @decorators.idempotent_id('a4de3cca-54e1-4e8b-8b52-2148e55eed84') def test_zone_list_with_fip_instance(self): """ @@ -217,7 +304,7 @@ class TestZonesScenario(TestZonesV2Ops): Create a port Verify zone record set has SOA and NS record typres """ - zone = self.create_designate_zone() + zone = self.create_zone() network_designate = self.create_zone_topology(zone['name']) self.assertEqual(network_designate['dns_domain'], zone['name']) LOG.info('Show recordset of the zone') @@ -298,6 +385,51 @@ class TestZonesScenario(TestZonesV2Ops): raise Exception('DNS response does not have entry ' 'for the instance') + @decorators.idempotent_id('2c3c0f63-c557-458f-a8f4-3b0e3065ed97') + def test_zone_reverse_nslookup_from_extvm(self): + """ + Create a zone + Update network with zone + Boot an instance and associate fip + Perform nslookup for the dns name from ext vm + """ + image_id = self.get_glance_image_id(['cirros', 'esx']) + zone = self.create_zone() + network_designate = self.create_zone_topology(zone['name']) + self.assertEqual(network_designate['dns_domain'], zone['name']) + dns_vm = self.create_topology_instance( + "dns_vm", [network_designate], + security_groups=[{'name': self.designate_sg['name']}], + clients=self.os_adm, + create_floating_ip=True, image_id=image_id) + fip = dns_vm['floating_ips'][0]['floating_ip_address'] + fip_id = dns_vm['floating_ips'][0]['id'] + ptr_rev_name = '.'.join(reversed(fip.split("."))) + ".in-addr.arpa" + LOG.info('Show recordset of the zone') + recordset = self.list_record_set_zone(zone['id']) + self.verify_recordset(recordset, 3) + record = self.verify_recordset_floatingip(recordset, fip) + if record is None: + raise Exception('fip is missing in the recordset') + my_resolver = dns.resolver.Resolver() + nameserver = CONF.dns.nameservers[0][:-3] + my_resolver.nameservers = [nameserver] + #wait for status to change from pending to active + time.sleep(const.ZONE_WAIT_TIME) + region = const.REGION_NAME + #check PTR record + ptr_record = self.show_ptr_record(region, fip_id) + self.assertEqual(fip, ptr_record[1]['address']) + try: + answer = my_resolver.query(ptr_rev_name, "PTR") + except Exception: + LOG.error('ns lookup failed on ext-vm') + if (ptr_rev_name not in answer.response.to_text() + or record['name'] not in answer.response.to_text()): + LOG.error('failed to perform reverse dns for the instance') + raise Exception('Reverse DNS response does not have entry ' + 'for the instance') + @decorators.idempotent_id('6286cbd5-b0e4-4daa-9d8f-f27802c95925') def test_zone_deletion_post_fip_association(self): """ @@ -306,7 +438,10 @@ class TestZonesScenario(TestZonesV2Ops): Boot an instance and associate fip Delete zone successfully """ - image_id = self.get_glance_image_id(['cirros', 'esx']) + try: + image_id = self.get_glance_image_id(['cirros', 'esx']) + except Exception: + LOG.error('cirros image is absent for esx HV') zone = self.create_zone() network_designate = self.create_zone_topology(zone['name']) self.assertEqual(network_designate['dns_domain'], zone['name']) @@ -331,3 +466,26 @@ class TestZonesScenario(TestZonesV2Ops): time.sleep(const.ZONE_WAIT_TIME) self.assertRaises(lib_exc.NotFound, self.delete_zone, zone['id']) + + @decorators.idempotent_id('6963e17e-9404-4397-8738-cf0190ab2a66') + def test_negative_dns_network_update(self): + """ + Create a zone + Update network with different dns name + Boot an instance and associate fip + Verify the recordset of the guestVM does not contain + 'A' record type + """ + image_id = self.get_glance_image_id(['cirros', 'esx']) + zone = self.create_zone() + network_designate = self.create_zone_topology( + const.ZONE_NAME) + self.assertNotEqual(network_designate['dns_domain'], zone['name']) + self.create_topology_instance( + "dns_vm", [network_designate], + security_groups=[{'name': self.designate_sg['name']}], + clients=self.os_adm, + create_floating_ip=True, image_id=image_id) + LOG.info('Show recordset of the zone') + recordset = self.list_record_set_zone(zone['id']) + self.verify_recordset(recordset, 2)