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