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
51 self.default_member = env.get('NEW_USER_ROLE')
54 """Create projects/users"""
55 assert self.orig_cloud
57 self.password = str(uuid.uuid4())
58 self.domain = self.orig_cloud.get_domain(
59 name_or_id=self.orig_cloud.auth.get(
60 "project_domain_name", "Default"))
61 self.project = self.orig_cloud.create_project(
62 name='{}-project_{}'.format(self.case_name[:18], self.guid),
63 description="Created by OPNFV Functest: {}".format(
65 domain_id=self.domain.id)
66 self.__logger.debug("project: %s", self.project)
67 self.user = self.orig_cloud.create_user(
68 name='{}-user_{}'.format(self.case_name, self.guid),
69 password=self.password,
70 domain_id=self.domain.id)
71 self.__logger.debug("user: %s", self.user)
73 if self.orig_cloud.get_role(self.default_member):
74 self.role_name = self.default_member
75 elif self.orig_cloud.get_role(self.default_member.lower()):
76 self.role_name = self.default_member.lower()
78 raise Exception("Cannot detect {}".format(self.default_member))
79 except Exception: # pylint: disable=broad-except
80 self.__logger.info("Creating default role %s", self.default_member)
81 self.role = self.orig_cloud.create_role(self.default_member)
82 self.role_name = self.role.name
83 self.__logger.debug("role: %s", self.role)
84 self.orig_cloud.grant_role(
85 self.role_name, user=self.user.id, project=self.project.id,
86 domain=self.domain.id)
87 osconfig = os_client_config.config.OpenStackConfig()
88 osconfig.cloud_config[
89 'clouds']['envvars']['project_name'] = self.project.name
90 osconfig.cloud_config[
91 'clouds']['envvars']['project_id'] = self.project.id
92 osconfig.cloud_config['clouds']['envvars']['username'] = self.user.name
93 osconfig.cloud_config['clouds']['envvars']['password'] = self.password
94 self.__logger.debug("cloud_config %s", osconfig.cloud_config)
95 self.cloud = shade.OpenStackCloud(
96 cloud_config=osconfig.get_one_cloud())
97 self.__logger.debug("new cloud %s", self.cloud.auth)
100 """Remove projects/users"""
102 assert self.orig_cloud
104 self.orig_cloud.delete_user(self.user.id)
106 self.orig_cloud.delete_project(self.project.id)
108 self.orig_cloud.delete_role(self.role.id)
109 sec_id = self.cloud.list_security_groups(
110 filters={'name': 'default',
111 'project_id': self.project.id})[0].id
112 self.orig_cloud.delete_security_group(sec_id)
113 except Exception: # pylint: disable=broad-except
114 self.__logger.exception("Cannot clean all resources")
117 class TenantNetwork1(testcase.TestCase):
118 # pylint: disable=too-many-instance-attributes
119 """Create a tenant network (scenario1)
121 It creates and configures all tenant network resources required by
122 advanced testcases (subnet, network and router).
124 It ensures that all testcases inheriting from TenantNetwork1 could work
125 without network specific configurations (or at least read the same config
129 __logger = logging.getLogger(__name__)
130 cidr = '192.168.120.0/24'
131 shared_network = False
133 def __init__(self, **kwargs):
134 if "case_name" not in kwargs:
135 kwargs["case_name"] = 'tenantnetwork1'
136 super(TenantNetwork1, self).__init__(**kwargs)
137 self.res_dir = os.path.join(
138 getattr(config.CONF, 'dir_results'), self.case_name)
140 cloud_config = os_client_config.get_config()
141 self.cloud = self.orig_cloud = shade.OpenStackCloud(
142 cloud_config=cloud_config)
143 except Exception: # pylint: disable=broad-except
144 self.cloud = self.orig_cloud = None
146 self.__logger.exception("Cannot connect to Cloud")
148 self.ext_net = self.get_external_network(self.cloud)
149 except Exception: # pylint: disable=broad-except
150 self.__logger.exception("Cannot get the external network")
151 self.guid = str(uuid.uuid4())
157 def get_external_network(cloud):
159 Return the configured external network name or
160 the first retrieved external network name
163 if env.get("EXTERNAL_NETWORK"):
164 network = cloud.get_network(
165 env.get("EXTERNAL_NETWORK"), {"router:external": True})
168 networks = cloud.list_networks({"router:external": True})
174 def get_default_role(cloud, member="Member"):
175 """Get the default role
177 It also tests the role in lowercase to avoid possible conflicts.
179 role = cloud.get_role(member)
181 role = cloud.get_role(member.lower())
185 def get_public_auth_url(cloud):
186 """Get Keystone public endpoint"""
187 keystone_id = cloud.search_services('keystone')[0].id
188 endpoint = cloud.search_endpoints(
189 filters={'interface': 'public',
190 'service_id': keystone_id})[0].url
193 def create_network_resources(self):
194 """Create all tenant network resources
196 It creates a router which gateway is the external network detected.
197 The new subnet is attached to that router.
199 Raises: expection on error
204 if hasattr(config.CONF, '{}_network_type'.format(self.case_name)):
205 provider["network_type"] = getattr(
206 config.CONF, '{}_network_type'.format(self.case_name))
207 if hasattr(config.CONF, '{}_physical_network'.format(self.case_name)):
208 provider["physical_network"] = getattr(
209 config.CONF, '{}_physical_network'.format(self.case_name))
210 if hasattr(config.CONF, '{}_segmentation_id'.format(self.case_name)):
211 provider["segmentation_id"] = getattr(
212 config.CONF, '{}_segmentation_id'.format(self.case_name))
213 domain = self.orig_cloud.get_domain(
214 name_or_id=self.orig_cloud.auth.get(
215 "project_domain_name", "Default"))
216 project = self.orig_cloud.get_project(
217 self.cloud.auth['project_name'],
219 self.network = self.orig_cloud.create_network(
220 '{}-net_{}'.format(self.case_name, self.guid),
221 provider=provider, project_id=project.id,
222 shared=self.shared_network)
223 self.__logger.debug("network: %s", self.network)
225 self.subnet = self.cloud.create_subnet(
227 subnet_name='{}-subnet_{}'.format(self.case_name, self.guid),
229 config.CONF, '{}_private_subnet_cidr'.format(self.case_name),
232 dns_nameservers=[env.get('NAMESERVER')])
233 self.__logger.debug("subnet: %s", self.subnet)
235 self.router = self.cloud.create_router(
236 name='{}-router_{}'.format(self.case_name, self.guid),
237 ext_gateway_net_id=self.ext_net.id)
238 self.__logger.debug("router: %s", self.router)
239 self.cloud.add_router_interface(self.router, subnet_id=self.subnet.id)
241 def run(self, **kwargs):
242 status = testcase.TestCase.EX_RUN_ERROR
245 self.start_time = time.time()
246 self.create_network_resources()
248 status = testcase.TestCase.EX_OK
249 except Exception: # pylint: disable=broad-except
250 self.__logger.exception('Cannot run %s', self.case_name)
252 self.stop_time = time.time()
260 self.cloud.remove_router_interface(
261 self.router, self.subnet.id)
262 self.cloud.delete_router(self.router.id)
264 self.cloud.delete_subnet(self.subnet.id)
266 self.cloud.delete_network(self.network.id)
267 except Exception: # pylint: disable=broad-except
268 self.__logger.exception("cannot clean all resources")
271 class TenantNetwork2(TenantNetwork1):
272 """Create a tenant network (scenario2)
274 It creates new user/project before creating and configuring all tenant
275 network resources required by a testcase (subnet, network and router).
277 It ensures that all testcases inheriting from TenantNetwork2 could work
278 without network specific configurations (or at least read the same config
282 __logger = logging.getLogger(__name__)
284 def __init__(self, **kwargs):
285 if "case_name" not in kwargs:
286 kwargs["case_name"] = 'tenantnetwork2'
287 super(TenantNetwork2, self).__init__(**kwargs)
290 self.project = NewProject(
291 self.cloud, self.case_name, self.guid)
292 self.project.create()
293 self.cloud = self.project.cloud
294 except Exception: # pylint: disable=broad-except
295 self.__logger.exception("Cannot create user or project")
301 super(TenantNetwork2, self).clean()
304 except Exception: # pylint: disable=broad-except
305 self.__logger.exception("Cannot clean all resources")