blob: 0bb806fe2f248acf4417708471a13797d6753fc5 [file] [log] [blame]
Gavin Brebner0f465a32013-03-14 13:26:09 +00001# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2013 Hewlett-Packard Development Company, L.P.
4# All Rights Reserved.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
18import subprocess
19
20import netaddr
21
22from quantumclient.common import exceptions as exc
23from tempest.common.utils.data_utils import rand_name
24from tempest import smoke
25from tempest import test
26
27
28class AttributeDict(dict):
29
30 """
31 Provide attribute access (dict.key) to dictionary values.
32 """
33
34 def __getattr__(self, name):
35 """Allow attribute access for all keys in the dict."""
36 if name in self:
37 return self[name]
38 return super(AttributeDict, self).__getattribute__(name)
39
40
41class DeletableResource(AttributeDict):
42
43 """
44 Support deletion of quantum resources (networks, subnets) via a
45 delete() method, as is supported by keystone and nova resources.
46 """
47
48 def __init__(self, *args, **kwargs):
49 self.client = kwargs.pop('client', None)
50 super(DeletableResource, self).__init__(*args, **kwargs)
51
52 def __str__(self):
53 return '<%s id="%s" name="%s">' % (self.__class__.__name__,
54 self.id, self.name)
55
56 def delete(self):
57 raise NotImplemented()
58
59
60class DeletableNetwork(DeletableResource):
61
62 def delete(self):
63 self.client.delete_network(self.id)
64
65
66class DeletableSubnet(DeletableResource):
67
68 _router_ids = set()
69
70 def add_to_router(self, router_id):
71 self._router_ids.add(router_id)
72 body = dict(subnet_id=self.id)
73 self.client.add_interface_router(router_id, body=body)
74
75 def delete(self):
76 for router_id in self._router_ids.copy():
77 body = dict(subnet_id=self.id)
78 self.client.remove_interface_router(router_id, body=body)
79 self._router_ids.remove(router_id)
80 self.client.delete_subnet(self.id)
81
82
83class DeletableRouter(DeletableResource):
84
85 def add_gateway(self, network_id):
86 body = dict(network_id=network_id)
87 self.client.add_gateway_router(self.id, body=body)
88
89 def delete(self):
90 self.client.remove_gateway_router(self.id)
91 self.client.delete_router(self.id)
92
93
94class DeletableFloatingIp(DeletableResource):
95
96 def delete(self):
97 self.client.delete_floatingip(self.id)
98
99
100class DeletablePort(DeletableResource):
101
102 def delete(self):
103 self.client.delete_port(self.id)
104
105
106class TestNetworkSmokeCommon(smoke.DefaultClientSmokeTest):
107 """
108 Base class for network smoke tests
109 """
110
111 @classmethod
112 def check_preconditions(cls):
113 if (cls.config.network.quantum_available):
114 cls.enabled = True
115 #verify that quantum_available is telling the truth
116 try:
117 cls.network_client.list_networks()
118 except exc.EndpointNotFound:
119 cls.enabled = False
120 raise
121 else:
122 cls.enabled = False
123 msg = 'Quantum not available'
124 raise cls.skipException(msg)
125
126 @classmethod
127 def setUpClass(cls):
128 super(TestNetworkSmokeCommon, cls).setUpClass()
129 cfg = cls.config.network
130 cls.tenant_id = cls.manager._get_identity_client(
131 cls.config.identity.username,
132 cls.config.identity.password,
133 cls.config.identity.tenant_name).tenant_id
134
135 def _create_keypair(self, client, namestart='keypair-smoke-'):
136 kp_name = rand_name(namestart)
137 keypair = client.keypairs.create(kp_name)
138 try:
139 self.assertEqual(keypair.id, kp_name)
140 self.set_resource(kp_name, keypair)
141 except AttributeError:
142 self.fail("Keypair object not successfully created.")
143 return keypair
144
145 def _create_security_group(self, client, namestart='secgroup-smoke-'):
146 # Create security group
147 sg_name = rand_name(namestart)
148 sg_desc = sg_name + " description"
149 secgroup = client.security_groups.create(sg_name, sg_desc)
150 try:
151 self.assertEqual(secgroup.name, sg_name)
152 self.assertEqual(secgroup.description, sg_desc)
153 self.set_resource(sg_name, secgroup)
154 except AttributeError:
155 self.fail("SecurityGroup object not successfully created.")
156
157 # Add rules to the security group
158 rulesets = [
159 {
160 # ssh
161 'ip_protocol': 'tcp',
162 'from_port': 22,
163 'to_port': 22,
164 'cidr': '0.0.0.0/0',
165 'group_id': secgroup.id
166 },
167 {
168 # ping
169 'ip_protocol': 'icmp',
170 'from_port': -1,
171 'to_port': -1,
172 'cidr': '0.0.0.0/0',
173 'group_id': secgroup.id
174 }
175 ]
176 for ruleset in rulesets:
177 try:
178 client.security_group_rules.create(secgroup.id, **ruleset)
179 except Exception:
180 self.fail("Failed to create rule in security group.")
181
182 return secgroup
183
184 def _create_network(self, tenant_id, namestart='network-smoke-'):
185 name = rand_name(namestart)
186 body = dict(
187 network=dict(
188 name=name,
189 tenant_id=tenant_id,
190 ),
191 )
192 result = self.network_client.create_network(body=body)
193 network = DeletableNetwork(client=self.network_client,
194 **result['network'])
195 self.assertEqual(network.name, name)
196 self.set_resource(name, network)
197 return network
198
199 def _list_networks(self):
200 nets = self.network_client.list_networks()
201 return nets['networks']
202
203 def _list_subnets(self):
204 subnets = self.network_client.list_subnets()
205 return subnets['subnets']
206
207 def _list_routers(self):
208 routers = self.network_client.list_routers()
209 return routers['routers']
210
211 def _create_subnet(self, network, namestart='subnet-smoke-'):
212 """
213 Create a subnet for the given network within the cidr block
214 configured for tenant networks.
215 """
216 cfg = self.config.network
217 tenant_cidr = netaddr.IPNetwork(cfg.tenant_network_cidr)
218 result = None
219 # Repeatedly attempt subnet creation with sequential cidr
220 # blocks until an unallocated block is found.
221 for subnet_cidr in tenant_cidr.subnet(cfg.tenant_network_mask_bits):
222 body = dict(
223 subnet=dict(
224 ip_version=4,
225 network_id=network.id,
226 tenant_id=network.tenant_id,
227 cidr=str(subnet_cidr),
228 ),
229 )
230 try:
231 result = self.network_client.create_subnet(body=body)
232 break
233 except exc.QuantumClientException as e:
234 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
235 if not is_overlapping_cidr:
236 raise
237 self.assertIsNotNone(result, 'Unable to allocate tenant network')
238 subnet = DeletableSubnet(client=self.network_client,
239 **result['subnet'])
240 self.assertEqual(subnet.cidr, str(subnet_cidr))
241 self.set_resource(rand_name(namestart), subnet)
242 return subnet
243
244 def _create_port(self, network, namestart='port-quotatest-'):
245 name = rand_name(namestart)
246 body = dict(
247 port=dict(name=name,
248 network_id=network.id,
249 tenant_id=network.tenant_id))
250 try:
251 result = self.network_client.create_port(body=body)
252 except Exception as e:
253 raise
254 self.assertIsNotNone(result, 'Unable to allocate port')
255 port = DeletablePort(client=self.network_client,
256 **result['port'])
257 self.set_resource(name, port)
258 return port
259
260 def _create_server(self, client, network, name, key_name, security_groups):
261 flavor_id = self.config.compute.flavor_ref
262 base_image_id = self.config.compute.image_ref
263 create_kwargs = {
264 'nics': [
265 {'net-id': network.id},
266 ],
267 'key_name': key_name,
268 'security_groups': security_groups,
269 }
270 server = client.servers.create(name, base_image_id, flavor_id,
271 **create_kwargs)
272 try:
273 self.assertEqual(server.name, name)
274 self.set_resource(name, server)
275 except AttributeError:
276 self.fail("Server not successfully created.")
277 self.status_timeout(client.servers, server.id, 'ACTIVE')
278 # The instance retrieved on creation is missing network
279 # details, necessitating retrieval after it becomes active to
280 # ensure correct details.
281 server = client.servers.get(server.id)
282 self.set_resource(name, server)
283 return server
284
285 def _create_floating_ip(self, server, external_network_id):
286 result = self.network_client.list_ports(device_id=server.id)
287 ports = result.get('ports', [])
288 self.assertEqual(len(ports), 1,
289 "Unable to determine which port to target.")
290 port_id = ports[0]['id']
291 body = dict(
292 floatingip=dict(
293 floating_network_id=external_network_id,
294 port_id=port_id,
295 tenant_id=server.tenant_id,
296 )
297 )
298 result = self.network_client.create_floatingip(body=body)
299 floating_ip = DeletableFloatingIp(client=self.network_client,
300 **result['floatingip'])
301 self.set_resource(rand_name('floatingip-'), floating_ip)
302 return floating_ip
303
304 def _ping_ip_address(self, ip_address):
305 cmd = ['ping', '-c1', '-w1', ip_address]
306
307 def ping():
308 proc = subprocess.Popen(cmd,
309 stdout=subprocess.PIPE,
310 stderr=subprocess.PIPE)
311 proc.wait()
312 if proc.returncode == 0:
313 return True
314
315 # TODO(mnewby) Allow configuration of execution and sleep duration.
316 return test.call_until_true(ping, 20, 1)