Typos (ressources)
[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, 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 = shade.OpenStackCloud(cloud_config=cloud_config)
138         except Exception:  # pylint: disable=broad-except
139             self.cloud = None
140             self.ext_net = None
141             self.__logger.exception("Cannot connect to Cloud")
142         try:
143             self.ext_net = self.get_external_network(self.cloud)
144         except Exception:  # pylint: disable=broad-except
145             self.__logger.exception("Cannot get the external network")
146         self.guid = str(uuid.uuid4())
147         self.network = None
148         self.subnet = None
149         self.router = None
150
151     @staticmethod
152     def get_external_network(cloud):
153         """
154         Return the configured external network name or
155         the first retrieved external network name
156         """
157         assert cloud
158         if env.get("EXTERNAL_NETWORK"):
159             network = cloud.get_network(
160                 env.get("EXTERNAL_NETWORK"), {"router:external": True})
161             if network:
162                 return network
163         networks = cloud.list_networks({"router:external": True})
164         if networks:
165             return networks[0]
166         return None
167
168     @staticmethod
169     def get_default_role(cloud, member="Member"):
170         """Get the default role
171
172         It also tests the role in lowercase to avoid possible conflicts.
173         """
174         role = cloud.get_role(member)
175         if not role:
176             role = cloud.get_role(member.lower())
177         return role
178
179     @staticmethod
180     def get_public_auth_url(cloud):
181         """Get Keystone public endpoint"""
182         keystone_id = cloud.search_services('keystone')[0].id
183         endpoint = cloud.search_endpoints(
184             filters={'interface': 'public',
185                      'service_id': keystone_id})[0].url
186         return endpoint
187
188     def create_network_resources(self):
189         """Create all tenant network resources
190
191         It creates a router which gateway is the external network detected.
192         The new subnet is attached to that router.
193
194         Raises: expection on error
195         """
196         assert self.cloud
197         assert self.ext_net
198         provider = {}
199         if hasattr(config.CONF, '{}_network_type'.format(self.case_name)):
200             provider["network_type"] = getattr(
201                 config.CONF, '{}_network_type'.format(self.case_name))
202         if hasattr(config.CONF, '{}_physical_network'.format(self.case_name)):
203             provider["physical_network"] = getattr(
204                 config.CONF, '{}_physical_network'.format(self.case_name))
205         if hasattr(config.CONF, '{}_segmentation_id'.format(self.case_name)):
206             provider["segmentation_id"] = getattr(
207                 config.CONF, '{}_segmentation_id'.format(self.case_name))
208         self.network = self.cloud.create_network(
209             '{}-net_{}'.format(self.case_name, self.guid),
210             provider=provider,
211             shared=self.shared_network)
212         self.__logger.debug("network: %s", self.network)
213
214         self.subnet = self.cloud.create_subnet(
215             self.network.id,
216             subnet_name='{}-subnet_{}'.format(self.case_name, self.guid),
217             cidr=getattr(
218                 config.CONF, '{}_private_subnet_cidr'.format(self.case_name),
219                 self.cidr),
220             enable_dhcp=True,
221             dns_nameservers=[env.get('NAMESERVER')])
222         self.__logger.debug("subnet: %s", self.subnet)
223
224         self.router = self.cloud.create_router(
225             name='{}-router_{}'.format(self.case_name, self.guid),
226             ext_gateway_net_id=self.ext_net.id)
227         self.__logger.debug("router: %s", self.router)
228         self.cloud.add_router_interface(self.router, subnet_id=self.subnet.id)
229
230     def run(self, **kwargs):
231         status = testcase.TestCase.EX_RUN_ERROR
232         try:
233             assert self.cloud
234             self.start_time = time.time()
235             self.create_network_resources()
236             self.result = 100
237             status = testcase.TestCase.EX_OK
238         except Exception:  # pylint: disable=broad-except
239             self.__logger.exception('Cannot run %s', self.case_name)
240         finally:
241             self.stop_time = time.time()
242         return status
243
244     def clean(self):
245         try:
246             assert self.cloud
247             if self.router:
248                 if self.subnet:
249                     self.cloud.remove_router_interface(
250                         self.router, self.subnet.id)
251                 self.cloud.delete_router(self.router.id)
252             if self.subnet:
253                 self.cloud.delete_subnet(self.subnet.id)
254             if self.network:
255                 self.cloud.delete_network(self.network.id)
256         except Exception:  # pylint: disable=broad-except
257             self.__logger.exception("cannot clean all resources")
258
259
260 class TenantNetwork2(TenantNetwork1):
261     """Create a tenant network (scenario2)
262
263     It creates new user/project before creating and configuring all tenant
264     network resources required by a testcase (subnet, network and router).
265
266     It ensures that all testcases inheriting from TenantNetwork2 could work
267     without network specific configurations (or at least read the same config
268     data).
269     """
270
271     __logger = logging.getLogger(__name__)
272
273     def __init__(self, **kwargs):
274         if "case_name" not in kwargs:
275             kwargs["case_name"] = 'tenantnetwork2'
276         super(TenantNetwork2, self).__init__(**kwargs)
277         try:
278             assert self.cloud
279             self.project = NewProject(
280                 self.cloud, self.case_name, self.guid)
281             self.project.create()
282             self.cloud = self.project.cloud
283         except Exception:  # pylint: disable=broad-except
284             self.__logger.exception("Cannot create user or project")
285             self.cloud = None
286             self.project = None
287
288     def clean(self):
289         try:
290             super(TenantNetwork2, self).clean()
291             assert self.project
292             self.project.clean()
293         except Exception:  # pylint: disable=broad-except
294             self.__logger.exception("Cannot clean all resources")