Clean the default security group
[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             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")
115
116
117 class TenantNetwork1(testcase.TestCase):
118     # pylint: disable=too-many-instance-attributes
119     """Create a tenant network (scenario1)
120
121     It creates and configures all tenant network resources required by
122     advanced testcases (subnet, network and router).
123
124     It ensures that all testcases inheriting from TenantNetwork1 could work
125     without network specific configurations (or at least read the same config
126     data).
127     """
128
129     __logger = logging.getLogger(__name__)
130     cidr = '192.168.120.0/24'
131     shared_network = False
132
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)
139         try:
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
145             self.ext_net = None
146             self.__logger.exception("Cannot connect to Cloud")
147         try:
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())
152         self.network = None
153         self.subnet = None
154         self.router = None
155
156     @staticmethod
157     def get_external_network(cloud):
158         """
159         Return the configured external network name or
160         the first retrieved external network name
161         """
162         assert cloud
163         if env.get("EXTERNAL_NETWORK"):
164             network = cloud.get_network(
165                 env.get("EXTERNAL_NETWORK"), {"router:external": True})
166             if network:
167                 return network
168         networks = cloud.list_networks({"router:external": True})
169         if networks:
170             return networks[0]
171         return None
172
173     @staticmethod
174     def get_default_role(cloud, member="Member"):
175         """Get the default role
176
177         It also tests the role in lowercase to avoid possible conflicts.
178         """
179         role = cloud.get_role(member)
180         if not role:
181             role = cloud.get_role(member.lower())
182         return role
183
184     @staticmethod
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
191         return endpoint
192
193     def create_network_resources(self):
194         """Create all tenant network resources
195
196         It creates a router which gateway is the external network detected.
197         The new subnet is attached to that router.
198
199         Raises: expection on error
200         """
201         assert self.cloud
202         assert self.ext_net
203         provider = {}
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'],
218             domain_id=domain.id)
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)
224
225         self.subnet = self.cloud.create_subnet(
226             self.network.id,
227             subnet_name='{}-subnet_{}'.format(self.case_name, self.guid),
228             cidr=getattr(
229                 config.CONF, '{}_private_subnet_cidr'.format(self.case_name),
230                 self.cidr),
231             enable_dhcp=True,
232             dns_nameservers=[env.get('NAMESERVER')])
233         self.__logger.debug("subnet: %s", self.subnet)
234
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)
240
241     def run(self, **kwargs):
242         status = testcase.TestCase.EX_RUN_ERROR
243         try:
244             assert self.cloud
245             self.start_time = time.time()
246             self.create_network_resources()
247             self.result = 100
248             status = testcase.TestCase.EX_OK
249         except Exception:  # pylint: disable=broad-except
250             self.__logger.exception('Cannot run %s', self.case_name)
251         finally:
252             self.stop_time = time.time()
253         return status
254
255     def clean(self):
256         try:
257             assert self.cloud
258             if self.router:
259                 if self.subnet:
260                     self.cloud.remove_router_interface(
261                         self.router, self.subnet.id)
262                 self.cloud.delete_router(self.router.id)
263             if self.subnet:
264                 self.cloud.delete_subnet(self.subnet.id)
265             if self.network:
266                 self.cloud.delete_network(self.network.id)
267         except Exception:  # pylint: disable=broad-except
268             self.__logger.exception("cannot clean all resources")
269
270
271 class TenantNetwork2(TenantNetwork1):
272     """Create a tenant network (scenario2)
273
274     It creates new user/project before creating and configuring all tenant
275     network resources required by a testcase (subnet, network and router).
276
277     It ensures that all testcases inheriting from TenantNetwork2 could work
278     without network specific configurations (or at least read the same config
279     data).
280     """
281
282     __logger = logging.getLogger(__name__)
283
284     def __init__(self, **kwargs):
285         if "case_name" not in kwargs:
286             kwargs["case_name"] = 'tenantnetwork2'
287         super(TenantNetwork2, self).__init__(**kwargs)
288         try:
289             assert self.cloud
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")
296             self.cloud = None
297             self.project = None
298
299     def clean(self):
300         try:
301             super(TenantNetwork2, self).clean()
302             assert self.project
303             self.project.clean()
304         except Exception:  # pylint: disable=broad-except
305             self.__logger.exception("Cannot clean all resources")