Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / tests / servers.py @ a1baa42b

History | View | Annotate | Download (12.7 kB)

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

    
31
# Provides automated tests for logic module
32
from django.test import TransactionTestCase
33
#from snf_django.utils.testing import mocked_quotaholder
34
from synnefo.logic import servers
35
from synnefo.db import models_factory as mfactory, models
36
from mock import patch
37

    
38
from snf_django.lib.api import faults
39
from snf_django.utils.testing import mocked_quotaholder, override_settings
40
from django.conf import settings
41
from copy import deepcopy
42

    
43

    
44
@patch("synnefo.logic.rapi_pool.GanetiRapiClient")
45
class ServerCreationTest(TransactionTestCase):
46
    def test_create(self, mrapi):
47
        flavor = mfactory.FlavorFactory()
48
        kwargs = {
49
            "userid": "test",
50
            "name": "test_vm",
51
            "password": "1234",
52
            "flavor": flavor,
53
            "image": {"id": "foo", "backend_id": "foo", "format": "diskdump",
54
                      "metadata": "{}"},
55
            "metadata": {"foo": "bar"},
56
            "personality": [],
57
        }
58
        # no backend!
59
        mfactory.BackendFactory(offline=True)
60
        self.assertRaises(faults.ServiceUnavailable, servers.create, **kwargs)
61
        self.assertEqual(models.VirtualMachine.objects.count(), 0)
62

    
63
        mfactory.BackendFactory(drained=False)
64
        mfactory.BackendNetworkFactory(network__public=True)
65

    
66
        # error in nics
67
        req = deepcopy(kwargs)
68
        req["private_networks"] = [42]
69
        self.assertRaises(faults.ItemNotFound, servers.create, **req)
70
        self.assertEqual(models.VirtualMachine.objects.count(), 0)
71

    
72
        # error in enqueue. check the vm is deleted and resources released
73
        mrapi().CreateInstance.side_effect = Exception("ganeti is down")
74
        with mocked_quotaholder():
75
            servers.create(**kwargs)
76
        vm = models.VirtualMachine.objects.get()
77
        self.assertFalse(vm.deleted)
78
        self.assertEqual(vm.operstate, "ERROR")
79
        self.assertEqual(len(vm.nics.all()), 1)
80
        for nic in vm.nics.all():
81
            self.assertEqual(nic.state, "ERROR")
82

    
83
        # success with no nics
84
        mrapi().CreateInstance.side_effect = None
85
        mrapi().CreateInstance.return_value = 42
86
        with override_settings(settings,
87
                               DEFAULT_INSTANCE_NETWORKS=[]):
88
            with mocked_quotaholder():
89
                vm = servers.create(**kwargs)
90
        vm = models.VirtualMachine.objects.get(id=vm.id)
91
        self.assertEqual(vm.nics.count(), 0)
92
        self.assertEqual(vm.backendjobid, 42)
93
        self.assertEqual(vm.task_job_id, 42)
94
        self.assertEqual(vm.task, "BUILD")
95

    
96
        # test connect in IPv6 only network
97
        net = mfactory.IPv6NetworkFactory(state="ACTIVE")
98
        mfactory.BackendNetworkFactory(network=net)
99
        with override_settings(settings,
100
                               DEFAULT_INSTANCE_NETWORKS=[str(net.id)]):
101
            with mocked_quotaholder():
102
                vm = servers.create(**kwargs)
103
        nics = vm.nics.all()
104
        self.assertEqual(len(nics), 1)
105
        self.assertEqual(nics[0].ipv4, None)
106
        args, kwargs = mrapi().CreateInstance.call_args
107
        ganeti_nic = kwargs["nics"][0]
108
        self.assertEqual(ganeti_nic["ip"], None)
109
        self.assertEqual(ganeti_nic["network"], net.backend_id)
110

    
111

    
112
@patch("synnefo.logic.rapi_pool.GanetiRapiClient")
113
class ServerTest(TransactionTestCase):
114
    def test_connect_network(self, mrapi):
115
        # Common connect
