286aef67e970a26d56e158eda09a1ccfdf21cee7
[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 ressources required by a
13 testcase (including all Functest ones):
14   - TenantNetwork1 selects the user and the project set as env vars
15   - TenantNetwork2 creates a user and project to isolate the same ressources
16
17 This classes could be reused by more complexed scenarios (Single VM)
18 """
19
20 import logging
21 import os
22 import time
23 import uuid
24
25 import os_client_config
26 import shade
27 from xtesting.core import testcase
28
29 from functest.utils import config
30 from functest.utils import env
31
32
33 class NewProject(object):
34     """Ease creating new projects/users"""
35     # pylint: disable=too-many-instance-attributes
36
37     __logger = logging.getLogger(__name__)
38     default_member = "Member"
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
52     def create(self):
53         """Create projects/users"""
54         assert self.orig_cloud
55         assert self.case_name
56         self.password = str(uuid.uuid4())
57         self.domain = self.orig_cloud.get_domain(
58             name_or_id=self.orig_cloud.auth.get(
59                 "project_domain_name", "Default"))
60         self.project = self.orig_cloud.create_project(
61             name='{}-project_{}'.format(self.case_name, self.guid),
62             description="Created by OPNFV Functest: {}".format(
63                 self.case_name),
64             domain_id=self.domain.id)
65         self.__logger.debug("project: %s", self.project)
66         self.user = self.orig_cloud.create_user(
67             name='{}-user_{}'.format(self.case_name, self.guid),
68             password=self.password,
69             domain_id=self.domain.id)
70         self.__logger.debug("user: %s", self.user)
71         try:
72             if self.orig_cloud.get_role(self.default_member):
73                 self.role_name = self.default_member
74             elif self.orig_cloud.get_role(self.default_member.lower()):
75                 self.role_name = self.default_member.lower()
76             else:
77                 raise Exception("Cannot detect {}".format(self.default_member))
78         except Exception:  # pylint: disable=broad-except
79             self.__logger.info("Creating default role %s", self.default_member)
80             self.role = self.orig_cloud.create_role(self.default_member)
81             self.role_name = self.role.name
82             self.__logger.debug("role: %s", self.role)
83         self.orig_cloud.grant_role(
84             self.role_name, user=self.user.id, project=self.project.id,
85             domain=self.domain.id)
86         osconfig = os_client_config.config.OpenStackConfig()
87         osconfig.cloud_config[
88             'clouds']['envvars']['project_name'] = self.project.name
89         osconfig.cloud_config[
90             'clouds']['envvars']['project_id'] = self.project.id
91         osconfig.cloud_config['clouds']['envvars']['username'] = self.user.name
92         osconfig.cloud_config['clouds']['envvars']['password'] = self.password
93         self.__logger.debug("cloud_config %s", osconfig.cloud_config)
94         self.cloud = shade.OpenStackCloud(
95             cloud_config=osconfig.get_one_cloud())
96         self.__logger.debug("new cloud %s", self.cloud.auth)
97
98     def clean(self):
99         """Remove projects/users"""
100         try:
101             assert self.orig_cloud
102             if self.user:
103                 self.orig_cloud.delete_user(self.user.id)
104             if self.project:
105                 self.orig_cloud.delete_project(self.project.id)
106             if self.role:
107                 self.orig_cloud.delete_role(self.role.id)
108         except Exception:  # pylint: disable=broad-except
109             self.__logger.exception("Cannot clean all ressources")
110
111
112 class TenantNetwork1(testcase.TestCase):
113     # pylint: disable=too-many-instance-attributes
114     """Create a tenant network (scenario1)
115
116     It creates and configures all tenant network ressources required by
117     advanced testcases (subnet, network and router).
118
119     It ensures that all testcases inheriting from TenantNetwork1 could work
120     without network specific configurations (or at least read the same config
121     data).
122     """
123
124     __logger = logging.getLogger(__name__)
125     cidr = '192.168.0.0/24'
126     shared_network = False
127
128     def __init__(self, **kwargs):
129         if "case_name" not in kwargs:
130             kwargs["case_name"] = 'tenantnetwork1'
131         super(TenantNetwork1, self).__init__(**kwargs)
132         self.res_dir = os.path.join(
133             getattr(config.CONF, 'dir_results'), self.case_name)
134         try:
135             cloud_config = os_client_config.get_config()
136             self.cloud = shade.OpenStackCloud(cloud_config=cloud_config)
137         except Exception:  # pylint: disable=broad-except
138             self.cloud = None
139             self.ext_net = None
140             self.__logger.exception("Cannot connect to Cloud")
141         try:
142             self.ext_net = self.get_external_network(self.cloud)
143         except Exception:  # pylint: disable=broad-except
144             self.__logger.exception("Cannot get the external network")
145         self.guid = str(uuid.uuid4())
146         self.network = None
147         self.subnet = None
148         self.router = None
149
150     @staticmethod
151     def get_external_network(cloud):
152         """
153         Return the configured external network name or
154         the first retrieved external network name
155         """
156         assert cloud
157         if env.get("EXTERNAL_NETWORK"):
158             network = cloud.get_network(
159                 env.get("EXTERNAL_NETWORK"), {"router:external": True})
160             if network:
161                 return network
162         networks = cloud.list_networks({"router:external": True})
163         if networks:
164             return networks[0]
165         return None
166
167     @staticmethod
168     def get_default_role(cloud, member="Member"):
169         """Get the default role
170
171         It also tests the role in lowercase to avoid possible conflicts.
172         """
173         role = cloud.get_role(member)
174         if not role:
175             role = cloud.get_role(member.lower())
176         return role
177
178     def _create_network_ressources(self):
179         assert self.cloud
180         assert self.ext_net
181         provider = {}
182         if hasattr(config.CONF, '{}_network_type'.format(self.case_name)):
183             provider["network_type"] = getattr(
184                 config.CONF, '{}_network_type'.format(self.case_name))
185         if hasattr(config.CONF, '{}_physical_network'.format(self.case_name)):
186             provider["physical_network"] = getattr(
187                 config.CONF, '{}_physical_network'.format(self.case_name))
188         if hasattr(config.CONF, '{}_segmentation_id'.format(self.case_name)):
189             provider["segmentation_id"] = getattr(
190                 config.CONF, '{}_segmentation_id'.format(self.case_name))
191         self.network = self.cloud.create_network(
192             '{}-net_{}'.format(self.case_name, self.guid),
193             provider=provider,
194             shared=self.shared_network)
195         self.__logger.debug("network: %s", self.network)
196
197         self.subnet = self.cloud.create_subnet(
198             self.network.id,
199             subnet_name='{}-subnet_{}'.format(self.case_name, self.guid),
200             cidr=getattr(
201                 config.CONF, '{}_private_subnet_cidr'.format(self.case_name),
202                 self.cidr),
203             enable_dhcp=True,
204             dns_nameservers=[env.get('NAMESERVER')])
205         self.__logger.debug("subnet: %s", self.subnet)
206
207         self.router = self.cloud.create_router(
208             name='{}-router_{}'.format(self.case_name, self.guid),
209             ext_gateway_net_id=self.ext_net.id)
210         self.__logger.debug("router: %s", self.router)
211         self.cloud.add_router_interface(self.router, subnet_id=self.subnet.id)
212
213     def run(self, **kwargs):
214         status = testcase.TestCase.EX_RUN_ERROR
215         try:
216             assert self.cloud
217             self.start_time = time.time()
218             self._create_network_ressources()
219             self.result = 100
220             status = testcase.TestCase.EX_OK
221         except Exception:  # pylint: disable=broad-except
222             self.__logger.exception('Cannot run %s', self.case_name)
223         finally:
224             self.stop_time = time.time()
225         return status
226
227     def clean(self):
228         try:
229             assert self.cloud
230             if self.router:
231                 if self.subnet:
232                     self.cloud.remove_router_interface(
233                         self.router, self.subnet.id)
234                 self.cloud.delete_router(self.router.id)
235             if self.subnet:
236                 self.cloud.delete_subnet(self.subnet.id)
237             if self.network:
238                 self.cloud.delete_network(self.network.id)
239         except Exception:  # pylint: disable=broad-except
240             self.__logger.exception("cannot clean all ressources")
241
242
243 class TenantNetwork2(TenantNetwork1):
244     """Create a tenant network (scenario2)
245
246     It creates new user/project before creating and configuring all tenant
247     network ressources required by a testcase (subnet, network and router).
248
249     It ensures that all testcases inheriting from TenantNetwork2 could work
250     without network specific configurations (or at least read the same config
251     data).
252     """
253
254     __logger = logging.getLogger(__name__)
255
256     def __init__(self, **kwargs):
257         if "case_name" not in kwargs:
258             kwargs["case_name"] = 'tenantnetwork2'
259         super(TenantNetwork2, self).__init__(**kwargs)
260         try:
261             assert self.cloud
262             self.project = NewProject(
263                 self.cloud, self.case_name, self.guid)
264             self.project.create()
265             self.cloud = self.project.cloud
266         except Exception:  # pylint: disable=broad-except
267             self.__logger.exception("Cannot create user or project")
268             self.cloud = None
269             self.project = None
270
271     def clean(self):
272         try:
273             super(TenantNetwork2, self).clean()
274             assert self.project
275             self.project.clean()
276         except Exception:  # pylint: disable=broad-except
277             self.__logger.exception("Cannot clean all ressources")