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 xtesting.core import testcase
30 from functest.utils import config
31 from functest.utils import env
34 class NewProject(object):
35 """Ease creating new projects/users"""
36 # pylint: disable=too-many-instance-attributes
38 __logger = logging.getLogger(__name__)
40 def __init__(self, cloud, case_name, guid):
42 self.orig_cloud = cloud
43 self.case_name = case_name
50 self.default_member = env.get('NEW_USER_ROLE')
53 """Create projects/users"""
54 assert self.orig_cloud
56 self.password = str(uuid.uuid4())
57 self.domain = self.orig_cloud.get_domain(
58 name_or_id=self.orig_cloud.auth.get(
59 "project_domain_name", "Default"))
60 self.project = self.orig_cloud.create_project(
61 name='{}-project_{}'.format(self.case_name[:18], self.guid),
62 description="Created by OPNFV Functest: {}".format(
64 domain_id=self.domain.id)
65 self.__logger.debug("project: %s", self.project)
66 self.user = self.orig_cloud.create_user(
67 name='{}-user_{}'.format(self.case_name, self.guid),
68 password=self.password,
69 domain_id=self.domain.id)
70 self.__logger.debug("user: %s", self.user)
72 if self.orig_cloud.get_role(self.default_member):
73 self.role_name = self.default_member
74 elif self.orig_cloud.get_role(self.default_member.lower()):
75 self.role_name = self.default_member.lower()
77 raise Exception("Cannot detect {}".format(self.default_member))
78 except Exception: # pylint: disable=broad-except
79 self.__logger.info("Creating default role %s", self.default_member)
80 role = self.orig_cloud.create_role(self.default_member)
81 self.role_name = role.name
82 self.__logger.debug("role: %s", role)
83 self.orig_cloud.grant_role(
84 self.role_name, user=self.user.id, project=self.project.id,
85 domain=self.domain.id)
86 osconfig = os_client_config.config.OpenStackConfig()
87 osconfig.cloud_config[
88 'clouds']['envvars']['project_name'] = self.project.name
89 osconfig.cloud_config[
90 'clouds']['envvars']['project_id'] = self.project.id
91 osconfig.cloud_config['clouds']['envvars']['username'] = self.user.name
92 osconfig.cloud_config['clouds']['envvars']['password'] = self.password
93 self.__logger.debug("cloud_config %s", osconfig.cloud_config)
94 self.cloud = shade.OpenStackCloud(
95 cloud_config=osconfig.get_one_cloud())
96 self.__logger.debug("new cloud %s", self.cloud.auth)
99 """Remove projects/users"""
101 assert self.orig_cloud
103 self.orig_cloud.delete_user(self.user.id)
105 self.orig_cloud.delete_project(self.project.id)
106 secgroups = self.orig_cloud.list_security_groups(
107 filters={'name': 'default',
108 'project_id': self.project.id})
110 sec_id = secgroups[0].id
111 self.orig_cloud.delete_security_group(sec_id)
112 except Exception: # pylint: disable=broad-except
113 self.__logger.exception("Cannot clean all resources")
116 class TenantNetwork1(testcase.TestCase):
117 # pylint: disable=too-many-instance-attributes
118 """Create a tenant network (scenario1)
120 It creates and configures all tenant network resources required by
121 advanced testcases (subnet, network and router).
123 It ensures that all testcases inheriting from TenantNetwork1 could work
124 without network specific configurations (or at least read the same config
128 __logger = logging.getLogger(__name__)
129 cidr = '192.168.120.0/24'
130 shared_network = False
132 def __init__(self, **kwargs):
133 if "case_name" not in kwargs:
134 kwargs["case_name"] = 'tenantnetwork1'
135 super(TenantNetwork1, self).__init__(**kwargs)
136 self.res_dir = os.path.join(
137 getattr(config.CONF, 'dir_results'), self.case_name)
139 cloud_config = os_client_config.get_config()
140 self.cloud = self.orig_cloud = shade.OpenStackCloud(
141 cloud_config=cloud_config)
142 except Exception: # pylint: disable=broad-except
143 self.cloud = self.orig_cloud = None
145 self.__logger.exception("Cannot connect to Cloud")
147 self.ext_net = self.get_external_network(self.cloud)
148 except Exception: # pylint: disable=broad-except
149 self.__logger.exception("Cannot get the external network")
150 self.guid = str(uuid.uuid4())
156 def get_external_network(cloud):
158 Return the configured external network name or
159 the first retrieved external network name
162 if env.get("EXTERNAL_NETWORK"):
163 network = cloud.get_network(
164 env.get("EXTERNAL_NETWORK"), {"router:external": True})
167 networks = cloud.list_networks({"router:external": True})
173 def get_default_role(cloud, member="Member"):
174 """Get the default role
176 It also tests the role in lowercase to avoid possible conflicts.
178 role = cloud.get_role(member)
180 role = cloud.get_role(member.lower())
184 def get_public_auth_url(cloud):
185 """Get Keystone public endpoint"""
186 keystone_id = cloud.search_services('keystone')[0].id
187 endpoint = cloud.search_endpoints(
188 filters={'interface': 'public',
189 'service_id': keystone_id})[0].url
192 def create_network_resources(self):
193 """Create all tenant network resources
195 It creates a router which gateway is the external network detected.
196 The new subnet is attached to that router.
198 Raises: expection on error
203 if hasattr(config.CONF, '{}_network_type'.format(self.case_name)):
204 provider["network_type"] = getattr(
205 config.CONF, '{}_network_type'.format(self.case_name))
206 if hasattr(config.CONF, '{}_physical_network'.format(self.case_name)):
207 provider["physical_network"] = getattr(
208 config.CONF, '{}_physical_network'.format(self.case_name))
209 if hasattr(config.CONF, '{}_segmentation_id'.format(self.case_name)):
210 provider["segmentation_id"] = getattr(
211 config.CONF, '{}_segmentation_id'.format(self.case_name))
212 domain = self.orig_cloud.get_domain(
213 name_or_id=self.orig_cloud.auth.get(
214 "project_domain_name", "Default"))
215 project = self.orig_cloud.get_project(
216 self.cloud.auth['project_name'],
218 self.network = self.orig_cloud.create_network(
219 '{}-net_{}'.format(self.case_name, self.guid),
220 provider=provider, project_id=project.id,
221 shared=self.shared_network)
222 self.__logger.debug("network: %s", self.network)
224 self.subnet = self.cloud.create_subnet(
226 subnet_name='{}-subnet_{}'.format(self.case_name, self.guid),
228 config.CONF, '{}_private_subnet_cidr'.format(self.case_name),
231 dns_nameservers=[env.get('NAMESERVER')])
232 self.__logger.debug("subnet: %s", self.subnet)
234 self.router = self.cloud.create_router(
235 name='{}-router_{}'.format(self.case_name, self.guid),
236 ext_gateway_net_id=self.ext_net.id)
237 self.__logger.debug("router: %s", self.router)
238 self.cloud.add_router_interface(self.router, subnet_id=self.subnet.id)
240 def run(self, **kwargs):
241 status = testcase.TestCase.EX_RUN_ERROR
244 self.start_time = time.time()
245 self.create_network_resources()
247 status = testcase.TestCase.EX_OK
248 except Exception: # pylint: disable=broad-except
249 self.__logger.exception('Cannot run %s', self.case_name)
251 self.stop_time = time.time()
259 self.cloud.remove_router_interface(
260 self.router, self.subnet.id)
261 self.cloud.delete_router(self.router.id)
263 self.cloud.delete_subnet(self.subnet.id)
265 self.cloud.delete_network(self.network.id)
266 except Exception: # pylint: disable=broad-except
267 self.__logger.exception("cannot clean all resources")
270 class TenantNetwork2(TenantNetwork1):
271 """Create a tenant network (scenario2)
273 It creates new user/project before creating and configuring all tenant
274 network resources required by a testcase (subnet, network and router).
276 It ensures that all testcases inheriting from TenantNetwork2 could work
277 without network specific configurations (or at least read the same config
281 __logger = logging.getLogger(__name__)
283 def __init__(self, **kwargs):
284 if "case_name" not in kwargs:
285 kwargs["case_name"] = 'tenantnetwork2'
286 super(TenantNetwork2, self).__init__(**kwargs)
289 self.project = NewProject(
290 self.cloud, self.case_name, self.guid)
291 self.project.create()
292 self.cloud = self.project.cloud
293 except Exception: # pylint: disable=broad-except
294 self.__logger.exception("Cannot create user or project")
300 super(TenantNetwork2, self).clean()
303 except Exception: # pylint: disable=broad-except
304 self.__logger.exception("Cannot clean all resources")