Revision ca4d59e3

b/snf-cyclades-app/synnefo/logic/backend.py
36 36

  
37 37
from synnefo.db.models import (Backend, VirtualMachine, Network,
38 38
                               BackendNetwork, BACKEND_STATUSES,
39
                               pooled_rapi_client, VirtualMachineDiagnostic)
39
                               pooled_rapi_client, VirtualMachineDiagnostic,
40
                               Flavor)
40 41
from synnefo.logic import utils
41 42
from synnefo import quotas
42 43
from synnefo.api.util import release_resource
......
55 56

  
56 57

  
57 58
@transaction.commit_on_success
58
def process_op_status(vm, etime, jobid, opcode, status, logmsg, nics=None):
59
def process_op_status(vm, etime, jobid, opcode, status, logmsg, nics=None,
60
                      beparams=None):
59 61
    """Process a job progress notification from the backend
60 62

  
61 63
    Process an incoming message from the backend (currently Ganeti).
......
78 80
    if status == 'success' and state_for_success is not None:
79 81
        vm.operstate = state_for_success
80 82

  
81
    # Update the NICs of the VM
82 83
    if status == "success" and nics is not None:
84
        # Update the NICs of the VM
83 85
        _process_net_status(vm, etime, nics)
84 86

  
87
    if beparams:
88
        assert(opcode == "OP_INSTANCE_SET_PARAMS"), "'beparams' should exist"\
89
                                                    " only for SET_PARAMS"
90
        # VM Resize
91
        if status == "success":
92
            # VM has been resized. Change the flavor
93
            _process_resize(vm, beparams)
94
            vm.operstate = "STOPPED"
95
        elif status in ("canceled", "error"):
96
            vm.operstate = "STOPPED"
97
        else:
98
            vm.operstate = "RESIZE"
99

  
85 100
    # Special case: if OP_INSTANCE_CREATE fails --> ERROR
86 101
    if opcode == 'OP_INSTANCE_CREATE' and status in ('canceled', 'error'):
87 102
        vm.operstate = 'ERROR'
......
111 126
    vm.save()
112 127

  
113 128

  
129
def _process_resize(vm, beparams):
130
    """Change flavor of a VirtualMachine based on new beparams."""
131
    old_flavor = vm.flavor
132
    vcpus = beparams.get("vcpus", None) or old_flavor.cpu
133
    minmem, maxmem = beparams.get("minmem"), beparams.get("maxmem")
134
    assert(minmem == maxmem), "Different minmem from maxmem"
135
    if vcpus is None and maxmem is None:
136
        return
137
    ram = maxmem or old_flavor.ram
138
    try:
139
        new_flavor = Flavor.objects.get(cpu=vcpus, ram=ram,
140
                                        disk=old_flavor.disk,
141
                                        disk_template=old_flavor.disk_template)
142
    except Flavor.DoesNotExist:
143
        raise Exception("Can not find flavor for VM")
144
    vm.flavor = new_flavor
145
    vm.save()
146

  
147

  
114 148
@transaction.commit_on_success
115 149
def process_net_status(vm, etime, nics):
116 150
    """Wrap _process_net_status inside transaction."""
b/snf-cyclades-app/synnefo/logic/callbacks.py
171 171
        return
172 172

  
173 173
    nics = msg.get("nics", None)
174
    beparams = msg.get("beparams", None)
174 175
    backend.process_op_status(vm, event_time, msg['jobId'], msg['operation'],
175
                              msg['status'], msg['logmsg'], nics)
176
                              msg['status'], msg['logmsg'], nics=nics,
177
                              beparams=beparams)
176 178

  
177 179
    log.debug("Done processing ganeti-op-status msg for vm %s.",
178 180
              msg['instance'])
b/snf-cyclades-app/synnefo/logic/tests.py
193 193
        self.assertEqual(db_vm.operstate, vm.operstate)
194 194
        self.assertEqual(db_vm.backendtime, vm.backendtime)
195 195

  
196
    def test_resize_msg(self, client):
197
        vm = mfactory.VirtualMachineFactory()
198
        # Test empty beparams
199
        for status in ["success", "error"]:
200
            msg = self.create_msg(operation='OP_INSTANCE_SET_PARAMS',
201
                                  instance=vm.backend_vm_id,
202
                                  beparams={},
203
                                  status=status)
204
            client.reset_mock()
205
            update_db(client, msg)
206
            self.assertTrue(client.basic_ack.called)
207
            db_vm = VirtualMachine.objects.get(id=vm.id)
208
            self.assertEqual(db_vm.operstate, vm.operstate)
209
        # Test intermediate states
210
        for status in ["queued", "waiting", "running"]:
211
            msg = self.create_msg(operation='OP_INSTANCE_SET_PARAMS',
212
                                  instance=vm.backend_vm_id,
213
                                  beparams={"vcpus": 4, "minmem": 2048,
214
                                            "maxmem": 2048},
215
                                  status=status)
216
            client.reset_mock()
217
            update_db(client, msg)
218
            self.assertTrue(client.basic_ack.called)
219
            db_vm = VirtualMachine.objects.get(id=vm.id)
220
            self.assertEqual(db_vm.operstate, "RESIZE")
221
        # Test operstate after error
222
        msg = self.create_msg(operation='OP_INSTANCE_SET_PARAMS',
223
                              instance=vm.backend_vm_id,
224
                              beparams={"vcpus": 4},
225
                              status="error")
226
        client.reset_mock()
227
        update_db(client, msg)
228
        self.assertTrue(client.basic_ack.called)
229
        db_vm = VirtualMachine.objects.get(id=vm.id)
230
        self.assertEqual(db_vm.operstate, "STOPPED")
231
        # Test success
232
        f1 = mfactory.FlavorFactory(cpu=4, ram=1024, disk_template="drbd",
233
                                    disk=1024)
234
        vm.flavor = f1
235
        vm.save()
236
        f2 = mfactory.FlavorFactory(cpu=8, ram=2048, disk_template="drbd",
237
                                    disk=1024)
238
        msg = self.create_msg(operation='OP_INSTANCE_SET_PARAMS',
239
                              instance=vm.backend_vm_id,
240
                              beparams={"vcpus": 8, "minmem": 2048,
241
                                        "maxmem": 2048},
242
                              status="success")
243
        client.reset_mock()
244
        update_db(client, msg)
245
        self.assertTrue(client.basic_ack.called)
246
        db_vm = VirtualMachine.objects.get(id=vm.id)
247
        self.assertEqual(db_vm.operstate, "STOPPED")
248
        self.assertEqual(db_vm.flavor, f2)
249
        msg = self.create_msg(operation='OP_INSTANCE_SET_PARAMS',
250
                              instance=vm.backend_vm_id,
251
                              beparams={"vcpus": 100, "minmem": 2048,
252
                                        "maxmem": 2048},
253
                              status="success")
254
        client.reset_mock()
255
        update_db(client, msg)
256
        self.assertTrue(client.basic_reject.called)
257

  
196 258

  
197 259
@patch('synnefo.lib.amqp.AMQPClient')
198 260
class UpdateNetTest(TestCase):

Also available in: Unified diff