Disable test_auto_allocated_topology_rbac in patrole
[functest.git] / functest / core / tenantnetwork.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2018 Orange and others.
4 #
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
9
10 """Ease deploying tenant networks
11
12 It offers a simple way to create all tenant network resources required by a
13 testcase (including all Functest ones):
14
15   - TenantNetwork1 selects the user and the project set as env vars
16   - TenantNetwork2 creates a user and project to isolate the same resources
17
18 This classes could be reused by more complexed scenarios (Single VM)
19 """
20
21 import logging
22 import os
23 import time
24 import uuid
25
26 import os_client_config
27 import shade
28 from xtesting.core import testcase
29
30 from functest.utils import config
31 from functest.utils import env
32
33
34 class NewProject(object):
35     """Ease creating new projects/users"""
36     # pylint: disable=too-many-instance-attributes
37
38     __logger = logging.getLogger(__name__)
39
40     def __init__(self, cloud, case_name, guid):
41         self.cloud = None
42         self.orig_cloud = cloud
43         self.case_name = case_name
44         self.guid = guid
45         self.project = None
46         self.user = None
47         self.password = None
48         self.domain = None
49         self.role = None
50         self.role_name = None
51         self.default_member = env.get('NEW_USER_ROLE')
52
53     def create(self):
54         """Create projects/users"""
55         assert self.orig_cloud
56         assert self.case_name
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(
64                 self.case_name),
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)
72         try:
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()
77             else:
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)
98
99     def clean(self):
100         """Remove projects/users"""
101         try:
102             assert self.orig_cloud
103             if self.user:
104                 self.orig_cloud.delete_user(self.user.id)
105             if self.project:
106                 self.orig_cloud.delete_project(self.project.id)
107             if self.role:
108                 self.orig_cloud.delete_role(self.role.id)
109         except Exception:  # pylint: disable=broad-except
110             self.__logger.exception("Cannot clean all resources")
111
112
113 class TenantNetwork1(testcase.TestCase):
114     # pylint: disable=too-many-instance-attributes
115     """Create a tenant network (scenario1)
116
117     It creates and configures all tenant network resources required by
118     advanced testcases (subnet, network and router).
119
120     It ensures that all testcases inheriting from TenantNetwork1 could work
121     without network specific configurations (or at least read the same config
122     data).
123     """
124
125     __logger = logging.getLogger(__name__)
126     cidr = '192.168.120.0/24'
127     shared_network = False
128
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)
135         try:
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
141             self.ext_net = None
142             self.__logger.exception("Cannot connect to Cloud")
143         try:
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())
148         self.network = None
149         self.subnet = None
150         self.router = None
151
152     @staticmethod
153     def get_external_network(cloud):
154         """
155         Return the configured external network name or
156         the first retrieved external network name
157         """
158         assert cloud
159         if env.get("EXTERNAL_NETWORK"):
160             network = cloud.get_network(
161                 env.get("EXTERNAL_NETWORK"), {"router:external": True})
162             if network:
163                 return network
164         networks = cloud.list_networks({"router:external": True})
165         if networks:
166             return networks[0]
167         return None
168
169     @staticmethod
170     def get_default_role(cloud, member="Member"):
171         """Get the default role
172
173         It also tests the role in lowercase to avoid possible conflicts.
174         """
175         role = cloud.get_role(member)
176         if not role:
177             role = cloud.get_role(member.lower())
178         return role
179
180     @staticmethod
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
187         return endpoint
188
189     def create_network_resources(self):
190         """Create all tenant network resources
191
192         It creates a router which gateway is the external network detected.
193         The new subnet is attached to that router.
194
195         Raises: expection on error
196         """
197         assert self.cloud
198         assert self.ext_net
199         provider = {}
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'],
214             domain_id=domain.id)
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)
220
221         self.subnet = self.cloud.create_subnet(
222             self.network.id,
223             subnet_name='{}-subnet_{}'.format(self.case_name, self.guid),
224             cidr=getattr(
225                 config.CONF, '{}_private_subnet_cidr'.format(self.case_name),
226                 self.cidr),
227             enable_dhcp=True,
228             dns_nameservers=[env.get('NAMESERVER')])
229         self.__logger.debug("subnet: %s", self.subnet)
230
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)
236
237     def run(self, **kwargs):
238         status = testcase.TestCase.EX_RUN_ERROR
239         try:
240             assert self.cloud
241             self.start_time = time.time()
242             self.create_network_resources()
243             self.result = 100
244             status = testcase.TestCase.EX_OK
245         except Exception:  # pylint: disable=broad-except
246             self.__logger.exception('Cannot run %s', self.case_name)
247         finally:
248             self.stop_time = time.time()
249         return status
250
251     def clean(self):
252         try:
253             assert self.cloud
254             if self.router:
255                 if self.subnet:
256                     self.cloud.remove_router_interface(
257                         self.router, self.subnet.id)
258                 self.cloud.delete_router(self.router.id)
259             if self.subnet:
260                 self.cloud.delete_subnet(self.subnet.id)
261             if self.network:
262                 self.cloud.delete_network(self.network.id)
263         except Exception:  # pylint: disable=broad-except
264             self.__logger.exception("cannot clean all resources")
265
266
267 class TenantNetwork2(TenantNetwork1):
268     """Create a tenant network (scenario2)
269
270     It creates new user/project before creating and configuring all tenant
271     network resources required by a testcase (subnet, network and router).
272
273     It ensures that all testcases inheriting from TenantNetwork2 could work
274     without network specific configurations (or at least read the same config
275     data).
276     """
277
278     __logger = logging.getLogger(__name__)
279
280     def __init__(self, **kwargs):
281         if "case_name" not in kwargs:
282             kwargs["case_name"] = 'tenantnetwork2'
283         super(TenantNetwork2, self).__init__(**kwargs)
284         try:
285             assert self.cloud
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")
292             self.cloud = None
293             self.project = None
294
295     def clean(self):
296         try:
297             super(TenantNetwork2, self).clean()
298             assert self.project
299             self.project.clean()
300         except Exception:  # pylint: disable=broad-except
301             self.__logger.exception("Cannot clean all resources")