blob: 2834b2bb5441a44a689f7c9721dc336bd24712f8 [file] [log] [blame]
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +03001# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import functools
Matthew Treinish01472ff2015-02-20 17:26:52 -050014
15from tempest_lib.common.utils import data_utils
Masayuki Igawabfa07602015-01-20 18:47:17 +090016from tempest_lib import exceptions as lib_exc
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030017
18from tempest import clients
Matthew Treinishcb09bbb2014-01-29 18:20:25 +000019from tempest import config
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030020from tempest import test
21
Matthew Treinishcb09bbb2014-01-29 18:20:25 +000022CONF = config.CONF
23
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030024
Adam Gandelman3e8f7962014-06-25 13:18:29 -070025# NOTE(adam_g): The baremetal API tests exercise operations such as enroll
26# node, power on, power off, etc. Testing against real drivers (ie, IPMI)
27# will require passing driver-specific data to Tempest (addresses,
28# credentials, etc). Until then, only support testing against the fake driver,
29# which has no external dependencies.
30SUPPORTED_DRIVERS = ['fake']
31
Jim Rollenhagen92420f02014-09-19 12:04:07 -070032# NOTE(jroll): resources must be deleted in a specific order, this list
33# defines the resource types to clean up, and the correct order.
34RESOURCE_TYPES = ['port', 'node', 'chassis']
35
Adam Gandelman3e8f7962014-06-25 13:18:29 -070036
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030037def creates(resource):
38 """Decorator that adds resources to the appropriate cleanup list."""
39
40 def decorator(f):
41 @functools.wraps(f)
42 def wrapper(cls, *args, **kwargs):
Mh Raiesa9bb79d2014-04-17 16:20:17 +053043 resp, body = f(cls, *args, **kwargs)
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030044
45 if 'uuid' in body:
46 cls.created_objects[resource].add(body['uuid'])
47
Mh Raiesa9bb79d2014-04-17 16:20:17 +053048 return resp, body
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030049 return wrapper
50 return decorator
51
52
53class BaseBaremetalTest(test.BaseTestCase):
54 """Base class for Baremetal API tests."""
55
56 @classmethod
Rohan Kanade7ed42f52015-02-03 13:00:29 +053057 def skip_checks(cls):
58 super(BaseBaremetalTest, cls).skip_checks()
Matthew Treinishcb09bbb2014-01-29 18:20:25 +000059 if not CONF.service_available.ironic:
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030060 skip_msg = ('%s skipped as Ironic is not available' % cls.__name__)
61 raise cls.skipException(skip_msg)
62
Adam Gandelman3e8f7962014-06-25 13:18:29 -070063 if CONF.baremetal.driver not in SUPPORTED_DRIVERS:
64 skip_msg = ('%s skipped as Ironic driver %s is not supported for '
65 'testing.' %
66 (cls.__name__, CONF.baremetal.driver))
67 raise cls.skipException(skip_msg)
Adam Gandelman3e8f7962014-06-25 13:18:29 -070068
Rohan Kanade7ed42f52015-02-03 13:00:29 +053069 @classmethod
70 def setup_credentials(cls):
71 super(BaseBaremetalTest, cls).setup_credentials()
72 cls.mgr = clients.AdminManager()
73
74 @classmethod
75 def setup_clients(cls):
76 super(BaseBaremetalTest, cls).setup_clients()
77 cls.client = cls.mgr.baremetal_client
78
79 @classmethod
80 def resource_setup(cls):
81 super(BaseBaremetalTest, cls).resource_setup()
82
83 cls.driver = CONF.baremetal.driver
Mh Raiesf8ecf232014-04-17 12:43:55 +053084 cls.power_timeout = CONF.baremetal.power_timeout
Jim Rollenhagen92420f02014-09-19 12:04:07 -070085 cls.created_objects = {}
86 for resource in RESOURCE_TYPES:
87 cls.created_objects[resource] = set()
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030088
89 @classmethod
Andrea Frittoliba240c32014-09-15 13:14:53 +010090 def resource_cleanup(cls):
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030091 """Ensure that all created objects get destroyed."""
92
93 try:
Jim Rollenhagen92420f02014-09-19 12:04:07 -070094 for resource in RESOURCE_TYPES:
95 uuids = cls.created_objects[resource]
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030096 delete_method = getattr(cls.client, 'delete_%s' % resource)
97 for u in uuids:
Masayuki Igawabfa07602015-01-20 18:47:17 +090098 delete_method(u, ignore_errors=lib_exc.NotFound)
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030099 finally:
Andrea Frittoliba240c32014-09-15 13:14:53 +0100100 super(BaseBaremetalTest, cls).resource_cleanup()
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300101
102 @classmethod
103 @creates('chassis')
104 def create_chassis(cls, description=None, expect_errors=False):
105 """
106 Wrapper utility for creating test chassis.
107
108 :param description: A description of the chassis. if not supplied,
109 a random value will be generated.
110 :return: Created chassis.
111
112 """
113 description = description or data_utils.rand_name('test-chassis-')
114 resp, body = cls.client.create_chassis(description=description)
Mh Raiesa9bb79d2014-04-17 16:20:17 +0530115 return resp, body
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300116
117 @classmethod
118 @creates('node')
Adam Gandelman3ea1eb82015-02-18 19:13:25 -0800119 def create_node(cls, chassis_id, cpu_arch='x86', cpus=8, local_gb=10,
120 memory_mb=4096):
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300121 """
122 Wrapper utility for creating test baremetal nodes.
123
124 :param cpu_arch: CPU architecture of the node. Default: x86.
Adam Gandelman3ea1eb82015-02-18 19:13:25 -0800125 :param cpus: Number of CPUs. Default: 8.
126 :param local_gb: Disk size. Default: 10.
127 :param memory_mb: Available RAM. Default: 4096.
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300128 :return: Created node.
129
130 """
131 resp, body = cls.client.create_node(chassis_id, cpu_arch=cpu_arch,
Adam Gandelman3ea1eb82015-02-18 19:13:25 -0800132 cpus=cpus, local_gb=local_gb,
133 memory_mb=memory_mb,
134 driver=cls.driver)
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300135
Mh Raiesa9bb79d2014-04-17 16:20:17 +0530136 return resp, body
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300137
138 @classmethod
139 @creates('port')
Sergey Nikitin0d43eb52014-02-03 14:50:02 +0400140 def create_port(cls, node_id, address, extra=None, uuid=None):
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300141 """
142 Wrapper utility for creating test ports.
143
Sergey Nikitin0d43eb52014-02-03 14:50:02 +0400144 :param address: MAC address of the port.
145 :param extra: Meta data of the port. If not supplied, an empty
146 dictionary will be created.
147 :param uuid: UUID of the port.
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300148 :return: Created port.
149
150 """
Sergey Nikitin0d43eb52014-02-03 14:50:02 +0400151 extra = extra or {}
152 resp, body = cls.client.create_port(address=address, node_id=node_id,
153 extra=extra, uuid=uuid)
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300154
Mh Raiesa9bb79d2014-04-17 16:20:17 +0530155 return resp, body
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300156
157 @classmethod
158 def delete_chassis(cls, chassis_id):
159 """
160 Deletes a chassis having the specified UUID.
161
162 :param uuid: The unique identifier of the chassis.
163 :return: Server response.
164
165 """
166
167 resp, body = cls.client.delete_chassis(chassis_id)
168
169 if chassis_id in cls.created_objects['chassis']:
170 cls.created_objects['chassis'].remove(chassis_id)
171
172 return resp
173
174 @classmethod
175 def delete_node(cls, node_id):
176 """
177 Deletes a node having the specified UUID.
178
179 :param uuid: The unique identifier of the node.
180 :return: Server response.
181
182 """
183
184 resp, body = cls.client.delete_node(node_id)
185
186 if node_id in cls.created_objects['node']:
187 cls.created_objects['node'].remove(node_id)
188
189 return resp
190
191 @classmethod
192 def delete_port(cls, port_id):
193 """
194 Deletes a port having the specified UUID.
195
196 :param uuid: The unique identifier of the port.
197 :return: Server response.
198
199 """
200
201 resp, body = cls.client.delete_port(port_id)
202
203 if port_id in cls.created_objects['port']:
204 cls.created_objects['port'].remove(port_id)
205
206 return resp
Sergey Nikitin0d43eb52014-02-03 14:50:02 +0400207
208 def validate_self_link(self, resource, uuid, link):
209 """Check whether the given self link formatted correctly."""
210 expected_link = "{base}/{pref}/{res}/{uuid}".format(
211 base=self.client.base_url,
212 pref=self.client.uri_prefix,
213 res=resource,
214 uuid=uuid)
215 self.assertEqual(expected_link, link)