116
        net = mfactory.NetworkFactory(subnet="192.168.2.0/24",
117
                                      gateway="192.168.2.1",
118
                                      state="ACTIVE",
119
                                      dhcp=True,
120
                                      flavor="CUSTOM")
121
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")
122
        mfactory.BackendNetworkFactory(network=net, backend=vm.backend)
123
        mrapi().ModifyInstance.return_value = 42
124
        servers.connect(vm, net)
125
        pool = net.get_pool(with_lock=False)
126
        self.assertFalse(pool.is_available("192.168.2.2"))
127
        args, kwargs = mrapi().ModifyInstance.call_args
128
        nics = kwargs["nics"][0]
129
        self.assertEqual(kwargs["instance"], vm.backend_vm_id)
130
        self.assertEqual(nics[0], "add")
131
        self.assertEqual(nics[1], "-1")
132
        self.assertEqual(nics[2]["ip"], "192.168.2.2")
133
        self.assertEqual(nics[2]["network"], net.backend_id)
134

    
135
        # No dhcp
136
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")
137
        net = mfactory.NetworkFactory(subnet="192.168.2.0/24",
138
                                      gateway="192.168.2.1",
139
                                      state="ACTIVE",
140
                                      dhcp=False)
141
        mfactory.BackendNetworkFactory(network=net, backend=vm.backend)
142
        servers.connect(vm, net)
143
        pool = net.get_pool(with_lock=False)
144
        self.assertTrue(pool.is_available("192.168.2.2"))
145
        args, kwargs = mrapi().ModifyInstance.call_args
146
        nics = kwargs["nics"][0]
147
        self.assertEqual(kwargs["instance"], vm.backend_vm_id)
148
        self.assertEqual(nics[0], "add")
149
        self.assertEqual(nics[1], "-1")
150
        self.assertEqual(nics[2]["ip"], None)
151
        self.assertEqual(nics[2]["network"], net.backend_id)
152

    
153
        # Test connect to IPv6 only network
154
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")
155
        net = mfactory.NetworkFactory(subnet6="2000::/64",
156
                                      state="ACTIVE",
157
                                      gateway="2000::1")
158
        mfactory.BackendNetworkFactory(network=net, backend=vm.backend)
159
        servers.connect(vm, net)
160
        args, kwargs = mrapi().ModifyInstance.call_args
161
        nics = kwargs["nics"][0]
162
        self.assertEqual(kwargs["instance"], vm.backend_vm_id)
163
        self.assertEqual(nics[0], "add")
164
        self.assertEqual(nics[1], "-1")
165
        self.assertEqual(nics[2]["ip"], None)
166
        self.assertEqual(nics[2]["network"], net.backend_id)
167

    
168

    
169
@patch("synnefo.logic.rapi_pool.GanetiRapiClient")
170
class ServerCommandTest(TransactionTestCase):
171
    def test_pending_task(self, mrapi):
172
        vm = mfactory.VirtualMachineFactory(task="REBOOT", task_job_id=1)
173
        self.assertRaises(faults.BadRequest, servers.start, vm)
174
        vm = mfactory.VirtualMachineFactory(task="BUILD", task_job_id=1)
175
        self.assertRaises(faults.BuildInProgress, servers.start, vm)
176
        # Assert always succeeds
177
        vm = mfactory.VirtualMachineFactory(task="BUILD", task_job_id=1)
178
        mrapi().DeleteInstance.return_value = 1
179
        with mocked_quotaholder():
180
            servers.destroy(vm)
181
        vm = mfactory.VirtualMachineFactory(task="REBOOT", task_job_id=1)
182
        with mocked_quotaholder():
183
            servers.destroy(vm)
184

    
185
    def test_deleted_vm(self, mrapi):
186
        vm = mfactory.VirtualMachineFactory(deleted=True)
187
        self.assertRaises(faults.BadRequest, servers.start, vm)
188

    
189
    def test_invalid_operstate_for_action(self, mrapi):
190
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")
191
        self.assertRaises(faults.BadRequest, servers.start, vm)
192
        vm = mfactory.VirtualMachineFactory(operstate="STOPPED")
193
        self.assertRaises(faults.BadRequest, servers.stop, vm)
