Merge "[Tempest] Deploy and Validate Neutron resources using HEAT Orchestration Template"

This commit is contained in:
Jenkins 2017-03-31 22:15:50 +00:00 committed by Gerrit Code Review
commit 7b64469d32
2 changed files with 705 additions and 0 deletions

View File

@ -0,0 +1,252 @@
# 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.
import os
import re
import yaml
from oslo_log import log as logging
from tempest.api.orchestration import base
from tempest.common.utils import data_utils
from tempest import config
from tempest.lib import decorators
from tempest.scenario import manager
from tempest import test
from vmware_nsx_tempest.services import nsxv_client
CONF = config.CONF
LOG = logging.getLogger(__name__)
DIR_PATH = '/opt/stack/vmware-nsx/vmware_nsx_tempest/tests/'
class HeatSmokeTest(base.BaseOrchestrationTest,
manager.NetworkScenarioTest):
"""Deploy and Test Neutron Resources using HEAT.
The script load the neutron resources from template and fully
validates successful deployment of all resources from the template.
The template consists of two toplogies with Shared and Exclusive router.
Tests will be common to toplogies (pls refer template for topo info)and
will be as below :
1. verify created resources from template
2. verify all created resouces from template
-->neutronDB-->NSXbackend
3. check same network connectivity
4. check cross network connectivity
"""
def setUp(self):
super(HeatSmokeTest, self).setUp()
self.external_network = CONF.scenario.outside_world_servers
@classmethod
def read_template(cls, name, ext='yaml'):
loc = ["templates", "%s.%s" % (name, ext)]
filepath = os.path.join(DIR_PATH, *loc)
if os.path.isfile(filepath):
with open(filepath, "r") as f:
content = f.read()
return content
else:
raise IOError("File %s not found " % filepath)
@classmethod
def load_template(cls, name, ext='yaml'):
loc = ["templates", "%s.%s" % (name, ext)]
filepath = os.path.join(DIR_PATH, *loc)
if os.path.isfile(filepath):
with open(filepath, "r") as f:
return yaml.safe_load(f)
else:
raise IOError("File %s not found " % filepath)
@classmethod
def resource_setup(cls):
super(HeatSmokeTest, cls).resource_setup()
cls.stack_name = data_utils.rand_name('heat')
try:
cls.neutron_basic_template = cls.load_template(
'nsxv_neutron_smoke')
template = cls.read_template('nsxv_neutron_smoke')
except IOError as e:
LOG.exception(("file nsxv_neutron_smoke.yaml not found %(rsp)s") %
{'rsp': e})
cls.stack_identifier = cls.create_stack(cls.stack_name, template)
cls.client.wait_for_stack_status(cls.stack_identifier,
'CREATE_COMPLETE')
cls.stack_id = cls.stack_identifier.split('/')[1]
cls.resources = (cls.client.list_resources(cls.stack_identifier)
['resources'])
cls.test_resources = {}
for resource in cls.resources:
cls.test_resources[resource['logical_resource_id']] = resource
@classmethod
def setup_credentials(cls):
cls.set_network_resources()
super(HeatSmokeTest, cls).setup_credentials()
@classmethod
def setup_clients(cls):
super(HeatSmokeTest, cls).setup_clients()
cls.routers_client = cls.os.routers_client
cls.subnets_client = cls.os.subnets_client
manager_ip = re.search(r"(\d{1,3}\.){3}\d{1,3}",
CONF.nsxv.manager_uri).group(0)
cls.vsm = nsxv_client.VSMClient(
manager_ip, CONF.nsxv.user, CONF.nsxv.password)
def _resource_list_check(self, resource):
# sorts out the resources and returns resource id
if resource == 'networks':
body = self.networks_client.list_networks()
component = 'OS::Neutron::Net'
elif resource == 'routers':
body = self.routers_client.list_routers()
component = 'OS::Neutron::Router'
print(body)
elif resource == 'servers':
body = self.servers_client.list_servers()
component = 'OS::Nova::Server'
resource_list_id = [res_list['id'] for res_list in body[resource]]
test_resource_list_id = []
for _, resource in self.test_resources.items():
if resource['resource_type'] == component:
test_resource_list_id.append(resource['physical_resource_id'])
for resource_id in test_resource_list_id:
self.assertIn(resource_id, resource_list_id)
return test_resource_list_id
def _check_server_connectivity(self, floating_ip, address_list,
should_connect=True):
# checks server connectivity
private_key = self.get_stack_output(self.stack_identifier,
'private_key')
ssh_source = self.get_remote_client(floating_ip,
private_key=private_key)
for remote_ip in address_list:
if should_connect:
msg = ("Timed out waiting for %s to become "
"reachable") % remote_ip
else:
msg = "ip address %s is reachable" % remote_ip
try:
self.assertTrue(self._check_remote_connectivity
(ssh_source, remote_ip, should_connect),
msg)
except Exception:
LOG.exception(("Unable to access %(dest)s via ssh to "
"floating-ip %(src)s") %
{'dest': remote_ip, 'src': floating_ip})
raise
@decorators.idempotent_id('f693a425-b018-4cde-96ab-cdd5b858e15c')
@test.attr(type=["smoke"])
def test_created_resources(self):
"""Verifies created resources from template ."""
for resource in self.resources:
msg = 'resource %s not create successfully' \
% resource['logical_resource_id']
self.assertEqual('CREATE_COMPLETE', resource['resource_status'],
msg)
self.assertIsInstance(resource, dict)
@decorators.idempotent_id('3c3ccfcb-e50b-4372-82dc-d5b473acd506')
@test.attr(type=["smoke"])
def test_created_network(self):
"""Verifies created neutron networks."""
network_id_list = self._resource_list_check(resource='networks')
for network_id in network_id_list:
body = self.networks_client.show_network(network_id)
self.assertEqual('True', str(body['network']['admin_state_up']))
msg = 'newtwork %s not found' % body['network']['name']
self.assertIsNotNone(self.vsm.get_logical_switch(network_id), msg)
@decorators.idempotent_id('b3b103a7-69b2-42ea-a1b8-aa11cc551df9')
@test.attr(type=["smoke"])
def test_created_router(self):
"""Verifies created router."""
router_id_list = self._resource_list_check(resource='routers')
for router_id in router_id_list:
body = self.routers_client.show_router(router_id)
self.assertEqual('True', str(body['router']['admin_state_up']))
if (body['router']['router_type']) != 'shared':
router_edge_name = "%s-%s" % (
body['router']['name'], body['router']['id'])
exc_edge = self.vsm.get_edge(router_edge_name)
msg = 'exc edge %s not found' % body['router']['name']
self.assertTrue(exc_edge is not None, msg)
@decorators.idempotent_id('2b29dfef-6d9f-4a70-9377-af432100ef10')
@test.attr(type=["smoke"])
def test_created_server(self):
"""Verifies created sever."""
server_id_list = self._resource_list_check(resource='servers')
for server_id in server_id_list:
server = self.servers_client.show_server(server_id)['server']
msg = 'server %s not active ' % (server)
self.assertEqual('ACTIVE', str(server['status']), msg)
@decorators.idempotent_id('d937a607-aa5e-4cf1-bbf9-00044cbe7190')
@test.attr(type=["smoke"])
def test_topo1_same_network_connectivity_(self):
"""Verifies same network connnectivity for Topology 1 """
address_list = []
topo1_server1_floatingip = self.get_stack_output(self.stack_identifier,
'topo1_server1_floatingip')
server4_private_ip = self.get_stack_output(self.stack_identifier,
'topo1_server4_private_ip')
address_list.append(server4_private_ip)
LOG.info((" floating ip :%(rsp)s and private ip list : %(rsp1)s") %
{"rsp": topo1_server1_floatingip, "rsp1": address_list})
self._check_server_connectivity(topo1_server1_floatingip, address_list,
should_connect=True)
@decorators.idempotent_id('fdbc8b1a-755a-4b37-93e7-0a268e422f05')
@test.attr(type=["smoke"])
def test_topo1_cross_network_connectivity(self):
"""Verifies cross network connnectivity for Topology 1 """
address_list = []
topo1_server1_floatingip = self.get_stack_output(
self.stack_identifier, 'topo1_server1_floatingip')
server2_private_ip = self.get_stack_output(self.stack_identifier,
'topo1_server2_private_ip')
server3_private_ip = self.get_stack_output(self.stack_identifier,
'topo1_server3_private_ip')
address_list.append(server2_private_ip)
address_list.append(server3_private_ip)
LOG.info(("floating ip :%(rsp)s and private ip list : %(rsp1)s") %
{"rsp": topo1_server1_floatingip, "rsp1": address_list})
self._check_server_connectivity(topo1_server1_floatingip, address_list,
should_connect=True)
@decorators.idempotent_id('bcefd117-c55e-499d-a34b-653b8981f1c5')
@test.attr(type=["smoke"])
def test_topo1_cross_external_connectivity(self):
"""Verifies external network connnectivity for Topology 1 """
address_list = []
topo1_server1_floatingip = self.get_stack_output(self.stack_identifier,
'topo1_server1_floatingip')
external_network = self.external_network[0]
address_list.append(external_network)
LOG.info(("floating ip :%(rsp)s and external ip : %(rsp1)s") %
{"rsp": topo1_server1_floatingip, "rsp1": address_list})
self._check_server_connectivity(topo1_server1_floatingip, address_list,
should_connect=True)

