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)
28 import os_client_config
30 from xtesting.core import testcase
32 from functest.utils import config
33 from functest.utils import env
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 = ''.join(random.choice(
59 string.ascii_letters + string.digits +
60 '!()*+,-.<=>?@[]^_{|}~') for _ in range(30))
61 self.__logger.debug("password: %s", self.password)
62 self.domain = self.orig_cloud.get_domain(
63 name_or_id=self.orig_cloud.auth.get(
64 "project_domain_name", "Default"))
65 self.project = self.orig_cloud.create_project(
66 name='{}-project_{}'.format(self.case_name[:18], self.guid),
67 description="Created by OPNFV Functest: {}".format(
69 domain_id=self.domain.id)
70 self.__logger.debug("project: %s", self.project)
71 self.user = self.orig_cloud.create_user(
72 name='{}-user_{}'.format(self.case_name, self.guid),
73 password=self.password,
74 domain_id=self.domain.id)
75 self.__logger.debug("user: %s", self.user)
77 if self.orig_cloud.get_role(self.default_member):
78 self.role_name = self.default_member
79 elif self.orig_cloud.get_role(self.default_member.lower()):
80 self.role_name = self.default_member.lower()
82 raise Exception("Cannot detect {}".format(self.default_member))
83 except Exception: # pylint: disable=broad-except
84 self.__logger.info("Creating default role %s", self.default_member)
85 role = self.orig_cloud.create_role(self.default_member)
86 self.role_name = role.name
87 self.__logger.debug("role: %s", role)
88 self.orig_cloud.grant_role(
89 self.role_name, user=self.user.id, project=self.project.id,
90 domain=self.domain.id)
91 osconfig = os_client_config.config.OpenStackConfig()
92 osconfig.cloud_config[
93 'clouds']['envvars']['project_name'] = self.project.name
94 osconfig.cloud_config[
95 'clouds']['envvars']['project_id'] = self.project.id
96 osconfig.cloud_config['clouds']['envvars']['username'] = self.user.name
97 osconfig.cloud_config['clouds']['envvars']['password'] = self.password
98 self.__logger.debug("cloud_config %s", osconfig.cloud_config)
99 self.cloud = shade.OpenStackCloud(
100 cloud_config=osconfig.get_one_cloud())
101 self.__logger.debug("new cloud %s", self.cloud.auth)
103 def get_environ(self):
107 OS_USERNAME=self.user.name,
108 OS_PROJECT_NAME=self.project.name,
109 OS_PROJECT_ID=self.project.id,
110 OS_PASSWORD=self.password)
112 del environ['OS_TENANT_NAME']
113 del environ['OS_TENANT_ID']
114 except Exception: # pylint: disable=broad-except
119 """Remove projects/users"""
121 assert self.orig_cloud
123 self.orig_cloud.delete_user(self.user.id)
125 self.orig_cloud.delete_project(self.project.id)
126 secgroups = self.orig_cloud.list_security_groups(
127 filters={'name': 'default',
128 'project_id': self.project.id})
130 sec_id = secgroups[0].id
131 self.orig_cloud.delete_security_group(sec_id)
132 except Exception: # pylint: disable=broad-except
133 self.__logger.exception("Cannot clean all resources")
136 class TenantNetwork1(testcase.TestCase):
137 # pylint: disable=too-many-instance-attributes
138 """Create a tenant network (scenario1)
140 It creates and configures all tenant network resources required by
141 advanced testcases (subnet, network and router).
143 It ensures that all testcases inheriting from TenantNetwork1 could work
144 without network specific configurations (or at least read the same config
148 __logger = logging.getLogger(__name__)
149 cidr = '192.168.120.0/24'
150 shared_network = False
153 def __init__(self, **kwargs):
154 if "case_name" not in kwargs:
155 kwargs["case_name"] = 'tenantnetwork1'
156 super(TenantNetwork1, self).__init__(**kwargs)
157 self.res_dir = os.path.join(
158 getattr(config.CONF, 'dir_results'), self.case_name)
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 = cloud.search_services('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")