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 except Exception: # pylint: disable=broad-except
110 self.__logger.exception("Cannot clean all resources")
113 class TenantNetwork1(testcase.TestCase):
114 # pylint: disable=too-many-instance-attributes
115 """Create a tenant network (scenario1)
117 It creates and configures all tenant network resources required by
118 advanced testcases (subnet, network and router).
120 It ensures that all testcases inheriting from TenantNetwork1 could work
121 without network specific configurations (or at least read the same config
125 __logger = logging.getLogger(__name__)
126 cidr = '192.168.120.0/24'
127 shared_network = False
129 def __init__(self, **kwargs):
130 if "case_name" not in kwargs:
131 kwargs["case_name"] = 'tenantnetwork1'
132 super(TenantNetwork1, self).__init__(**kwargs)
133 self.res_dir = os.path.join(
134 getattr(config.CONF, 'dir_results'), self.case_name)
136 cloud_config = os_client_config.get_config()
137 self.cloud = self.orig_cloud = shade.OpenStackCloud(
138 cloud_config=cloud_config)
139 except Exception: # pylint: disable=broad-except
140 self.cloud = self.orig_cloud = None
142 self.__logger.exception("Cannot connect to Cloud")
144 self.ext_net = self.get_external_network(self.cloud)
145 except Exception: # pylint: disable=broad-except
146 self.__logger.exception("Cannot get the external network")
147 self.guid = str(uuid.uuid4())
153 def get_external_network(cloud):
155 Return the configured external network name or
156 the first retrieved external network name
159 if env.get("EXTERNAL_NETWORK"):
160 network = cloud.get_network(
161 env.get("EXTERNAL_NETWORK"), {"router:external": True})
164 networks = cloud.list_networks({"router:external": True})
170 def get_default_role(cloud, member="Member"):
171 """Get the default role
173 It also tests the role in lowercase to avoid possible conflicts.
175 role = cloud.get_role(member)
177 role = cloud.get_role(member.lower())
181 def get_public_auth_url(cloud):
182 """Get Keystone public endpoint"""
183 keystone_id = cloud.search_services('keystone')[0].id
184 endpoint = cloud.search_endpoints(
185 filters={'interface': 'public',
186 'service_id': keystone_id})[0].url
189 def create_network_resources(self):
190 """Create all tenant network resources
192 It creates a router which gateway is the external network detected.
193 The new subnet is attached to that router.
195 Raises: expection on error
200 if hasattr(config.CONF, '{}_network_type'.format(self.case_name)):
201 provider["network_type"] = getattr(
202 config.CONF, '{}_network_type'.format(self.case_name))
203 if hasattr(config.CONF, '{}_physical_network'.format(self.case_name)):
204 provider["physical_network"] = getattr(
205 config.CONF, '{}_physical_network'.format(self.case_name))
206 if hasattr(config.CONF, '{}_segmentation_id'.format(self.case_name)):
207 provider["segmentation_id"] = getattr(
208 config.CONF, '{}_segmentation_id'.format(self.case_name))
209 domain = self.orig_cloud.get_domain(
210 name_or_id=self.orig_cloud.auth.get(
211 "project_domain_name", "Default"))
212 project = self.orig_cloud.get_project(
213 self.cloud.auth['project_name'],
215 self.network = self.orig_cloud.create_network(
216 '{}-net_{}'.format(self.case_name, self.guid),
217 provider=provider, project_id=project.id,
218 shared=self.shared_network)
219 self.__logger.debug("network: %s", self.network)
221 self.subnet = self.cloud.create_subnet(
223 subnet_name='{}-subnet_{}'.format(self.case_name, self.guid),
225 config.CONF, '{}_private_subnet_cidr'.format(self.case_name),
228 dns_nameservers=[env.get('NAMESERVER')])
229 self.__logger.debug("subnet: %s", self.subnet)
231 self.router = self.cloud.create_router(
232 name='{}-router_{}'.format(self.case_name, self.guid),
233 ext_gateway_net_id=self.ext_net.id)
234 self.__logger.debug("router: %s", self.router)
235 self.cloud.add_router_interface(self.router, subnet_id=self.subnet.id)
237 def run(self, **kwargs):
238 status = testcase.TestCase.EX_RUN_ERROR
241 self.start_time = time.time()
242 self.create_network_resources()
244 status = testcase.TestCase.EX_OK
245 except Exception: # pylint: disable=broad-except
246 self.__logger.exception('Cannot run %s', self.case_name)
248 self.stop_time = time.time()
256 self.cloud.remove_router_interface(
257 self.router, self.subnet.id)
258 self.cloud.delete_router(self.router.id)
260 self.cloud.delete_subnet(self.subnet.id)
262 self.cloud.delete_network(self.network.id)
263 except Exception: # pylint: disable=broad-except
264 self.__logger.exception("cannot clean all resources")
267 class TenantNetwork2(TenantNetwork1):
268 """Create a tenant network (scenario2)
270 It creates new user/project before creating and configuring all tenant
271 network resources required by a testcase (subnet, network and router).
273 It ensures that all testcases inheriting from TenantNetwork2 could work
274 without network specific configurations (or at least read the same config
278 __logger = logging.getLogger(__name__)
280 def __init__(self, **kwargs):
281 if "case_name" not in kwargs:
282 kwargs["case_name"] = 'tenantnetwork2'
283 super(TenantNetwork2, self).__init__(**kwargs)
286 self.project = NewProject(
287 self.cloud, self.case_name, self.guid)
288 self.project.create()
289 self.cloud = self.project.cloud
290 except Exception: # pylint: disable=broad-except
291 self.__logger.exception("Cannot create user or project")
297 super(TenantNetwork2, self).clean()
300 except Exception: # pylint: disable=broad-except
301 self.__logger.exception("Cannot clean all resources")