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