Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / tests / ports.py @ 19d0725a

History | View | Annotate | Download (15.2 kB)

1
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.i
33

    
34
from django.conf import settings
35
from snf_django.utils.testing import BaseAPITest, override_settings
36
from django.utils import simplejson as json
37
from synnefo.cyclades_settings import cyclades_services
38
from synnefo.lib.services import get_service_path
39
from synnefo.lib import join_urls
40
from mock import patch
41
import synnefo.db.models_factory as dbmf
42

    
43
NETWORK_URL = get_service_path(cyclades_services, 'network',
44
                               version='v2.0')
45
PORTS_URL = join_urls(NETWORK_URL, "ports/")
46

    
47

    
48
class PortTest(BaseAPITest):
49
    def test_get_ports(self):
50
        url = join_urls(PORTS_URL)
51
        response = self.get(url)
52
        self.assertEqual(response.status_code, 200)
53
        ports = json.loads(response.content)
54
        self.assertEqual(ports, {"ports": []})
55

    
56
    def test_get_port_unfound(self):
57
        url = join_urls(PORTS_URL, "123")
58
        response = self.get(url)
59
        self.assertEqual(response.status_code, 404)
60

    
61
    def test_get_port(self):
62
        nic = dbmf.NetworkInterfaceFactory()
63
        url = join_urls(PORTS_URL, str(nic.id))
64
        response = self.get(url, user=nic.userid)
65
        self.assertEqual(response.status_code, 200)
66

    
67
    @patch("synnefo.db.models.get_rapi_client")
68
    def test_delete_port(self, mrapi):
69
        nic = dbmf.NetworkInterfaceFactory(device_owner='vm')
70
        url = join_urls(PORTS_URL, str(nic.id))
71
        mrapi().ModifyInstance.return_value = 42
72
        with override_settings(settings, GANETI_USE_HOTPLUG=True):
73
            response = self.delete(url, user=nic.userid)
74
        self.assertEqual(response.status_code, 204)
75
        with override_settings(settings, GANETI_USE_HOTPLUG=False):
76
            response = self.delete(url, user=nic.userid)
77
        self.assertEqual(response.status_code, 400)
78

    
79
    def test_remove_nic_malformed(self):
80
        url = join_urls(PORTS_URL, "123")
81
        response = self.delete(url)
82
        self.assertItemNotFound(response)
83

    
84
    def test_update_port_name(self):
85
        nic = dbmf.NetworkInterfaceFactory(device_owner='vm')
86
        url = join_urls(PORTS_URL, str(nic.id))
87
        request = {'port': {"name": u"test-name\u2601\u2602"}}
88
        response = self.put(url, params=json.dumps(request),
89
                            user=nic.userid)
90
        self.assertEqual(response.status_code, 200)
91
        res = json.loads(response.content)
92
        self.assertEqual(res['port']['name'],
93
                         u"test-name\u2601\u2602")
94

    
95
    def test_create_port_invalid(self):
96
        # No network
97
        request = {
98
            "port": {
99
                "device_id": "123",
100
                "name": "port1",
101
                "network_id": "123"
102
            }
103
        }
104
        response = self.post(PORTS_URL, params=json.dumps(request))
105
        self.assertEqual(response.status_code, 404)
106
        net = dbmf.NetworkFactory(public=True)
107
        request = {
108
            "port": {
109
                "name": "port1",
110
                "network_id": net.id,
111
                "fixed_ips": [u"lala\u2608"]
112
            }
113
        }
114
        response = self.post(PORTS_URL, params=json.dumps(request))
115
        self.assertEqual(response.status_code, 400, response.content)
116

    
117
    @patch("synnefo.db.models.get_rapi_client")
118
    def test_create_port_private_net(self, mrapi):
119
        net = dbmf.NetworkFactory(public=False)
120
        dbmf.IPv4SubnetFactory(network=net)
121
        dbmf.IPv6SubnetFactory(network=net)
122
        sg1 = dbmf.SecurityGroupFactory()
123
        sg2 = dbmf.SecurityGroupFactory()
124
        vm = dbmf.VirtualMachineFactory(userid=net.userid)
125
        request = {
126
            "port": {
127
                "name": "port1",
128
                "network_id": str(net.id),
129
                "device_id": str(vm.id),
130
                "security_groups": [str(sg1.id), str(sg2.id)]
131
            }
132
        }
133
        mrapi().ModifyInstance.return_value = 42
134
        with override_settings(settings, GANETI_USE_HOTPLUG=False):
135
            response = self.post(PORTS_URL, params=json.dumps(request),
136
                                 user=net.userid)
137
        self.assertEqual(response.status_code, 400)
138
        with override_settings(settings, GANETI_USE_HOTPLUG=True):
139
            response = self.post(PORTS_URL, params=json.dumps(request),
140
                                 user=net.userid)
141
        self.assertEqual(response.status_code, 201)
142

    
143
    def test_create_port_public_net_no_ip(self):
