348ef7d9273103776445255daf140f13def0a7c4
[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['clouds']['envvars']['username'] = self.user.name
90         osconfig.cloud_config['clouds']['envvars']['password'] = self.password
91         self.__logger.debug("cloud_config %s", osconfig.cloud_config)
92         self.cloud = shade.OpenStackCloud(
93             cloud_config=osconfig.get_one_cloud())
94         self.__logger.debug("new cloud %s", self.cloud.auth)
95
96     def clean(self):
97         """Remove projects/users"""
98         try:
99             assert self.orig_cloud
100             if self.user:
101                 self.orig_cloud.delete_user(self.user.id)
102             if self.project:
103                 self.orig_cloud.delete_project(self.project.id)
104             if self.role:
105                 self.orig_cloud.delete_role(self.role.id)
106         except Exception:  # pylint: disable=broad-except
107             self.__logger.exception("Cannot clean all ressources")
108
109
110 class TenantNetwork1(testcase.TestCase):
111     # pylint: disable=too-many-instance-attributes
112     """Create a tenant network (scenario1)
113
114     It creates and configures all tenant network ressources required by
115     advanced testcases (subnet, network and router).
116
117     It ensures that all testcases inheriting from TenantNetwork1 could work
118     without network specific configurations (or at least read the same config
119     data).
120     """
121
122     __logger = logging.getLogger(__name__)
123     cidr = '192.168.0.0/24'
124     shared_network = False
125
126     def __init__(self, **kwargs):
127         if "case_name" not in kwargs:
128             kwargs["case_name"] = 'tenantnetwork1'
129         super(TenantNetwork1, self).__init__(**kwargs)
130         self.res_dir = os.path.join(
131             getattr(config.CONF, 'dir_results'), self.case_name)
132         try:
133             cloud_config = os_client_config.get_config()
134             self.cloud = shade.OpenStackCloud(cloud_config=cloud_config)
135         except Exception:  # pylint: disable=broad-except
136             self.cloud = None
137             self.ext_net = None
138             self.__logger.exception("Cannot connect to Cloud")
139         try:
140             self.ext_net = self.get_external_network(self.cloud)
141         except Exception:  # pylint: disable=broad-except
142             self.__logger.exception("Cannot get the external network")
143         self.guid = str(uuid.uuid4())
144         self.network = None
145         self.subnet = None
146         self.router = None
147
148     @staticmethod
149     def get_external_network(cloud):
150         """
151         Returns the configured external network name or
152         the first retrieved external network name
153         """
154         assert cloud
155         if env.get("EXTERNAL_NETWORK"):
156             network = cloud.get_network(
157                 env.get("EXTERNAL_NETWORK"), {"router:external": True})
158             if network:
159                 return network
160         networks = cloud.list_networks({"router:external": True})
161         if networks:
162             return networks[0]
163         return None
164
165     def _create_network_ressources(self):
166         assert self.cloud
167         assert self.ext_net
168         provider = {}
169         if hasattr(config.CONF, '{}_network_type'.format(self.case_name)):
170             provider["network_type"] = getattr(
171                 config.CONF, '{}_network_type'.format(self.case_name))
172         if hasattr(config.CONF, '{}_physical_network'.format(self.case_name)):
173             provider["physical_network"] = getattr(
174                 config.CONF, '{}_physical_network'.format(self.case_name))
175         if hasattr(config.CONF, '{}_segmentation_id'.format(self.case_name)):
176             provider["segmentation_id"] = getattr(
177                 config.CONF, '{}_segmentation_id'.format(self.case_name))
178         self.network = self.cloud.create_network(
179             '{}-net_{}'.format(self.case_name, self.guid),
180             provider=provider,
181             shared=self.shared_network)
182         self.__logger.debug("network: %s", self.network)
183
184         self.subnet = self.cloud.create_subnet(
185             self.network.id,
186             subnet_name='{}-subnet_{}'.format(self.case_name, self.guid),
187             cidr=getattr(
188                 config.CONF, '{}_private_subnet_cidr'.format(self.case_name),
189                 self.cidr),
190             enable_dhcp=True,
191             dns_nameservers=[env.get('NAMESERVER')])
192         self.__logger.debug("subnet: %s", self.subnet)
193
194         self.router = self.cloud.create_router(
195             name='{}-router_{}'.format(self.case_name, self.guid),
196             ext_gateway_net_id=self.ext_net.id)
197         self.__logger.debug("router: %s", self.router)
198         self.cloud.add_router_interface(self.router, subnet_id=self.subnet.id)
199
200     def run(self, **kwargs):
201         status = testcase.TestCase.EX_RUN_ERROR
202         try:
203             assert self.cloud
204             self.start_time = time.time()
205             self._create_network_ressources()
206             self.result = 100
207             status = testcase.TestCase.EX_OK
208         except Exception:  # pylint: disable=broad-except
209             self.__logger.exception('Cannot run %s', self.case_name)
210         finally:
211             self.stop_time = time.time()
212         return status
213
214     def clean(self):
215         try:
216             assert self.cloud
217             if self.router:
218                 if self.subnet:
219                     self.cloud.remove_router_interface(
220                         self.router, self.subnet.id)
221                 self.cloud.delete_router(self.router.id)
222             if self.subnet:
223                 self.cloud.delete_subnet(self.subnet.id)
224             if self.network:
225                 self.cloud.delete_network(self.network.id)
226         except Exception:  # pylint: disable=broad-except
227             self.__logger.exception("cannot clean all ressources")
228
229
230 class TenantNetwork2(TenantNetwork1):
231     """Create a tenant network (scenario2)
232
233     It creates new user/project before creating and configuring all tenant
234     network ressources required by a testcase (subnet, network and router).
235
236     It ensures that all testcases inheriting from TenantNetwork2 could work
237     without network specific configurations (or at least read the same config
238     data).
239     """
240
241     __logger = logging.getLogger(__name__)
242
243     def __init__(self, **kwargs):
244         if "case_name" not in kwargs:
245             kwargs["case_name"] = 'tenantnetwork2'
246         super(TenantNetwork2, self).__init__(**kwargs)
247         try:
248             assert self.cloud
249             self.project = NewProject(
250                 self.cloud, self.case_name, self.guid)
251             self.project.create()
252             self.cloud = self.project.cloud
253         except Exception:  # pylint: disable=broad-except
254             self.__logger.exception("Cannot create user or project")
255             self.cloud = None
256             self.project = None
257
258     def clean(self):
259         try:
260             super(TenantNetwork2, self).clean()
261             assert self.project
262             self.project.clean()
263         except Exception:  # pylint: disable=broad-except
264             self.__logger.exception("Cannot clean all ressources")