3 # Copyright (c) 2018 Orange and others.
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 """Ease deploying tenant networks
12 It offers a simple way to create all tenant network resources required by a
13 testcase (including all Functest ones):
15 - TenantNetwork1 selects the user and the project set as env vars
16 - TenantNetwork2 creates a user and project to isolate the same resources
18 This classes could be reused by more complexed scenarios (Single VM)
26 import os_client_config
28 from tempest.lib.common.utils import data_utils
29 from xtesting.core import testcase
31 from functest.utils import config
32 from functest.utils import env
33 from functest.utils import functest_utils
37 """Ease creating new projects/users"""
38 # pylint: disable=too-many-instance-attributes
40 __logger = logging.getLogger(__name__)
42 def __init__(self, cloud, case_name, guid):
44 self.orig_cloud = cloud
45 self.case_name = case_name
52 self.default_member = env.get('NEW_USER_ROLE')
55 """Create projects/users"""
56 assert self.orig_cloud
58 self.password = data_utils.rand_password().replace('%', '!')
59 self.__logger.debug("password: %s", self.password)
60 self.domain = self.orig_cloud.get_domain(
61 name_or_id=self.orig_cloud.auth.get(
62 "project_domain_name", "Default"))
63 self.project = self.orig_cloud.create_project(
64 name='{}-project_{}'.format(self.case_name[:18], self.guid),
65 description="Created by OPNFV Functest: {}".format(
67 domain_id=self.domain.id)
68 self.__logger.debug("project: %s", self.project)
69 self.user = self.orig_cloud.create_user(
70 name='{}-user_{}'.format(self.case_name, self.guid),
71 password=self.password,
72 domain_id=self.domain.id)
73 self.__logger.debug("user: %s", self.user)
75 if self.orig_cloud.get_role(self.default_member):
76 self.role_name = self.default_member
77 elif self.orig_cloud.get_role(self.default_member.lower()):
78 self.role_name = self.default_member.lower()
80 raise Exception("Cannot detect {}".format(self.default_member))
81 except Exception: # pylint: disable=broad-except
82 self.__logger.info("Creating default role %s", self.default_member)
83 role = self.orig_cloud.create_role(self.default_member)
84 self.role_name = role.name
85 self.__logger.debug("role: %s", role)
86 self.orig_cloud.grant_role(
87 self.role_name, user=self.user.id, project=self.project.id,
88 domain=self.domain.id)
89 osconfig = os_client_config.config.OpenStackConfig()
90 osconfig.cloud_config[
91 'clouds']['envvars']['project_name'] = self.project.name
92 osconfig.cloud_config[
93 'clouds']['envvars']['project_id'] = self.project.id
94 osconfig.cloud_config['clouds']['envvars']['username'] = self.user.name
95 osconfig.cloud_config['clouds']['envvars']['password'] = self.password
96 self.__logger.debug("cloud_config %s", osconfig.cloud_config)
97 self.cloud = shade.OpenStackCloud(
98 cloud_config=osconfig.get_one_cloud())
99 self.__logger.debug("new cloud %s", self.cloud.auth)
101 def get_environ(self):
105 OS_USERNAME=self.user.name,
106 OS_PROJECT_NAME=self.project.name,
107 OS_PROJECT_ID=self.project.id,
108 OS_PASSWORD=self.password)
110 del environ['OS_TENANT_NAME']
111 del environ['OS_TENANT_ID']
112 except Exception: # pylint: disable=broad-except
117 """Remove projects/users"""
119 assert self.orig_cloud
121 self.orig_cloud.delete_user(self.user.id)
123 self.orig_cloud.delete_project(self.project.id)
124 secgroups = self.orig_cloud.list_security_groups(
125 filters={'name': 'default',
126 'project_id': self.project.id})
128 sec_id = secgroups[0].id
129 self.orig_cloud.delete_security_group(sec_id)
130 except Exception: # pylint: disable=broad-except
131 self.__logger.exception("Cannot clean all resources")
134 class TenantNetwork1(testcase.TestCase):
135 # pylint: disable=too-many-instance-attributes
136 """Create a tenant network (scenario1)
138 It creates and configures all tenant network resources required by
139 advanced testcases (subnet, network and router).
141 It ensures that all testcases inheriting from TenantNetwork1 could work
142 without network specific configurations (or at least read the same config
146 __logger = logging.getLogger(__name__)
147 cidr = '192.168.120.0/24'
148 shared_network = False
151 def __init__(self, **kwargs):
152 if "case_name" not in kwargs:
153 kwargs["case_name"] = 'tenantnetwork1'
154 super(TenantNetwork1, self).__init__(**kwargs)
155 self.res_dir = os.path.join(
156 getattr(config.CONF, 'dir_results'), self.case_name)
157 self.output_log_name = 'functest.log'
158 self.output_debug_log_name = 'functest.debug.log'
160 cloud_config = os_client_config.get_config()
161 self.cloud = self.orig_cloud = shade.OpenStackCloud(
162 cloud_config=cloud_config)
163 except Exception: # pylint: disable=broad-except
164 self.cloud = self.orig_cloud = None
166 self.__logger.exception("Cannot connect to Cloud")
168 self.ext_net = self.get_external_network(self.cloud)
169 except Exception: # pylint: disable=broad-except
171 self.__logger.exception("Cannot get the external network")
172 self.guid = str(uuid.uuid4())
178 def get_external_network(cloud):
180 Return the configured external network name or
181 the first retrieved external network name
184 if env.get("EXTERNAL_NETWORK"):
185 network = cloud.get_network(
186 env.get("EXTERNAL_NETWORK"), {"router:external": True})
189 networks = cloud.list_networks({"router:external": True})
195 def get_default_role(cloud, member="Member"):
196 """Get the default role
198 It also tests the role in lowercase to avoid possible conflicts.
200 role = cloud.get_role(member)
202 role = cloud.get_role(member.lower())
206 def get_public_auth_url(cloud):
207 """Get Keystone public endpoint"""
208 keystone_id = functest_utils.search_services(cloud, 'keystone')[0].id
209 endpoint = cloud.search_endpoints(
210 filters={'interface': 'public',
211 'service_id': keystone_id})[0].url
214 def create_network_resources(self):
215 """Create all tenant network resources
217 It creates a router which gateway is the external network detected.
218 The new subnet is attached to that router.
220 Raises: expection on error
223 if not self.allow_no_fip:
226 if hasattr(config.CONF, '{}_network_type'.format(self.case_name)):
227 provider["network_type"] = getattr(
228 config.CONF, '{}_network_type'.format(self.case_name))
229 if hasattr(config.CONF, '{}_physical_network'.format(self.case_name)):
230 provider["physical_network"] = getattr(
231 config.CONF, '{}_physical_network'.format(self.case_name))
232 if hasattr(config.CONF, '{}_segmentation_id'.format(self.case_name)):
233 provider["segmentation_id"] = getattr(
234 config.CONF, '{}_segmentation_id'.format(self.case_name))
235 domain = self.orig_cloud.get_domain(
236 name_or_id=self.orig_cloud.auth.get(
237 "project_domain_name", "Default"))
238 project = self.orig_cloud.get_project(
239 self.cloud.auth['project_name'],
241 self.network = self.orig_cloud.create_network(
242 '{}-net_{}'.format(self.case_name, self.guid),
243 provider=provider, project_id=project.id,
244 shared=self.shared_network)
245 self.__logger.debug("network: %s", self.network)
247 self.subnet = self.cloud.create_subnet(
249 subnet_name='{}-subnet_{}'.format(self.case_name, self.guid),
251 config.CONF, '{}_private_subnet_cidr'.format(self.case_name),
254 dns_nameservers=[env.get('NAMESERVER')])
255 self.__logger.debug("subnet: %s", self.subnet)
257 self.router = self.cloud.create_router(
258 name='{}-router_{}'.format(self.case_name, self.guid),
259 ext_gateway_net_id=self.ext_net.id if self.ext_net else None)
260 self.__logger.debug("router: %s", self.router)
261 self.cloud.add_router_interface(self.router, subnet_id=self.subnet.id)
263 def run(self, **kwargs):
264 status = testcase.TestCase.EX_RUN_ERROR
267 self.start_time = time.time()
268 self.create_network_resources()
270 status = testcase.TestCase.EX_OK
271 except Exception: # pylint: disable=broad-except
272 self.__logger.exception('Cannot run %s', self.case_name)
274 self.stop_time = time.time()
282 self.cloud.remove_router_interface(
283 self.router, self.subnet.id)
284 self.cloud.delete_router(self.router.id)
286 self.cloud.delete_subnet(self.subnet.id)
288 self.cloud.delete_network(self.network.id)
289 except Exception: # pylint: disable=broad-except
290 self.__logger.exception("cannot clean all resources")
293 class TenantNetwork2(TenantNetwork1):
294 """Create a tenant network (scenario2)
296 It creates new user/project before creating and configuring all tenant
297 network resources required by a testcase (subnet, network and router).
299 It ensures that all testcases inheriting from TenantNetwork2 could work
300 without network specific configurations (or at least read the same config
304 __logger = logging.getLogger(__name__)
306 def __init__(self, **kwargs):
307 if "case_name" not in kwargs:
308 kwargs["case_name"] = 'tenantnetwork2'
309 super(TenantNetwork2, self).__init__(**kwargs)
312 self.project = NewProject(
313 self.cloud, self.case_name, self.guid)
314 self.project.create()
315 self.cloud = self.project.cloud
316 except Exception: # pylint: disable=broad-except
317 self.__logger.exception("Cannot create user or project")
323 super(TenantNetwork2, self).clean()
326 except Exception: # pylint: disable=broad-except
327 self.__logger.exception("Cannot clean all resources")