144
        net = dbmf.NetworkFactory(public=True)
145
        vm = dbmf.VirtualMachineFactory(userid=net.userid)
146
        request = {
147
            "port": {
148
                "name": u"Port in the \u2601",
149
                "network_id": str(net.id),
150
                "device_id": str(vm.id),
151
            }
152
        }
153
        response = self.post(PORTS_URL, params=json.dumps(request),
154
                             user=net.userid)
155
        self.assertEqual(response.status_code, 400)
156

    
157
    def test_create_port_public_net_wrong_ip(self):
158
        net = dbmf.NetworkFactory(public=True)
159
        vm = dbmf.VirtualMachineFactory(userid=net.userid)
160
        request = {
161
            "port": {
162
                "name": u"Port in the \u2601",
163
                "network_id": str(net.id),
164
                "device_id": str(vm.id),
165
                "fixed_ips": [{"ip_address": "8.8.8.8"}]
166
            }
167
        }
168
        response = self.post(PORTS_URL, params=json.dumps(request),
169
                             user=net.userid)
170
        self.assertEqual(response.status_code, 404)
171

    
172
    def test_create_port_public_net_conflict(self):
173
        net = dbmf.NetworkFactory(public=True)
174
        fip = dbmf.FloatingIPFactory(nic=None, userid=net.userid)
175
        vm = dbmf.VirtualMachineFactory(userid=net.userid)
176
        request = {
177
            "port": {
178
                "name": "port1",
179
                "network_id": str(net.id),
180
                "device_id": str(vm.id),
181
                "fixed_ips": [{"ip_address": fip.address}]
182
            }
183
        }
184
        response = self.post(PORTS_URL, params=json.dumps(request),
185
                             user=net.userid)
186
        self.assertEqual(response.status_code, 409)
187

    
188
    def test_create_port_public_net_taken_ip(self):
189
        net = dbmf.NetworkFactory(public=True)
190
        fip = dbmf.FloatingIPFactory(network=net, userid=net.userid)
191
        vm = dbmf.VirtualMachineFactory(userid=net.userid)
192
        request = {
193
            "port": {
194
                "name": "port1",
195
                "network_id": str(net.id),
196
                "device_id": str(vm.id),
197
                "fixed_ips": [{"ip_address": fip.address}]
198
            }
199
        }
200
        response = self.post(PORTS_URL, params=json.dumps(request),
201
                             user=net.userid)
202
        self.assertEqual(response.status_code, 409)
203

    
204
    @patch("synnefo.db.models.get_rapi_client")
205
    def test_create_port_with_floating_ip(self, mrapi):
206
        vm = dbmf.VirtualMachineFactory()
207
        fip = dbmf.FloatingIPFactory(network__public=True, nic=None,
208
                                     userid=vm.userid)
209
        request = {
210
            "port": {
211
                "name": "Port in the \u2601",
212
                "network_id": str(fip.network_id),
213
                "device_id": str(vm.id),
214
                "fixed_ips": [{"ip_address": fip.address}]
215
            }
216
        }
217
        mrapi().ModifyInstance.return_value = 42
218
        with override_settings(settings, GANETI_USE_HOTPLUG=True):
219
            response = self.post(PORTS_URL, params=json.dumps(request),
220
                                 user=vm.userid)
221
        self.assertEqual(response.status_code, 201)
222

    
223
    @patch("synnefo.db.models.get_rapi_client")
224
    def test_create_port_with_address(self, mrapi):
225
        """Test creation if IP address is specified."""
226
        mrapi().ModifyInstance.return_value = 42
227
        vm = dbmf.VirtualMachineFactory()
228
        net = dbmf.NetworkWithSubnetFactory(userid=vm.userid,
229
                                            public=False,
230
                                            subnet__cidr="192.168.2.0/24",
231
                                            subnet__gateway=None,
232
                                            subnet__pool__size=1,
233
                                            subnet__pool__offset=1)
234
        request = {
235
            "port": {
236
                "name": "port_with_address",
237
                "network_id": str(net.id),
238
                "device_id": str(vm.id),
239
                "fixed_ips": [{"ip_address": "192.168.2.1"}]
240
            }
241
        }
242
        with override_settings(settings, GANETI_USE_HOTPLUG=True):
243
            response = self.post(PORTS_URL, params=json.dumps(request),
244
                                 user=vm.userid)
245
        self.assertEqual(response.status_code, 201)
246
        new_port_ip = json.loads(response.content)["port"]["fixed_ips"][0]
247
        self.assertEqual(new_port_ip["ip_address"], "192.168.2.1")
248

    
249
        # But 409 if address is already used
250
        with override_settings(settings, GANETI_USE_HOTPLUG=True):
251
            response = self.post(PORTS_URL, params=json.dumps(request),
252
                                 user=vm.userid)
253
        self.assertConflict(response)
254

    
255
        # And bad request if IPv6 address is specified
256
        request["port"]["fixed_ips"][0]["ip_address"] = "babe::"