View File

@ -0,0 +1,453 @@
heat_template_version: 2013-05-23
description: >
Topology 1:
- 4 servers (Cirros))
- 2 Logical Switches
- 1 Logical Router (Shared)
- 2 Security Group allowing HTTP
Topology 2:
- 2 servers (Cirros))
- 2 Logical Switch
- 1 Logical Router (Exclusive)
- 1 Security Group allowing HTTP
parameters:
public_net:
label: Public Network ID for external connectivity
type: string
description: >
ID or name of public network
# Need to update this network UUID for each vPod.
default: ext-net
dmz_network:
default: ext-net
description: "External network"
type: string
ubuntu_image:
default: cirros
description: "Ubuntu image"
type: string
resources:
# Topology1
heat_NAT_web_net:
type: OS::Neutron::Net
properties:
name: heat_NAT_web
heat_NAT_web_subnet:
type: OS::Neutron::Subnet
properties:
network_id: { get_resource: heat_NAT_web_net }
cidr: 10.21.1.0/24
dns_nameservers: [ "10.166.17.90" ]
heat_NAT_db_net:
type: OS::Neutron::Net
properties:
name: heat_NAT_db
heat_NAT_db_subnet:
type: OS::Neutron::Subnet
properties:
network_id: { get_resource: heat_NAT_db_net }
cidr: 10.21.2.0/24
dns_nameservers: [ "10.166.17.90" ]
my_key:
type: OS::Nova::KeyPair
properties:
save_private_key: true
name: my_key
router:
type: OS::Neutron::Router
properties:
admin_state_up: true
name: heat_NAT_router
router_gw:
type: OS::Neutron::RouterGateway
properties:
network_id: { get_param: public_net}
router_id: { get_resource: router }
router_interface1:
type: OS::Neutron::RouterInterface
properties:
router_id: { get_resource: router }
subnet_id: { get_resource: heat_NAT_web_subnet }
router_interface2:
type: OS::Neutron::RouterInterface
properties:
router_id: { get_resource: router }
subnet_id: { get_resource: heat_NAT_db_subnet }
heat_NAT_web_secgroup:
type: OS::Neutron::SecurityGroup
properties:
name: heat_NAT_web_secgroup
rules:
- protocol: tcp
remote_ip_prefix: 0.0.0.0/0
port_range_min: 443
port_range_max: 443
- protocol: tcp
remote_ip_prefix: 0.0.0.0/0
port_range_min: 22
port_range_max: 22
- protocol: icmp
remote_ip_prefix: 0.0.0.0/0
heat_NAT_db_secgroup:
type: OS::Neutron::SecurityGroup
properties:
name: heat_NAT_db_secgroup
rules:
- protocol: tcp
remote_mode: remote_group_id
remote_group_id: { get_resource: heat_NAT_web_secgroup }
port_range_min: 3307
port_range_max: 3307
- protocol: icmp
remote_ip_prefix: 0.0.0.0/0
server1_port:
type: OS::Neutron::Port
properties:
network_id: { get_resource: heat_NAT_web_net }
security_groups:
- { get_resource: heat_NAT_web_secgroup }
server1_instance:
type: OS::Nova::Server
properties:
image: cirros
flavor: m1.tiny
key_name: { get_resource: my_key }
networks:
- port: { get_resource: server1_port }
server1_floating_ip:
type: OS::Neutron::FloatingIP
properties:
floating_network_id: { get_param: public_net }
port_id: { get_resource: server1_port }
server2_port:
type: OS::Neutron::Port
properties:
network_id: { get_resource: heat_NAT_db_net }
security_groups:
- { get_resource: heat_NAT_db_secgroup }
server2_instance:
type: OS::Nova::Server
properties:
image: cirros
flavor: m1.tiny
key_name: { get_resource: my_key }
networks:
- port: { get_resource: server2_port }
server3_port:
type: OS::Neutron::Port
properties:
network_id: { get_resource: heat_NAT_db_net }
security_groups:
- { get_resource: heat_NAT_db_secgroup }
server3_instance:
type: OS::Nova::Server
properties:
image: cirros
flavor: m1.tiny
key_name: { get_resource: my_key }
networks:
- port: { get_resource: server3_port }
server4_port:
type: OS::Neutron::Port
properties:
network_id: { get_resource: heat_NAT_web_net }
security_groups:
- { get_resource: heat_NAT_web_secgroup }
server4_instance:
type: OS::Nova::Server
properties:
image: cirros
flavor: m1.tiny
key_name: { get_resource: my_key }
networks:
- port: { get_resource: server4_port }
# Topology2
dmz_router:
properties:
admin_state_up: true
external_gateway_info:
network:
get_param: dmz_network
name:
Fn::Join:
- '_'
- [get_param: "OS::stack_name", "DmzGateway"]
value_specs:
router_type: exclusive
type: "OS::Neutron::Router"
floatingip_jump:
properties:
floating_network:
get_param: dmz_network
type: "OS::Neutron::FloatingIP"
floatingip_jump_association:
depends_on:
- floatingip_jump
- server_jump1
- router_interface_subnet_mgmt_dmz
properties:
floating_ip:
get_resource: floatingip_jump
server_id:
get_resource: server_jump1
type: "OS::Nova::FloatingIPAssociation"
network_mgmt:
properties:
admin_state_up: true
name:
Fn::Join:
- '_'
- [get_param: "OS::stack_name", "mgmt"]
shared: false
type: "OS::Neutron::Net"
network_mgmt2:
properties:
admin_state_up: true
name:
Fn::Join:
- '_'
- [get_param: "OS::stack_name", "mgmt2"]
shared: false
type: "OS::Neutron::Net"
port_dmz_jump:
depends_on:
- security_group
- subnet_mgmt
properties:
fixed_ips:
- ip_address: "50.0.0.10"
security_groups:
- get_resource: security_group
network_id:
get_resource: network_mgmt
type: "OS::Neutron::Port"
port_dmz_jump2:
depends_on:
- security_group
- subnet_mgmt
properties:
fixed_ips:
- ip_address: "60.0.0.10"
security_groups:
- get_resource: security_group
network_id:
get_resource: network_mgmt2
type: "OS::Neutron::Port"
port_mgmt_dmz_router:
depends_on:
- security_group
- subnet_mgmt
properties:
fixed_ips:
- ip_address: "50.0.0.254"
network_id:
get_resource: network_mgmt
security_groups:
- get_resource: security_group
type: "OS::Neutron::Port"
router_interface_subnet_mgmt_dmz:
depends_on:
- dmz_router
- port_mgmt_dmz_router
properties:
port_id:
get_resource: port_mgmt_dmz_router
router_id:
get_resource: dmz_router
type: "OS::Neutron::RouterInterface"
port_mgmt_dmz_router2:
depends_on:
- security_group
- subnet_mgmt2
properties:
fixed_ips:
- ip_address: "60.0.0.254"
network_id:
get_resource: network_mgmt2
security_groups:
- get_resource: security_group
type: "OS::Neutron::Port"
router_interface_subnet_mgmt_dmz2:
depends_on:
- dmz_router
- port_mgmt_dmz_router2
properties:
port_id:
get_resource: port_mgmt_dmz_router2
router_id:
get_resource: dmz_router
type: "OS::Neutron::RouterInterface"
security_group:
properties:
description: "Allows all"
name:
Fn::Join:
- '_'
- [get_param: "OS::stack_name", "Permissive"]
rules:
-
direction: ingress
ethertype: IPv4
port_range_max: 65535
port_range_min: 1
protocol: tcp
remote_ip_prefix: 0.0.0.0/0
-
direction: ingress
ethertype: IPv4
port_range_max: 65535
port_range_min: 1
protocol: udp
remote_ip_prefix: 0.0.0.0/0
-
direction: ingress
ethertype: IPv4
protocol: icmp
remote_ip_prefix: 0.0.0.0/0
-
direction: egress
ethertype: IPv4
port_range_max: 65535
port_range_min: 1
protocol: tcp
remote_ip_prefix: 0.0.0.0/0
-
direction: egress
ethertype: IPv4
port_range_max: 65535
port_range_min: 1
protocol: udp
remote_ip_prefix: 0.0.0.0/0
-
direction: egress
ethertype: IPv4
protocol: icmp
remote_ip_prefix: 0.0.0.0/0
type: "OS::Neutron::SecurityGroup"
server_jump1:
depends_on:
- port_dmz_jump
properties:
diskConfig: MANUAL
flavor: m1.tiny
image:
get_param: ubuntu_image
key_name: { get_resource: my_key }
name:
Fn::Join:
- '_'
- [get_param: "OS::stack_name", "JumpServer1"]
networks:
- port:
get_resource: port_dmz_jump
networks:
- port:
get_resource: port_dmz_jump
type: "OS::Nova::Server"
subnet_mgmt:
depends_on:
- network_mgmt
properties:
allocation_pools:
-
end: "50.0.0.250"
start: "50.0.0.2"
cidr: 50.0.0.0/24
dns_nameservers:
- "172.17.100.11"
enable_dhcp: true
ip_version: 4
name:
Fn::Join:
- '_'
- [get_param: "OS::stack_name", "DMZSubnet"]
network_id:
get_resource: network_mgmt
type: "OS::Neutron::Subnet"
subnet_mgmt2:
depends_on:
- network_mgmt2
properties:
allocation_pools:
-
end: "60.0.0.250"
start: "60.0.0.2"
cidr: 60.0.0.0/24
dns_nameservers:
- "172.17.100.11"
enable_dhcp: true
ip_version: 4
name:
Fn::Join:
- '_'
- [get_param: "OS::stack_name", "DMZSubnet2"]
network_id:
get_resource: network_mgmt2
type: "OS::Neutron::Subnet"
server_jump2:
properties:
diskConfig: MANUAL
flavor: m1.tiny
image:
get_param: ubuntu_image
key_name: { get_resource: my_key }
name:
Fn::Join:
- '_'
- [get_param: "OS::stack_name", "JumpServer2"]
networks:
- port:
get_resource: port_dmz_jump2
depends_on: [ port_dmz_jump2 ]
type: OS::Nova::Server
outputs:
topo1_server1_floatingip:
description: Floating IP address of Topology1_Server1_floatingip
value: { get_attr: [ server1_floating_ip, floating_ip_address ] }
topo1_server1_private_ip:
description: Private IP address of the deployed compute instance
value: { get_attr: [server1_instance, networks, heat_NAT_web, 0] }
topo1_server2_private_ip:
description: Private IP address of the deployed compute instance
value: { get_attr: [server2_instance, networks, heat_NAT_db, 0] }
topo1_server3_private_ip:
description: Private IP address of the deployed compute instance
value: { get_attr: [server3_instance, networks, heat_NAT_db, 0] }
topo1_server4_private_ip:
description: Private IP address of the deployed compute instance
value: { get_attr: [server4_instance, networks, heat_NAT_web, 0] }
private_key:
description: Private key
value: { get_attr: [ my_key, private_key ] }