Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (11.3 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.IPv4SubnetFactory(network__public=True)
64
        mfactory.IPv6SubnetFactory(network__public=True)
65
        mfactory.BackendFactory()
66

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

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

    
84

    
85
@patch("synnefo.logic.rapi_pool.GanetiRapiClient")
86
class ServerTest(TransactionTestCase):
87
    def test_connect_network(self, mrapi):
88
        # Common connect
89
        for dhcp in [True, False]:
90
            subnet = mfactory.IPv4SubnetFactory(network__flavor="CUSTOM",
91
                                                cidr="192.168.2.0/24",
92
                                                gateway="192.168.2.1",
93
                                                dhcp=dhcp)
94
            net = subnet.network
95
            vm = mfactory.VirtualMachineFactory(operstate="STARTED")
96
            mfactory.BackendNetworkFactory(network=net, backend=vm.backend)
97
            mrapi().ModifyInstance.return_value = 42
98
            with override_settings(settings, GANETI_USE_HOTPLUG=True):
99
                servers.connect(vm, net)
100
            pool = net.get_ip_pools(locked=False)[0]
101
            self.assertFalse(pool.is_available("192.168.2.2"))
102
            args, kwargs = mrapi().ModifyInstance.call_args
103
            nics = kwargs["nics"][0]
104
            self.assertEqual(kwargs["instance"], vm.backend_vm_id)
105
            self.assertEqual(nics[0], "add")
106
            self.assertEqual(nics[1], "-1")
107
            self.assertEqual(nics[2]["ip"], "192.168.2.2")
108
            self.assertEqual(nics[2]["network"], net.backend_id)
109

    
110
        # Test connect to IPv6 only network
111
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")
112
        subnet = mfactory.IPv6SubnetFactory(cidr="2000::/64",
113
                                            gateway="2000::1")
114
        net = subnet.network
115
        mfactory.BackendNetworkFactory(network=net, backend=vm.backend)
116
        with override_settings(settings, GANETI_USE_HOTPLUG=True):
117
            servers.connect(vm, net)
118
        args, kwargs = mrapi().ModifyInstance.call_args
119
        nics = kwargs["nics"][0]
120
        self.assertEqual(kwargs["instance"], vm.backend_vm_id)
121
        self.assertEqual(nics[0], "add")
122
        self.assertEqual(nics[1], "-1")
123
        self.assertEqual(nics[2]["ip"], None)
124
        self.assertEqual(nics[2]["network"], net.backend_id)
125

    
126

    
127
@patch("synnefo.logic.rapi_pool.GanetiRapiClient")
128
class ServerCommandTest(TransactionTestCase):
129
    def test_pending_task(self, mrapi):
130
        vm = mfactory.VirtualMachineFactory(task="REBOOT", task_job_id=1)
131
        self.assertRaises(faults.BadRequest, servers.start, vm)
132
        vm = mfactory.VirtualMachineFactory(task="BUILD", task_job_id=1)
133
        self.assertRaises(faults.BuildInProgress, servers.start, vm)
134
        # Assert always succeeds
135
        vm = mfactory.VirtualMachineFactory(task="BUILD", task_job_id=1)
136
        mrapi().DeleteInstance.return_value = 1
137
        with mocked_quotaholder():
138
            servers.destroy(vm)
139
        vm = mfactory.VirtualMachineFactory(task="REBOOT", task_job_id=1)
140
        with mocked_quotaholder():
141
            servers.destroy(vm)
142

    
143
    def test_deleted_vm(self, mrapi):
144
        vm = mfactory.VirtualMachineFactory(deleted=True)
145
        self.assertRaises(faults.BadRequest, servers.start, vm)
146

    
147
    def test_invalid_operstate_for_action(self, mrapi):
148
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")
149
        self.assertRaises(faults.BadRequest, servers.start, vm)
150
        vm = mfactory.VirtualMachineFactory(operstate="STOPPED")
151
        self.assertRaises(faults.BadRequest, servers.stop, vm)
152
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")
153
        self.assertRaises(faults.BadRequest, servers.resize, vm)
154
        # Check that connect/disconnect is allowed only in STOPPED vms
155
        # if hotplug is disabled.
156
        vm = mfactory.VirtualMachineFactory(operstate="STARTED")
157
        network = mfactory.NetworkFactory(state="ACTIVE")
158
        with override_settings(settings, GANETI_USE_HOTPLUG=False):
159
            self.assertRaises(faults.BadRequest, servers.connect, vm, network)
160
            self.assertRaises(faults.BadRequest, servers.disconnect, vm,
161
                              network)
162
        #test valid
163
        vm = mfactory.VirtualMachineFactory(operstate="STOPPED")
164
        mrapi().StartupInstance.return_value = 1
165
        with mocked_quotaholder():
166
            servers.start(vm)
167
        vm.task = None
168
        vm.task_job_id = None
169
        vm.save()
170
        mrapi().RebootInstance.return_value = 1
171
        with mocked_quotaholder():
172
            servers.reboot(vm, "HARD")
173

    
174
    def test_commission(self, mrapi):
175
        vm = mfactory.VirtualMachineFactory(operstate="STOPPED")
176
        # Still pending
177
        vm.serial = mfactory.QuotaHolderSerialFactory(serial=200,
178
                                                      resolved=False,
179
                                                      pending=True)
180
        serial = vm.serial
181
        mrapi().StartupInstance.return_value = 1
182
        with mocked_quotaholder() as m:
183
            with override_settings(settings, CYCLADES_SERVICE_TOKEN=''):
184
                servers.start(vm)
185
            m.resolve_commissions.assert_called_once_with('', [],
186
                                                          [serial.serial])
187
            self.assertTrue(m.issue_one_commission.called)
188
        # Not pending, rejct
189
        vm.task = None
190
        vm.serial = mfactory.QuotaHolderSerialFactory(serial=400,
191
                                                      resolved=False,
192
                                                      pending=False,
193
                                                      accept=False)
194
        serial = vm.serial
195
        mrapi().StartupInstance.return_value = 1
196
        with mocked_quotaholder() as m:
197
            with override_settings(settings, CYCLADES_SERVICE_TOKEN=''):
198
                servers.start(vm)
199
            m.resolve_commissions.assert_called_once_with('', [],
200
                                                          [serial.serial])
201
            self.assertTrue(m.issue_one_commission.called)
202
        # Not pending, accept
203
        vm.task = None
204
        vm.serial = mfactory.QuotaHolderSerialFactory(serial=600,
205
                                                      resolved=False,
206
                                                      pending=False,
207
                                                      accept=True)
208
        serial = vm.serial
209
        mrapi().StartupInstance.return_value = 1
210
        with mocked_quotaholder() as m:
211
            with override_settings(settings, CYCLADES_SERVICE_TOKEN=''):
212
                servers.start(vm)
213
            m.resolve_commissions.assert_called_once_with('', [serial.serial],
214
                                                          [])
215
            self.assertTrue(m.issue_one_commission.called)
216

    
217
        mrapi().StartupInstance.side_effect = ValueError
218
        vm.task = None
219
        vm.serial = None
220
        # Test reject if Ganeti erro
221
        with mocked_quotaholder() as m:
222
            with override_settings(settings, CYCLADES_SERVICE_TOKEN=''):
223
                try:
224
                    servers.start(vm)
225
                except:
226
                    m.resolve_commissions\
227
                     .assert_called_once_with('', [], [vm.serial.serial])
228

    
229
    def test_task_after(self, mrapi):
230
        return
231
        vm = mfactory.VirtualMachineFactory()
232
        mrapi().StartupInstance.return_value = 1
233
        mrapi().ShutdownInstance.return_value = 2
234
        mrapi().RebootInstance.return_value = 2
235
        with mocked_quotaholder():
236
            vm.task = None
237
            vm.operstate = "STOPPED"
238
            servers.start(vm)
239
            self.assertEqual(vm.task, "START")
240
            self.assertEqual(vm.task_job_id, 1)
241
        with mocked_quotaholder():
242
            vm.task = None
243
            vm.operstate = "STARTED"
244
            servers.stop(vm)
245
            self.assertEqual(vm.task, "STOP")
246
            self.assertEqual(vm.task_job_id, 2)
247
        with mocked_quotaholder():
248
            vm.task = None
249
            servers.reboot(vm)
250
            self.assertEqual(vm.task, "REBOOT")
251
            self.assertEqual(vm.task_job_id, 3)