257
        with override_settings(settings, GANETI_USE_HOTPLUG=True):
258
            response = self.post(PORTS_URL, params=json.dumps(request),
259
                                 user=vm.userid)
260
        self.assertBadRequest(response)
261

    
262
    def test_create_port_without_device(self):
263
        net = dbmf.NetworkWithSubnetFactory(userid="test_user",
264
                                            public=False,
265
                                            subnet__cidr="192.168.2.0/24",
266
                                            subnet__gateway=None,
267
                                            subnet__pool__size=3,
268
                                            subnet__pool__offset=1)
269
        request = {
270
            "port": {
271
                "name": "port_with_address",
272
                "network_id": str(net.id),
273
            }
274
        }
275
        response = self.post(PORTS_URL, params=json.dumps(request),
276
                             user="test_user")
277
        self.assertEqual(response.status_code, 201)
278
        new_port = json.loads(response.content)["port"]
279
        self.assertEqual(new_port["device_id"], None)
280
        # And with address
281
        request["port"]["fixed_ips"] = [{"ip_address": "192.168.2.2"}]
282
        with override_settings(settings, GANETI_USE_HOTPLUG=True):
283
            response = self.post(PORTS_URL, params=json.dumps(request),
284
                                 user="test_user")
285
        self.assertEqual(response.status_code, 201)
286
        new_port = json.loads(response.content)["port"]
287
        self.assertEqual(new_port["device_id"], None)
288
        self.assertEqual(new_port["fixed_ips"][0]["ip_address"], "192.168.2.2")
289

    
290
    def test_add_nic_to_deleted_network(self):
291
        user = 'userr'
292
        vm = dbmf.VirtualMachineFactory(name='yo', userid=user,
293
                                        operstate="ACTIVE")
294
        net = dbmf.NetworkFactory(state='ACTIVE', userid=user,
295
                                  deleted=True)
296
        request = {
297
            "port": {
298
                "device_id": str(vm.id),
299
                "name": "port1",
300
                "network_id": str(net.id)
301
            }
302
        }
303
        response = self.post(PORTS_URL, params=json.dumps(request),
304
                             user=net.userid)
305
        self.assertBadRequest(response)
306

    
307
    def test_add_nic_to_public_network(self):
308
        user = 'userr'
309
        vm = dbmf.VirtualMachineFactory(name='yo', userid=user)
310
        net = dbmf.NetworkFactory(state='ACTIVE', userid=user, public=True)
311
        request = {
312
            "port": {
313
                "device_id": str(vm.id),
314
                "name": "port1",
315
                "network_id": str(net.id)
316
            }
317
        }
318
        response = self.post(PORTS_URL, params=json.dumps(request),
319
                             user=net.userid)
320
        self.assertBadRequest(response)
321
        #self.assertFault(response, 403, 'forbidden')
322

    
323
    def test_add_nic_malformed_2(self):
324
        user = 'userr'
325
        vm = dbmf.VirtualMachineFactory(name='yo', userid=user)
326
        net = dbmf.NetworkFactory(state='ACTIVE', userid=user)
327
        request = {
328
            "port": {
329
                "device_id": str(vm.id),
330
                "name": "port1"
331
            }
332
        }
333
        response = self.post(PORTS_URL, params=json.dumps(request),
334
                             user=net.userid)
335
        self.assertBadRequest(response)
336

    
337
    def test_add_nic_not_active(self):
338
        """Test connecting VM to non-active network"""
339
        user = 'dummy'
340
        vm = dbmf.VirtualMachineFactory(name='yo', userid=user)
341
        net = dbmf.NetworkFactory(state='PENDING', userid=user)
342
        request = {
343
            "port": {
344
                "device_id": str(vm.id),
345
                "name": "port1",
346
                "network_id": str(net.id)
347
            }
348
        }
349
        response = self.post(PORTS_URL, params=json.dumps(request),
350
                             user=net.userid)
351
        # Test that returns BuildInProgress
352
        self.assertEqual(response.status_code, 409)
353

    
354
#    def test_add_nic_full_network(self, mrapi):
355
#        """Test connecting VM to a full network"""
356
#        user = 'userr'
357
#        vm = dbmf.VirtualMachineFactory(name='yo', userid=user,
358
#                                            operstate="STARTED")
359
#        net = dbmf.NetworkFactory(state='ACTIVE', subnet='10.0.0.0/30',
360
#                                      userid=user, dhcp=True)
361
#        pool = net.get_pool()
362
#        while not pool.empty():
363
#            pool.get()
364
#        pool.save()
365
#        pool = net.get_pool()
366
#        self.assertTrue(pool.empty())
367
#        request = {'add': {'serverRef': vm.id}}
368
#        response = self.mypost('networks/%d/action' % net.id,
369
#                               net.userid, json.dumps(request), 'json')
370
#        # Test that returns OverLimit
371
#        self.assertEqual(response.status_code, 413)
372
#        self.assertFalse(mrapi.called)