60b747bd20bb763d3ad7f8019f3d831a0615e9bb
[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         Returns 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     def _create_network_ressources(self):
168         assert self.cloud
169         assert self.ext_net
170         provider = {}
171         if hasattr(config.CONF, '{}_network_type'.format(self.case_name)):
172             provider["network_type"] = getattr(
173                 config.CONF, '{}_network_type'.format(self.case_name))
174         if hasattr(config.CONF, '{}_physical_network'.format(self.case_name)):
175             provider["physical_network"] = getattr(
176                 config.CONF, '{}_physical_network'.format(self.case_name))
177         if hasattr(config.CONF, '{}_segmentation_id'.format(self.case_name)):
178             provider["segmentation_id"] = getattr(
179                 config.CONF, '{}_segmentation_id'.format(self.case_name))
180         self.network = self.cloud.create_network(
181             '{}-net_{}'.format(self.case_name, self.guid),
182             provider=provider,
183             shared=self.shared_network)
184         self.__logger.debug("network: %s", self.network)
185
186         self.subnet = self.cloud.create_subnet(
187             self.network.id,
188             subnet_name='{}-subnet_{}'.format(self.case_name, self.guid),
189             cidr=getattr(
190                 config.CONF, '{}_private_subnet_cidr'.format(self.case_name),
191                 self.cidr),
192             enable_dhcp=True,
193             dns_nameservers=[env.get('NAMESERVER')])
194         self.__logger.debug("subnet: %s", self.subnet)
195
196         self.router = self.cloud.create_router(
197             name='{}-router_{}'.format(self.case_name, self.guid),
198             ext_gateway_net_id=self.ext_net.id)
199         self.__logger.debug("router: %s", self.router)
200         self.cloud.add_router_interface(self.router, subnet_id=self.subnet.id)
201
202     def run(self, **kwargs):
203         status = testcase.TestCase.EX_RUN_ERROR
204         try:
205             assert self.cloud
206             self.start_time = time.time()
207             self._create_network_ressources()
208             self.result = 100
209             status = testcase.TestCase.EX_OK
210         except Exception:  # pylint: disable=broad-except
211             self.__logger.exception('Cannot run %s', self.case_name)
212         finally:
213             self.stop_time = time.time()
214         return status
215
216     def clean(self):
217         try:
218             assert self.cloud
219             if self.router:
220                 if self.subnet:
221                     self.cloud.remove_router_interface(
222                         self.router, self.subnet.id)
223                 self.cloud.delete_router(self.router.id)
224             if self.subnet:
225                 self.cloud.delete_subnet(self.subnet.id)
226             if self.network:
227                 self.cloud.delete_network(self.network.id)
228         except Exception:  # pylint: disable=broad-except
229             self.__logger.exception("cannot clean all ressources")
230
231
232 class TenantNetwork2(TenantNetwork1):
233     """Create a tenant network (scenario2)
234
235     It creates new user/project before creating and configuring all tenant
236     network ressources required by a testcase (subnet, network and router).
237
238     It ensures that all testcases inheriting from TenantNetwork2 could work
239     without network specific configurations (or at least read the same config
240     data).
241     """
242
243     __logger = logging.getLogger(__name__)
244
245     def __init__(self, **kwargs):
246         if "case_name" not in kwargs:
247             kwargs["case_name"] = 'tenantnetwork2'
248         super(TenantNetwork2, self).__init__(**kwargs)
249         try:
250             assert self.cloud
251             self.project = NewProject(
252                 self.cloud, self.case_name, self.guid)
253             self.project.create()
254             self.cloud = self.project.cloud
255         except Exception:  # pylint: disable=broad-except
256             self.__logger.exception("Cannot create user or project")
257             self.cloud = None
258             self.project = None
259
260     def clean(self):
261         try:
262             super(TenantNetwork2, self).clean()
263             assert self.project
264             self.project.clean()
265         except Exception:  # pylint: disable=broad-except
266             self.__logger.exception("Cannot clean all ressources")