blob: 62edd1033afe0d09ff43799f8b4bcf1c5751b39d [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
14
15from tempest import clients
16from tempest.common.utils import data_utils
Matthew Treinishcb09bbb2014-01-29 18:20:25 +000017from tempest import config
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030018from tempest import exceptions as exc
19from tempest import test
20
Matthew Treinishcb09bbb2014-01-29 18:20:25 +000021CONF = config.CONF
22
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030023
Adam Gandelman3e8f7962014-06-25 13:18:29 -070024# NOTE(adam_g): The baremetal API tests exercise operations such as enroll
25# node, power on, power off, etc. Testing against real drivers (ie, IPMI)
26# will require passing driver-specific data to Tempest (addresses,
27# credentials, etc). Until then, only support testing against the fake driver,
28# which has no external dependencies.
29SUPPORTED_DRIVERS = ['fake']
30
31
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030032def creates(resource):
33 """Decorator that adds resources to the appropriate cleanup list."""
34
35 def decorator(f):
36 @functools.wraps(f)
37 def wrapper(cls, *args, **kwargs):
Mh Raiesa9bb79d2014-04-17 16:20:17 +053038 resp, body = f(cls, *args, **kwargs)
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030039
40 if 'uuid' in body:
41 cls.created_objects[resource].add(body['uuid'])
42
Mh Raiesa9bb79d2014-04-17 16:20:17 +053043 return resp, body
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030044 return wrapper
45 return decorator
46
47
48class BaseBaremetalTest(test.BaseTestCase):
49 """Base class for Baremetal API tests."""
50
51 @classmethod
52 def setUpClass(cls):
53 super(BaseBaremetalTest, cls).setUpClass()
54
Matthew Treinishcb09bbb2014-01-29 18:20:25 +000055 if not CONF.service_available.ironic:
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030056 skip_msg = ('%s skipped as Ironic is not available' % cls.__name__)
57 raise cls.skipException(skip_msg)
58
Adam Gandelman3e8f7962014-06-25 13:18:29 -070059 if CONF.baremetal.driver not in SUPPORTED_DRIVERS:
60 skip_msg = ('%s skipped as Ironic driver %s is not supported for '
61 'testing.' %
62 (cls.__name__, CONF.baremetal.driver))
63 raise cls.skipException(skip_msg)
64 cls.driver = CONF.baremetal.driver
65
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030066 mgr = clients.AdminManager()
67 cls.client = mgr.baremetal_client
Mh Raiesf8ecf232014-04-17 12:43:55 +053068 cls.power_timeout = CONF.baremetal.power_timeout
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030069 cls.created_objects = {'chassis': set(),
70 'port': set(),
71 'node': set()}
72
73 @classmethod
74 def tearDownClass(cls):
75 """Ensure that all created objects get destroyed."""
76
77 try:
78 for resource, uuids in cls.created_objects.iteritems():
79 delete_method = getattr(cls.client, 'delete_%s' % resource)
80 for u in uuids:
81 delete_method(u, ignore_errors=exc.NotFound)
82 finally:
83 super(BaseBaremetalTest, cls).tearDownClass()
84
85 @classmethod
86 @creates('chassis')
87 def create_chassis(cls, description=None, expect_errors=False):
88 """
89 Wrapper utility for creating test chassis.
90
91 :param description: A description of the chassis. if not supplied,
92 a random value will be generated.
93 :return: Created chassis.
94
95 """
96 description = description or data_utils.rand_name('test-chassis-')
97 resp, body = cls.client.create_chassis(description=description)
Mh Raiesa9bb79d2014-04-17 16:20:17 +053098 return resp, body
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +030099
100 @classmethod
101 @creates('node')
102 def create_node(cls, chassis_id, cpu_arch='x86', cpu_num=8, storage=1024,
Adam Gandelman3e8f7962014-06-25 13:18:29 -0700103 memory=4096):
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300104 """
105 Wrapper utility for creating test baremetal nodes.
106
107 :param cpu_arch: CPU architecture of the node. Default: x86.
108 :param cpu_num: Number of CPUs. Default: 8.
109 :param storage: Disk size. Default: 1024.
110 :param memory: Available RAM. Default: 4096.
111 :return: Created node.
112
113 """
114 resp, body = cls.client.create_node(chassis_id, cpu_arch=cpu_arch,
115 cpu_num=cpu_num, storage=storage,
Adam Gandelman3e8f7962014-06-25 13:18:29 -0700116 memory=memory, driver=cls.driver)
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300117
Mh Raiesa9bb79d2014-04-17 16:20:17 +0530118 return resp, body
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300119
120 @classmethod
121 @creates('port')
Sergey Nikitin0d43eb52014-02-03 14:50:02 +0400122 def create_port(cls, node_id, address, extra=None, uuid=None):
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300123 """
124 Wrapper utility for creating test ports.
125
Sergey Nikitin0d43eb52014-02-03 14:50:02 +0400126 :param address: MAC address of the port.
127 :param extra: Meta data of the port. If not supplied, an empty
128 dictionary will be created.
129 :param uuid: UUID of the port.
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300130 :return: Created port.
131
132 """
Sergey Nikitin0d43eb52014-02-03 14:50:02 +0400133 extra = extra or {}
134 resp, body = cls.client.create_port(address=address, node_id=node_id,
135 extra=extra, uuid=uuid)
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300136
Mh Raiesa9bb79d2014-04-17 16:20:17 +0530137 return resp, body
Roman Prykhodchenko62b1ed12013-10-16 21:51:47 +0300138
139 @classmethod
140 def delete_chassis(cls, chassis_id):
141 """
142 Deletes a chassis having the specified UUID.
143
144 :param uuid: The unique identifier of the chassis.
145 :return: Server response.
146
147 """
148
149 resp, body = cls.client.delete_chassis(chassis_id)
150
151 if chassis_id in cls.created_objects['chassis']:
152 cls.created_objects['chassis'].remove(chassis_id)
153
154 return resp
155
156 @classmethod
157 def delete_node(cls, node_id):
158 """
159 Deletes a node having the specified UUID.
160
161 :param uuid: The unique identifier of the node.
162 :return: Server response.
163
164 """
165
166 resp, body = cls.client.delete_node(node_id)
167
168 if node_id in cls.created_objects['node']:
169 cls.created_objects['node'].remove(node_id)
170
171 return resp
172
173 @classmethod
174 def delete_port(cls, port_id):
175 """
176 Deletes a port having the specified UUID.
177
178 :param uuid: The unique identifier of the port.
179 :return: Server response.
180
181 """
182
183 resp, body = cls.client.delete_port(port_id)
184
185 if port_id in cls.created_objects['port']:
186 cls.created_objects['port'].remove(port_id)
187
188 return resp
Sergey Nikitin0d43eb52014-02-03 14:50:02 +0400189
190 def validate_self_link(self, resource, uuid, link):
191 """Check whether the given self link formatted correctly."""
192 expected_link = "{base}/{pref}/{res}/{uuid}".format(
193 base=self.client.base_url,
194 pref=self.client.uri_prefix,
195 res=resource,
196 uuid=uuid)
197 self.assertEqual(expected_link, link)