194
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")
195
        self.assertRaises(faults.BadRequest, servers.resize, vm)
196
        # Check that connect/disconnect is allowed only in STOPPED vms
197
        # if hotplug is disabled.
198
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")
199
        network = mfactory.NetworkFactory(state="ACTIVE")
200
        with override_settings(settings, GANETI_USE_HOTPLUG=False):
201
            self.assertRaises(faults.BadRequest, servers.connect, vm, network)
202
            self.assertRaises(faults.BadRequest, servers.disconnect, vm,
203
                              network)
204
        #test valid
205
        vm = mfactory.VirtualMachineFactory(operstate="STOPPED")
206
        mrapi().StartupInstance.return_value = 1
207
        with mocked_quotaholder():
208
            servers.start(vm)
209
        vm.task = None
210
        vm.task_job_id = None
211
        vm.save()
212
        mrapi().RebootInstance.return_value = 1
213
        with mocked_quotaholder():
214
            servers.reboot(vm, "HARD")
215

    
216
    def test_commission(self, mrapi):
217
        vm = mfactory.VirtualMachineFactory(operstate="STOPPED")
218
        # Still pending
219
        vm.serial = mfactory.QuotaHolderSerialFactory(serial=200,
220
                                                      resolved=False,
221
                                                      pending=True)
222
        serial = vm.serial
223
        mrapi().StartupInstance.return_value = 1
224
        with mocked_quotaholder() as m:
225
            servers.start(vm)
226
            m.resolve_commissions.assert_called_once_with('', [],
227
                                                          [serial.serial])
228
            self.assertTrue(m.issue_one_commission.called)
229
        # Not pending, rejct
230
        vm.task = None
231
        vm.serial = mfactory.QuotaHolderSerialFactory(serial=400,
232
                                                      resolved=False,
233
                                                      pending=False,
234
                                                      accept=False)
235
        serial = vm.serial
236
        mrapi().StartupInstance.return_value = 1
237
        with mocked_quotaholder() as m:
238
            servers.start(vm)
239
            m.resolve_commissions.assert_called_once_with('', [],
240
                                                          [serial.serial])
241
            self.assertTrue(m.issue_one_commission.called)
242
        # Not pending, accept
243
        vm.task = None
244
        vm.serial = mfactory.QuotaHolderSerialFactory(serial=600,
245
                                                      resolved=False,
246
                                                      pending=False,
247
                                                      accept=True)
248
        serial = vm.serial
249
        mrapi().StartupInstance.return_value = 1
250
        with mocked_quotaholder() as m:
251
            servers.start(vm)
252
            m.resolve_commissions.assert_called_once_with('', [serial.serial],
253
                                                          [])
254
            self.assertTrue(m.issue_one_commission.called)
255

    
256
        mrapi().StartupInstance.side_effect = ValueError
257
        vm.task = None
258
        vm.serial = None
259
        # Test reject if Ganeti erro
260
        with mocked_quotaholder() as m:
261
            try:
262
                servers.start(vm)
263
            except:
264
                m.resolve_commissions\
265
                 .assert_called_once_with('', [], [vm.serial.serial])
266

    
267
    def test_task_after(self, mrapi):
268
        return
269
        vm = mfactory.VirtualMachineFactory()
270
        mrapi().StartupInstance.return_value = 1
271
        mrapi().ShutdownInstance.return_value = 2
272
        mrapi().RebootInstance.return_value = 2
273
        with mocked_quotaholder():
274
            vm.task = None
275
            vm.operstate = "STOPPED"
276
            servers.start(vm)
277
            self.assertEqual(vm.task, "START")
278
            self.assertEqual(vm.task_job_id, 1)
279
        with mocked_quotaholder():
280
            vm.task = None
281
            vm.operstate = "STARTED"
282
            servers.stop(vm)
283
            self.assertEqual(vm.task, "STOP")
284
            self.assertEqual(vm.task_job_id, 2)
285
        with mocked_quotaholder():
286
            vm.task = None
287
            servers.reboot(vm)
288
            self.assertEqual(vm.task, "REBOOT")
289
            self.assertEqual(vm.task_job_id, 3)