Statistics
| Branch: | Tag: | Revision:

one / src / rm / RequestManagerVirtualMachine.cc @ 3f0a7fc0

History | View | Annotate | Download (60.9 KB)

1
/* -------------------------------------------------------------------------- */
2
/* Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs        */
3
/*                                                                            */
4
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
5
/* not use this file except in compliance with the License. You may obtain    */
6
/* a copy of the License at                                                   */
7
/*                                                                            */
8
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
9
/*                                                                            */
10
/* Unless required by applicable law or agreed to in writing, software        */
11
/* distributed under the License is distributed on an "AS IS" BASIS,          */
12
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
13
/* See the License for the specific language governing permissions and        */
14
/* limitations under the License.                                             */
15
/* -------------------------------------------------------------------------- */
16

    
17
#include "RequestManagerVirtualMachine.h"
18
#include "PoolObjectAuth.h"
19
#include "Nebula.h"
20
#include "Quotas.h"
21

    
22
/* -------------------------------------------------------------------------- */
23
/* -------------------------------------------------------------------------- */
24

    
25
bool RequestManagerVirtualMachine::vm_authorization(
26
        int                     oid,
27
        ImageTemplate *         tmpl,
28
        VirtualMachineTemplate* vtmpl,
29
        RequestAttributes&      att,
30
        PoolObjectAuth *        host_perm,
31
        PoolObjectAuth *        ds_perm,
32
        AuthRequest::Operation  op)
33
{
34
    PoolObjectSQL * object;
35
    PoolObjectAuth vm_perms;
36

    
37
    object = pool->get(oid,true);
38

    
39
    if ( object == 0 )
40
    {
41
        failure_response(NO_EXISTS,
42
                get_error(object_name(auth_object),oid),
43
                att);
44

    
45
        return false;
46
    }
47

    
48
    if ( att.uid == 0 )
49
    {
50
        object->unlock();
51
        return true;
52
    }
53

    
54
    object->get_permissions(vm_perms);
55

    
56
    object->unlock();
57

    
58
    AuthRequest ar(att.uid, att.group_ids);
59

    
60
    ar.add_auth(op, vm_perms);
61

    
62
    if (host_perm != 0)
63
    {
64
        ar.add_auth(AuthRequest::MANAGE, *host_perm);
65
    }
66

    
67
    if (tmpl != 0)
68
    {
69
        string t_xml;
70

    
71
        ar.add_create_auth(att.uid, att.gid, PoolObjectSQL::IMAGE, tmpl->to_xml(t_xml));
72
    }
73

    
74
    if ( vtmpl != 0 )
75
    {
76
        VirtualMachine::set_auth_request(att.uid, ar, vtmpl);
77
    }
78

    
79
    if ( ds_perm != 0 )
80
    {
81
        ar.add_auth(AuthRequest::USE, *ds_perm);
82
    }
83

    
84
    if (UserPool::authorize(ar) == -1)
85
    {
86
        failure_response(AUTHORIZATION,
87
                authorization_error(ar.message, att),
88
                att);
89

    
90
        return false;
91
    }
92

    
93
    return true;
94
}
95

    
96
/* -------------------------------------------------------------------------- */
97
/* -------------------------------------------------------------------------- */
98

    
99
bool RequestManagerVirtualMachine::quota_resize_authorization(
100
        int                 oid,
101
        Template *          deltas,
102
        RequestAttributes&  att)
103
{
104
    PoolObjectAuth      vm_perms;
105
    VirtualMachine *    vm = Nebula::instance().get_vmpool()->get(oid, true);
106

    
107
    if (vm == 0)
108
    {
109
        failure_response(NO_EXISTS,
110
                get_error(object_name(PoolObjectSQL::VM),oid),
111
                att);
112

    
113
        return false;
114
    }
115

    
116
    vm->get_permissions(vm_perms);
117

    
118
    vm->unlock();
119

    
120
    return quota_resize_authorization(deltas, att, vm_perms);
121
}
122

    
123
/* -------------------------------------------------------------------------- */
124
/* -------------------------------------------------------------------------- */
125

    
126
bool RequestManagerVirtualMachine::quota_resize_authorization(
127
        Template *          deltas,
128
        RequestAttributes&  att,
129
        PoolObjectAuth&     vm_perms)
130
{
131
    int rc;
132

    
133
    string   error_str;
134

    
135
    Nebula&    nd    = Nebula::instance();
136
    UserPool*  upool = nd.get_upool();
137
    GroupPool* gpool = nd.get_gpool();
138

    
139
    DefaultQuotas user_dquotas  = nd.get_default_user_quota();
140
    DefaultQuotas group_dquotas = nd.get_default_group_quota();
141

    
142
    if (vm_perms.uid != UserPool::ONEADMIN_ID)
143
    {
144
        User * user  = upool->get(vm_perms.uid, true);
145

    
146
        if ( user != 0 )
147
        {
148
            rc = user->quota.quota_update(Quotas::VM, deltas, user_dquotas, error_str);
149

    
150
            if (rc == false)
151
            {
152
                ostringstream oss;
153

    
154
                oss << object_name(PoolObjectSQL::USER)
155
                    << " [" << vm_perms.uid << "] "
156
                    << error_str;
157

    
158
                failure_response(AUTHORIZATION,
159
                        request_error(oss.str(), ""),
160
                        att);
161

    
162
                user->unlock();
163

    
164
                return false;
165
            }
166

    
167
            upool->update_quotas(user);
168

    
169
            user->unlock();
170
        }
171
    }
172

    
173
    if (vm_perms.gid != GroupPool::ONEADMIN_ID)
174
    {
175
        Group * group  = gpool->get(vm_perms.gid, true);
176

    
177
        if ( group != 0 )
178
        {
179
            rc = group->quota.quota_update(Quotas::VM, deltas, group_dquotas, error_str);
180

    
181
            if (rc == false)
182
            {
183
                ostringstream oss;
184
                RequestAttributes att_tmp(vm_perms.uid, -1, att);
185

    
186
                oss << object_name(PoolObjectSQL::GROUP)
187
                    << " [" << vm_perms.gid << "] "
188
                    << error_str;
189

    
190
                failure_response(AUTHORIZATION,
191
                                 request_error(oss.str(), ""),
192
                                 att);
193

    
194
                group->unlock();
195

    
196
                quota_rollback(deltas, Quotas::VM, att_tmp);
197

    
198
                return false;
199
            }
200

    
201
            gpool->update_quotas(group);
202

    
203
            group->unlock();
204
        }
205
    }
206

    
207
    return true;
208
}
209

    
210
/* -------------------------------------------------------------------------- */
211
/* -------------------------------------------------------------------------- */
212

    
213
int RequestManagerVirtualMachine::get_default_ds_information(
214
    int cluster_id,
215
    int& ds_id,
216
    string& tm_mad,
217
    RequestAttributes& att)
218
{
219
    Nebula& nd = Nebula::instance();
220

    
221
    ClusterPool*    clpool = nd.get_clpool();
222
    Cluster*        cluster;
223

    
224
    ds_id = -1;
225

    
226
    if (cluster_id == ClusterPool::NONE_CLUSTER_ID)
227
    {
228
        ds_id = DatastorePool::SYSTEM_DS_ID;
229
    }
230
    else
231
    {
232
        cluster = clpool->get(cluster_id, true);
233

    
234
        if (cluster == 0)
235
        {
236
            failure_response(NO_EXISTS,
237
                get_error(object_name(PoolObjectSQL::CLUSTER), cluster_id),
238
                att);
239

    
240
            return -1;
241
        }
242

    
243
        set<int> ds_ids = cluster->get_datastores();
244

    
245
        cluster->unlock();
246

    
247
        ds_id = Cluster::get_default_sysetm_ds(ds_ids);
248

    
249
        if (ds_id == -1)
250
        {
251
            ostringstream oss;
252

    
253
            oss << object_name(PoolObjectSQL::CLUSTER)
254
                << " [" << cluster_id << "] does not have any "
255
                << object_name(PoolObjectSQL::DATASTORE) << " of type "
256
                << Datastore::type_to_str(Datastore::SYSTEM_DS) << ".";
257

    
258
            failure_response(ACTION, request_error(oss.str(),""), att);
259

    
260
            return -1;
261
        }
262
    }
263

    
264
    return get_ds_information(ds_id, cluster_id, tm_mad, att);
265
}
266

    
267
/* -------------------------------------------------------------------------- */
268
/* -------------------------------------------------------------------------- */
269

    
270
int RequestManagerVirtualMachine::get_ds_information(int ds_id,
271
    int& ds_cluster_id,
272
    string& tm_mad,
273
    RequestAttributes& att)
274
{
275
    Nebula& nd = Nebula::instance();
276

    
277
    Datastore * ds = nd.get_dspool()->get(ds_id, true);
278

    
279
    ds_cluster_id = -1;
280

    
281
    if ( ds == 0 )
282
    {
283
        failure_response(NO_EXISTS,
284
            get_error(object_name(PoolObjectSQL::DATASTORE), ds_id),
285
            att);
286

    
287
        return -1;
288
    }
289

    
290
    if ( ds->get_type() != Datastore::SYSTEM_DS )
291
    {
292
        ostringstream oss;
293

    
294
        oss << "Trying to use " << object_name(PoolObjectSQL::DATASTORE)
295
            << " [" << ds_id << "] to deploy the VM, but it is not of type"
296
            << " system datastore.";
297

    
298
        failure_response(INTERNAL, request_error(oss.str(),""), att);
299

    
300
        ds->unlock();
301

    
302
        return -1;
303
    }
304

    
305
    ds_cluster_id = ds->get_cluster_id();
306

    
307
    tm_mad = ds->get_tm_mad();
308

    
309
    ds->unlock();
310

    
311
    return 0;
312
}
313

    
314

    
315
/* -------------------------------------------------------------------------- */
316
/* -------------------------------------------------------------------------- */
317

    
318
int RequestManagerVirtualMachine::get_host_information(
319
    int     hid,
320
    string& name,
321
    string& vmm,
322
    string& vnm,
323
    int&    cluster_id,
324
    string& ds_location,
325
    bool&   is_public_cloud,
326
    PoolObjectAuth&    host_perms,
327
    RequestAttributes& att)
328

    
329

    
330
{
331
    Nebula&    nd    = Nebula::instance();
332
    HostPool * hpool = nd.get_hpool();
333

    
334
    Host *     host  = hpool->get(hid,true);
335

    
336
    if ( host == 0 )
337
    {
338
        failure_response(NO_EXISTS,
339
                get_error(object_name(PoolObjectSQL::HOST),hid),
340
                att);
341

    
342
        return -1;
343
    }
344

    
345
    name = host->get_name();
346
    vmm  = host->get_vmm_mad();
347
    vnm  = host->get_vnm_mad();
348

    
349
    cluster_id = host->get_cluster_id();
350

    
351
    is_public_cloud = host->is_public_cloud();
352

    
353
    host->get_permissions(host_perms);
354

    
355
    host->unlock();
356

    
357
    if (nd.get_ds_location(cluster_id, ds_location) == -1)
358
    {
359
        failure_response(NO_EXISTS,
360
            get_error(object_name(PoolObjectSQL::CLUSTER),cluster_id),
361
            att);
362

    
363
        return -1;
364
    }
365

    
366
    return 0;
367
}
368

    
369
/* -------------------------------------------------------------------------- */
370
/* -------------------------------------------------------------------------- */
371

    
372
bool RequestManagerVirtualMachine::check_host(int     hid,
373
                                              int     cpu,
374
                                              int     mem,
375
                                              int     disk,
376
                                              string& error)
377
{
378
    Nebula&    nd    = Nebula::instance();
379
    HostPool * hpool = nd.get_hpool();
380

    
381
    Host * host;
382
    bool   test;
383

    
384
    host = hpool->get(hid, true);
385

    
386
    if (host == 0)
387
    {
388
        error = "Host no longer exists";
389
        return false;
390
    }
391

    
392
    test = host->test_capacity(cpu, mem, disk);
393

    
394
    if (!test)
395
    {
396
        ostringstream oss;
397

    
398
        oss << object_name(PoolObjectSQL::HOST)
399
            << " " << hid << " does not have enough capacity.";
400

    
401
        error = oss.str();
402
    }
403

    
404
    host->unlock();
405

    
406
    return test;
407
}
408

    
409
/* -------------------------------------------------------------------------- */
410
/* -------------------------------------------------------------------------- */
411

    
412
VirtualMachine * RequestManagerVirtualMachine::get_vm(int id,
413
                                                      RequestAttributes& att)
414
{
415
    VirtualMachine * vm;
416

    
417
    vm = static_cast<VirtualMachine *>(pool->get(id,true));
418

    
419
    if ( vm == 0 )
420
    {
421
        failure_response(NO_EXISTS,get_error(object_name(auth_object),id), att);
422
        return 0;
423
    }
424

    
425
    return vm;
426
}
427

    
428
/* -------------------------------------------------------------------------- */
429
/* -------------------------------------------------------------------------- */
430

    
431
int RequestManagerVirtualMachine::add_history(VirtualMachine * vm,
432
                                       int              hid,
433
                                       int              cid,
434
                                       const string&    hostname,
435
                                       const string&    vmm_mad,
436
                                       const string&    vnm_mad,
437
                                       const string&    tm_mad,
438
                                       const string&    ds_location,
439
                                       int              ds_id,
440
                                       RequestAttributes& att)
441
{
442
    string  vmdir;
443
    int     rc;
444

    
445
    VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
446

    
447
    vm->add_history(hid, cid, hostname, vmm_mad, vnm_mad, tm_mad, ds_location, ds_id);
448

    
449
    rc = vmpool->update_history(vm);
450

    
451
    if ( rc != 0 )
452
    {
453
        failure_response(INTERNAL,
454
                request_error("Cannot update virtual machine history",""),
455
                att);
456

    
457
        return -1;
458
    }
459

    
460
    vmpool->update(vm);
461

    
462
    return 0;
463
}
464

    
465
/* -------------------------------------------------------------------------- */
466
/* -------------------------------------------------------------------------- */
467

    
468
void VirtualMachineAction::request_execute(xmlrpc_c::paramList const& paramList,
469
                                           RequestAttributes& att)
470
{
471
    string action_st = xmlrpc_c::value_string(paramList.getString(1));
472
    int    id        = xmlrpc_c::value_int(paramList.getInt(2));
473

    
474
    int    rc;
475

    
476
    Nebula& nd = Nebula::instance();
477
    DispatchManager * dm = nd.get_dm();
478

    
479
    ostringstream oss;
480

    
481
    AuthRequest::Operation op = auth_op;
482
    History::VMAction action;
483

    
484
    VirtualMachine * vm;
485

    
486
    // Compatibility with 3.8
487
    if (action_st == "cancel")
488
    {
489
        action_st = "shutdown-hard";
490
    }
491
    else if (action_st == "restart")
492
    {
493
        action_st = "boot";
494
    }
495
    else if (action_st == "finalize")
496
    {
497
        action_st = "delete";
498
    }
499
    else if (action_st == "resubmit")
500
    {
501
        action_st = "delete-recreate";
502
    }
503
    else if (action_st == "reset")
504
    {
505
        action_st = "reboot-hard";
506
    }
507

    
508
    History::action_from_str(action_st, action);
509

    
510
    if (action == History::RESCHED_ACTION || action == History::UNRESCHED_ACTION)
511
    {
512
        op = AuthRequest::ADMIN;
513
    }
514

    
515
    if ( vm_authorization(id, 0, 0, att, 0, 0, op) == false )
516
    {
517
        return;
518
    }
519

    
520
    if ((vm = get_vm(id, att)) == 0)
521
    {
522
        return;
523
    }
524

    
525
    if (vm->isImported() && (
526
        action == History::DELETE_RECREATE_ACTION ||
527
        action == History::UNDEPLOY_ACTION ||
528
        action == History::UNDEPLOY_HARD_ACTION ||
529
        action == History::STOP_ACTION))
530
    {
531
        oss << "Action \"" << action_st << "\" is not supported for imported VMs";
532

    
533
        failure_response(ACTION,
534
                request_error(oss.str(),""),
535
                att);
536

    
537
        vm->unlock();
538
        return;
539
    }
540

    
541
    vm->unlock();
542

    
543
    switch (action)
544
    {
545
        case History::SHUTDOWN_ACTION:
546
            rc = dm->shutdown(id);
547
            break;
548
        case History::HOLD_ACTION:
549
            rc = dm->hold(id);
550
            break;
551
        case History::RELEASE_ACTION:
552
            rc = dm->release(id);
553
            break;
554
        case History::STOP_ACTION:
555
            rc = dm->stop(id);
556
            break;
557
        case History::SHUTDOWN_HARD_ACTION:
558
            rc = dm->cancel(id);
559
            break;
560
        case History::SUSPEND_ACTION:
561
            rc = dm->suspend(id);
562
            break;
563
        case History::RESUME_ACTION:
564
            rc = dm->resume(id);
565
            break;
566
        case History::BOOT_ACTION:
567
            rc = dm->restart(id);
568
            break;
569
        case History::DELETE_ACTION:
570
            rc = dm->finalize(id);
571
            break;
572
        case History::DELETE_RECREATE_ACTION:
573
            rc = dm->resubmit(id);
574
            break;
575
        case History::REBOOT_ACTION:
576
            rc = dm->reboot(id);
577
            break;
578
        case History::RESCHED_ACTION:
579
            rc = dm->resched(id, true);
580
            break;
581
        case History::UNRESCHED_ACTION:
582
            rc = dm->resched(id, false);
583
            break;
584
        case History::REBOOT_HARD_ACTION:
585
            rc = dm->reset(id);
586
            break;
587
        case History::POWEROFF_ACTION:
588
            rc = dm->poweroff(id, false);
589
            break;
590
        case History::POWEROFF_HARD_ACTION:
591
            rc = dm->poweroff(id, true);
592
            break;
593
        case History::UNDEPLOY_ACTION:
594
            rc = dm->undeploy(id, false);
595
            break;
596
        case History::UNDEPLOY_HARD_ACTION:
597
            rc = dm->undeploy(id, true);
598
            break;
599
        default:
600
            rc = -3;
601
            break;
602
    }
603

    
604
    switch (rc)
605
    {
606
        case 0:
607
            success_response(id, att);
608
            break;
609
        case -1:
610
            failure_response(NO_EXISTS,
611
                    get_error(object_name(auth_object),id),
612
                    att);
613
            break;
614
        case -2:
615
            oss << "Wrong state to perform action \"" << action_st << "\"";
616

    
617
            failure_response(ACTION,
618
                    request_error(oss.str(),""),
619
                    att);
620
             break;
621
        case -3:
622
            oss << "Virtual machine action \"" << action_st
623
                << "\" is not supported";
624

    
625
            failure_response(ACTION,
626
                    request_error(oss.str(),""),
627
                    att);
628
            break;
629
        default:
630
            failure_response(INTERNAL,
631
                    request_error("Internal error","Action result not defined"),
632
                    att);
633
    }
634

    
635
    return;
636
}
637

    
638
/* -------------------------------------------------------------------------- */
639
/* -------------------------------------------------------------------------- */
640

    
641
void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList,
642
                                           RequestAttributes& att)
643
{
644
    Nebula&             nd = Nebula::instance();
645
    DispatchManager *   dm = nd.get_dm();
646
    DatastorePool * dspool = nd.get_dspool();
647

    
648
    VirtualMachine * vm;
649

    
650
    string hostname;
651
    string vmm_mad;
652
    string vnm_mad;
653
    int    cluster_id;
654
    string ds_location;
655
    bool   is_public_cloud;
656

    
657
    PoolObjectAuth host_perms, ds_perms;
658
    PoolObjectAuth * auth_ds_perms;
659

    
660
    string tm_mad;
661

    
662
    bool auth = false;
663

    
664
    // ------------------------------------------------------------------------
665
    // Get request parameters and information about the target host
666
    // ------------------------------------------------------------------------
667

    
668
    int  id      = xmlrpc_c::value_int(paramList.getInt(1));
669
    int  hid     = xmlrpc_c::value_int(paramList.getInt(2));
670
    bool enforce = false;
671
    int  ds_id   = -1;
672

    
673
    if ( paramList.size() > 3 )
674
    {
675
        enforce = xmlrpc_c::value_boolean(paramList.getBoolean(3));
676
    }
677

    
678
    if ( paramList.size() > 4 )
679
    {
680
        ds_id = xmlrpc_c::value_int(paramList.getInt(4));
681
    }
682

    
683
    if (get_host_information(hid,
684
                             hostname,
685
                             vmm_mad,
686
                             vnm_mad,
687
                             cluster_id,
688
                             ds_location,
689
                             is_public_cloud,
690
                             host_perms,
691
                             att) != 0)
692
    {
693
        return;
694
    }
695

    
696
    // ------------------------------------------------------------------------
697
    // Get information about the system DS to use (tm_mad & permissions)
698
    // ------------------------------------------------------------------------
699

    
700
    if ((vm = get_vm(id, att)) == 0)
701
    {
702
        return;
703
    }
704

    
705
    if (vm->hasHistory() &&
706
        (vm->get_action() == History::STOP_ACTION ||
707
         vm->get_action() == History::UNDEPLOY_ACTION ||
708
         vm->get_action() == History::UNDEPLOY_HARD_ACTION))
709
    {
710
        ds_id = vm->get_ds_id();
711
    }
712

    
713
    vm->unlock();
714

    
715
    if (is_public_cloud) // Set ds_id to -1 and tm_mad empty(). This is used by
716
    {                    // by VirtualMachine::get_host_is_cloud()
717
        ds_id  = -1;
718
        tm_mad = "";
719
    }
720
    else
721
    {
722
        if ( ds_id == -1 ) //Use default system DS for cluster
723
        {
724
            if (get_default_ds_information(cluster_id, ds_id, tm_mad, att) != 0)
725
            {
726
                return;
727
            }
728
        }
729
        else //Get information from user selected system DS
730
        {
731
            int ds_cluster_id;
732

    
733
            if (get_ds_information(ds_id, ds_cluster_id, tm_mad, att) != 0)
734
            {
735
                return;
736
            }
737

    
738
            if (ds_cluster_id != cluster_id)
739
            {
740
                ostringstream oss;
741

    
742
                oss << object_name(PoolObjectSQL::DATASTORE)
743
                    << " [" << ds_id << "] and " << object_name(PoolObjectSQL::HOST)
744
                    << " [" << hid <<"] are not in the same cluster.";
745

    
746
                failure_response(ACTION, request_error(oss.str(),""), att);
747

    
748
                return;
749
            }
750
        }
751
    }
752

    
753
    if (ds_id == -1)
754
    {
755
       auth_ds_perms = 0;
756
    }
757
    else
758
    {
759
        Datastore * ds = dspool->get(ds_id, true);
760

    
761
        if (ds == 0 )
762
        {
763
            failure_response(NO_EXISTS,
764
                get_error(object_name(PoolObjectSQL::DATASTORE), ds_id),
765
                att);
766

    
767
            return;
768
        }
769

    
770
        ds->get_permissions(ds_perms);
771

    
772
        ds->unlock();
773

    
774
        auth_ds_perms = &ds_perms;
775
    }
776

    
777
    // ------------------------------------------------------------------------
778
    // Authorize request
779
    // ------------------------------------------------------------------------
780

    
781
    auth = vm_authorization(id, 0, 0, att, &host_perms, auth_ds_perms, auth_op);
782

    
783
    if (auth == false)
784
    {
785
        return;
786
    }
787

    
788
    // ------------------------------------------------------------------------
789
    // Check request consistency:
790
    // - VM States are right
791
    // - Host capacity if required
792
    // ------------------------------------------------------------------------
793

    
794
    if ((vm = get_vm(id, att)) == 0)
795
    {
796
        return;
797
    }
798

    
799
    if (vm->get_state() != VirtualMachine::PENDING &&
800
        vm->get_state() != VirtualMachine::HOLD &&
801
        vm->get_state() != VirtualMachine::STOPPED &&
802
        vm->get_state() != VirtualMachine::UNDEPLOYED)
803
    {
804
        failure_response(ACTION,
805
                request_error("Wrong state to perform action",""),
806
                att);
807

    
808
        vm->unlock();
809
        return;
810
    }
811

    
812
    if (enforce)
813
    {
814
        int    cpu, mem, disk;
815
        string error;
816

    
817
        vm->get_requirements(cpu, mem, disk);
818

    
819
        vm->unlock();
820

    
821
        if (check_host(hid, cpu, mem, disk, error) == false)
822
        {
823
            failure_response(ACTION, request_error(error,""), att);
824
            return;
825
        }
826

    
827
        if ((vm = get_vm(id, att)) == 0)
828
        {
829
            return;
830
        }
831
    }
832

    
833
    // ------------------------------------------------------------------------
834
    // Add a new history record and deploy the VM
835
    // ------------------------------------------------------------------------
836

    
837
    if (add_history(vm,
838
                    hid,
839
                    cluster_id,
840
                    hostname,
841
                    vmm_mad,
842
                    vnm_mad,
843
                    tm_mad,
844
                    ds_location,
845
                    ds_id,
846
                    att) != 0)
847
    {
848
        vm->unlock();
849
        return;
850
    }
851

    
852
    if (vm->isImported())
853
    {
854
        dm->import(vm);
855
    }
856
    else
857
    {
858
        dm->deploy(vm);
859
    }
860

    
861
    vm->unlock();
862

    
863
    success_response(id, att);
864
}
865

    
866
/* -------------------------------------------------------------------------- */
867
/* -------------------------------------------------------------------------- */
868

    
869
void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList,
870
                                            RequestAttributes& att)
871
{
872
    Nebula&             nd = Nebula::instance();
873
    DispatchManager *   dm = nd.get_dm();
874

    
875
    VirtualMachine * vm;
876

    
877
    string hostname;
878
    string vmm_mad;
879
    string vnm_mad;
880
    int    cluster_id;
881
    string ds_location;
882
    bool   is_public_cloud;
883
    PoolObjectAuth host_perms;
884

    
885
    int    c_hid;
886
    int    c_cluster_id;
887
    int    c_ds_id;
888
    string c_tm_mad;
889
    bool   c_is_public_cloud;
890

    
891
    bool auth = false;
892

    
893
    // ------------------------------------------------------------------------
894
    // Get request parameters and information about the target host
895
    // ------------------------------------------------------------------------
896

    
897
    int  id      = xmlrpc_c::value_int(paramList.getInt(1));
898
    int  hid     = xmlrpc_c::value_int(paramList.getInt(2));
899
    bool live    = xmlrpc_c::value_boolean(paramList.getBoolean(3));
900
    bool enforce = false;
901

    
902
    if ( paramList.size() > 4 )
903
    {
904
        enforce = xmlrpc_c::value_boolean(paramList.getBoolean(4));
905
    }
906

    
907
    if (get_host_information(hid,
908
                             hostname,
909
                             vmm_mad,
910
                             vnm_mad,
911
                             cluster_id,
912
                             ds_location,
913
                             is_public_cloud,
914
                             host_perms,
915
                             att) != 0)
916
    {
917
        return;
918
    }
919

    
920
    // ------------------------------------------------------------------------
921
    // Authorize request
922
    // ------------------------------------------------------------------------
923

    
924
    auth = vm_authorization(id, 0, 0, att, &host_perms, 0, auth_op);
925

    
926
    if (auth == false)
927
    {
928
        return;
929
    }
930

    
931
    // ------------------------------------------------------------------------
932
    // Check request consistency:
933
    // - VM States are right and there is at least a history record
934
    // - New host is not the current one
935
    // - Host capacity if required
936
    // - New host and current one are in the same cluster
937
    // - New or old host are not public cloud
938
    // ------------------------------------------------------------------------
939

    
940
    if ((vm = get_vm(id, att)) == 0)
941
    {
942
        return;
943
    }
944

    
945
    if((vm->get_state()     != VirtualMachine::ACTIVE)  ||
946
       (vm->get_lcm_state() != VirtualMachine::RUNNING &&
947
        vm->get_lcm_state() != VirtualMachine::UNKNOWN) ||
948
       (vm->hasPreviousHistory() && vm->get_previous_reason() == History::NONE))
949
    {
950
        failure_response(ACTION,
951
                request_error("Wrong state to perform action",""),
952
                att);
953

    
954
        vm->unlock();
955
        return;
956
    }
957

    
958
    if (vm->isImported())
959
    {
960
        failure_response(ACTION,
961
                request_error("Migration is not supported for imported VMs",""),
962
                att);
963

    
964
        vm->unlock();
965
        return;
966
    }
967

    
968
    // Check we are not migrating to the same host
969

    
970
    c_hid = vm->get_hid();
971

    
972
    if (c_hid == hid)
973
    {
974
        ostringstream oss;
975

    
976
        oss << "VM is already running on "
977
            << object_name(PoolObjectSQL::HOST) << " [" << c_hid << "]";
978

    
979
        failure_response(ACTION,
980
                request_error(oss.str(),""),
981
                att);
982

    
983
        vm->unlock();
984
        return;
985
    }
986

    
987
    // Get System DS information from current History record
988
    c_ds_id  = vm->get_ds_id();
989
    c_tm_mad = vm->get_tm_mad();
990

    
991
    if (enforce)
992
    {
993
        int    cpu, mem, disk;
994
        string error;
995

    
996
        vm->get_requirements(cpu, mem, disk);
997

    
998
        vm->unlock();
999

    
1000
        if (check_host(hid, cpu, mem, disk, error) == false)
1001
        {
1002
            failure_response(ACTION, request_error(error,""), att);
1003
            return;
1004
        }
1005
    }
1006
    else
1007
    {
1008
        vm->unlock();
1009
    }
1010

    
1011
    // Check we are in the same cluster
1012

    
1013
    Host * host = nd.get_hpool()->get(c_hid, true);
1014

    
1015
    if (host == 0)
1016
    {
1017
        failure_response(NO_EXISTS,
1018
                get_error(object_name(PoolObjectSQL::HOST), c_hid),
1019
                att);
1020
    }
1021

    
1022
    c_cluster_id = host->get_cluster_id();
1023

    
1024
    c_is_public_cloud = host->is_public_cloud();
1025

    
1026
    host->unlock();
1027

    
1028
    if ( c_cluster_id != cluster_id )
1029
    {
1030
        ostringstream oss;
1031

    
1032
        oss << "Cannot migrate to a different cluster. VM running in a host"
1033
            << " in " << object_name(PoolObjectSQL::CLUSTER) << " ["
1034
            << c_cluster_id << "] , and new host is in "
1035
            << object_name(PoolObjectSQL::CLUSTER) << " [" << cluster_id << "]";
1036

    
1037
        failure_response(ACTION,
1038
                request_error(oss.str(),""),
1039
                att);
1040

    
1041
        return;
1042
    }
1043

    
1044
    if ( is_public_cloud || c_is_public_cloud )
1045
    {
1046
        failure_response(ACTION,
1047
                request_error("Cannot migrate to or from a Public Cloud Host",""),
1048
                att);
1049

    
1050
        return;
1051
    }
1052

    
1053
    // ------------------------------------------------------------------------
1054
    // Add a new history record and migrate the VM
1055
    // ------------------------------------------------------------------------
1056

    
1057
    if ( (vm = get_vm(id, att)) == 0 )
1058
    {
1059
        return;
1060
    }
1061

    
1062
    if (add_history(vm,
1063
                    hid,
1064
                    cluster_id,
1065
                    hostname,
1066
                    vmm_mad,
1067
                    vnm_mad,
1068
                    c_tm_mad,
1069
                    ds_location,
1070
                    c_ds_id,
1071
                    att) != 0)
1072
    {
1073
        vm->unlock();
1074
        return;
1075
    }
1076

    
1077
    if (live == true && vm->get_lcm_state() == VirtualMachine::RUNNING )
1078
    {
1079
        dm->live_migrate(vm);
1080
    }
1081
    else
1082
    {
1083
        dm->migrate(vm);
1084
    }
1085

    
1086
    vm->unlock();
1087

    
1088
    success_response(id, att);
1089
}
1090

    
1091
/* -------------------------------------------------------------------------- */
1092
/* -------------------------------------------------------------------------- */
1093

    
1094
void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramList,
1095
                                             RequestAttributes& att)
1096
{
1097
    Nebula& nd  = Nebula::instance();
1098

    
1099
    ImagePool *     ipool  = nd.get_ipool();
1100
    DatastorePool * dspool = nd.get_dspool();
1101
    VMTemplatePool* tpool  = nd.get_tpool();
1102

    
1103
    int    id          = xmlrpc_c::value_int(paramList.getInt(1));
1104
    int    disk_id     = xmlrpc_c::value_int(paramList.getInt(2));
1105
    string img_name    = xmlrpc_c::value_string(paramList.getString(3));
1106
    string img_type    = xmlrpc_c::value_string(paramList.getString(4));
1107
    bool   is_hot      = false; //Optional XML-RPC argument
1108
    bool   do_template = false; //Optional XML-RPC argument
1109

    
1110
    if ( paramList.size() > 5 )
1111
    {
1112
        is_hot = xmlrpc_c::value_boolean(paramList.getBoolean(5));
1113
    }
1114

    
1115
    if ( paramList.size() > 6 )
1116
    {
1117
        do_template = xmlrpc_c::value_boolean(paramList.getBoolean(6));
1118
    }
1119

    
1120
    VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
1121
    VirtualMachine * vm;
1122
    Datastore      * ds;
1123
    int              iid;
1124
    int              tid;
1125

    
1126
    string error_str;
1127

    
1128
    string driver;
1129
    string target;
1130
    string dev_prefix;
1131

    
1132
    // -------------------------------------------------------------------------
1133
    // Prepare and check the VM/DISK to be saved_as
1134
    // -------------------------------------------------------------------------
1135
    if ((vm = get_vm(id, att)) == 0)
1136
    {
1137
        return;
1138
    }
1139

    
1140
    if ( vm->set_saveas_state(disk_id, is_hot) != 0 )
1141
    {
1142
        vm->unlock();
1143

    
1144
        failure_response(INTERNAL,
1145
                         request_error("VM has to be RUNNING, POWEROFF or"
1146
                         " SUSPENDED to snapshot disks.",""), att);
1147
        return;
1148
    }
1149

    
1150
    int iid_orig = vm->get_image_from_disk(disk_id, is_hot, error_str);
1151

    
1152
    if ( iid_orig == -1 )
1153
    {
1154
        vm->clear_saveas_state(disk_id, is_hot);
1155

    
1156
        vm->unlock();
1157

    
1158
        failure_response(INTERNAL,
1159
                         request_error("Cannot use selected DISK", error_str),
1160
                         att);
1161
        return;
1162
    }
1163

    
1164
    if (do_template && !vm->get_template_attribute("TEMPLATE_ID",tid))
1165
    {
1166
        vm->clear_saveas_state(disk_id, is_hot);
1167

    
1168
        vm->unlock();
1169

    
1170
        failure_response(ACTION,
1171
                         request_error("VM has no template to be saved",""),
1172
                         att);
1173
        return;
1174
    }
1175

    
1176
    vmpool->update(vm);
1177

    
1178
    vm->unlock();
1179

    
1180
    // -------------------------------------------------------------------------
1181
    // Get the data of the Image to be saved
1182
    // -------------------------------------------------------------------------
1183
    Image * img = ipool->get(iid_orig, true);
1184

    
1185
    if ( img == 0 )
1186
    {
1187
        failure_response(NO_EXISTS,
1188
                         get_error(object_name(PoolObjectSQL::IMAGE), iid_orig),
1189
                         att);
1190

    
1191
        if ((vm = vmpool->get(id, true)) != 0)
1192
        {
1193
            vm->clear_saveas_state(disk_id, is_hot);
1194

    
1195
            vmpool->update(vm);
1196
            vm->unlock();
1197
        }
1198

    
1199
        return;
1200
    }
1201

    
1202
    int       ds_id   = img->get_ds_id();
1203
    string    ds_name = img->get_ds_name();
1204
    long long size    = img->get_size();
1205

    
1206
    string iname_orig  = img->get_name();
1207
    string iuname_orig = img->get_uname();
1208
    Image::ImageType type = img->get_type();
1209

    
1210
    img->get_template_attribute("DRIVER", driver);
1211
    img->get_template_attribute("TARGET", target);
1212
    img->get_template_attribute("DEV_PREFIX", dev_prefix);
1213

    
1214
    img->unlock();
1215

    
1216
    switch (type)
1217
    {
1218
        case Image::OS:
1219
        case Image::DATABLOCK:
1220
        case Image::CDROM:
1221
        break;
1222

    
1223
        case Image::KERNEL:
1224
        case Image::RAMDISK:
1225
        case Image::CONTEXT:
1226
            failure_response(INTERNAL,
1227
                    request_error("Cannot save_as image of type " +
1228
                    Image::type_to_str(type), ""), att);
1229
        return;
1230
    }
1231

    
1232
    // -------------------------------------------------------------------------
1233
    // Get the data of the DataStore for the new image
1234
    // -------------------------------------------------------------------------
1235
    if ((ds = dspool->get(ds_id, true)) == 0 )
1236
    {
1237
        failure_response(NO_EXISTS,
1238
                get_error(object_name(PoolObjectSQL::DATASTORE), ds_id),
1239
                att);
1240

    
1241
        if ((vm = vmpool->get(id, true)) != 0)
1242
        {
1243
            vm->clear_saveas_state(disk_id, is_hot);
1244

    
1245
            vmpool->update(vm);
1246
            vm->unlock();
1247
        }
1248

    
1249
        return;
1250
    }
1251

    
1252
    string         ds_data;
1253
    PoolObjectAuth ds_perms;
1254
    long long      avail;
1255
    bool           ds_check;
1256

    
1257
    ds->get_permissions(ds_perms);
1258
    ds->to_xml(ds_data);
1259

    
1260
    ds_check = ds->get_avail_mb(avail);
1261

    
1262
    Image::DiskType ds_disk_type = ds->get_disk_type();
1263

    
1264
    ds->unlock();
1265

    
1266
    // -------------------------------------------------------------------------
1267
    // Check Datastore Capacity
1268
    // -------------------------------------------------------------------------
1269
    if (ds_check && (size > avail))
1270
    {
1271
        failure_response(ACTION, "Not enough space in datastore", att);
1272

    
1273
        if ((vm = vmpool->get(id, true)) != 0)
1274
        {
1275
            vm->clear_saveas_state(disk_id, is_hot);
1276

    
1277
            vmpool->update(vm);
1278
            vm->unlock();
1279
        }
1280

    
1281
        return;
1282
    }
1283

    
1284
    // -------------------------------------------------------------------------
1285
    // Create a template for the new Image
1286
    // -------------------------------------------------------------------------
1287
    ImageTemplate * itemplate = new ImageTemplate;
1288
    Template        img_usage;
1289

    
1290
    itemplate->add("NAME", img_name);
1291
    itemplate->add("SIZE", size);
1292

    
1293
    itemplate->add("SAVED_IMAGE_ID",iid_orig);
1294
    itemplate->add("SAVED_DISK_ID",disk_id);
1295
    itemplate->add("SAVED_VM_ID", id);
1296

    
1297
    itemplate->set_saving();
1298

    
1299
    if ( is_hot )
1300
    {
1301
        itemplate->set_saving_hot();
1302
    }
1303

    
1304
    if ( img_type.empty() )
1305
    {
1306
        itemplate->add("TYPE", Image::type_to_str(type));
1307
    }
1308
    else
1309
    {
1310
        itemplate->add("TYPE", img_type);
1311
    }
1312

    
1313
    if ( driver.empty() == false )
1314
    {
1315
        itemplate->add("DRIVER", driver);
1316
    }
1317

    
1318
    if ( target.empty() == false )
1319
    {
1320
        itemplate->add("TARGET", target);
1321
    }
1322

    
1323
    if ( dev_prefix.empty() == false )
1324
    {
1325
        itemplate->add("DEV_PREFIX", dev_prefix);
1326
    }
1327

    
1328
    img_usage.add("SIZE",      size);
1329
    img_usage.add("DATASTORE", ds_id);
1330

    
1331
    // -------------------------------------------------------------------------
1332
    // Authorize the operation & check quotas
1333
    // -------------------------------------------------------------------------
1334
    bool rc_auth = vm_authorization(id, itemplate, 0, att, 0,&ds_perms,auth_op);
1335

    
1336
    if ( rc_auth == true )
1337
    {
1338
        rc_auth = quota_authorization(&img_usage, Quotas::DATASTORE, att);
1339
    }
1340

    
1341
    if ( rc_auth == false)
1342
    {
1343
        delete itemplate;
1344

    
1345
        if ((vm = vmpool->get(id, true)) != 0)
1346
        {
1347
            vm->clear_saveas_state(disk_id, is_hot);
1348

    
1349
            vmpool->update(vm);
1350
            vm->unlock();
1351
        }
1352

    
1353
        return;
1354
    }
1355

    
1356
    // -------------------------------------------------------------------------
1357
    // Create the image
1358
    // -------------------------------------------------------------------------
1359
    int rc = ipool->allocate(att.uid,
1360
                             att.gid,
1361
                             att.uname,
1362
                             att.gname,
1363
                             att.umask,
1364
                             itemplate,
1365
                             ds_id,
1366
                             ds_name,
1367
                             ds_disk_type,
1368
                             ds_data,
1369
                             Datastore::IMAGE_DS,
1370
                             -1,
1371
                             &iid,
1372
                             error_str);
1373
    if (rc < 0)
1374
    {
1375
        quota_rollback(&img_usage, Quotas::DATASTORE, att);
1376

    
1377
        if ((vm = vmpool->get(id, true)) != 0)
1378
        {
1379
            vm->clear_saveas_state(disk_id, is_hot);
1380

    
1381
            vmpool->update(vm);
1382
            vm->unlock();
1383
        }
1384

    
1385
        failure_response(INTERNAL,
1386
                allocate_error(PoolObjectSQL::IMAGE, error_str), att);
1387
        return;
1388
    }
1389

    
1390
    ds = dspool->get(ds_id, true);
1391

    
1392
    if ( ds != 0 )  // TODO: error otherwise or leave image in ERROR?
1393
    {
1394
        ds->add_image(iid);
1395

    
1396
        dspool->update(ds);
1397

    
1398
        ds->unlock();
1399
    }
1400

    
1401
    // Return the new allocated Image ID
1402
    if (!do_template)
1403
    {
1404
        success_response(iid, att);
1405
        return;
1406
    }
1407

    
1408
    // -------------------------------------------------------------------------
1409
    // Clone original template and replace disk with saved one
1410
    // -------------------------------------------------------------------------
1411
    int ntid;
1412

    
1413
    PoolObjectAuth perms;
1414
    VMTemplate *   vm_tmpl = tpool->get(tid,true);
1415

    
1416
    if ( vm_tmpl == 0 ) //Failed to get original template return saved image id
1417
    {
1418
        ostringstream error;
1419

    
1420
        error << get_error(object_name(PoolObjectSQL::TEMPLATE), tid)
1421
              << "Image successfully saved with id: " << iid;
1422

    
1423
        failure_response(NO_EXISTS, error.str(), att);
1424
        return;
1425
    }
1426

    
1427
    VirtualMachineTemplate * tmpl = vm_tmpl->clone_template();
1428

    
1429
    vm_tmpl->get_permissions(perms);
1430

    
1431
    vm_tmpl->unlock();
1432

    
1433
    //Setup the new template: name and replace disk
1434

    
1435
    ostringstream tmpl_name;
1436

    
1437
    tmpl_name << img_name << "-" << iid;
1438

    
1439
    tmpl->replace("NAME", tmpl_name.str());
1440
    tmpl->replace("SAVED_TEMPLATE_ID", tid);
1441
    tmpl->replace("SAVED_TO_IMAGE_ID", iid);
1442

    
1443
    tmpl->replace_disk_image(iid_orig, iname_orig, iuname_orig, img_name, att.uname);
1444

    
1445
    //Authorize the template creation operation
1446

    
1447
    if ( att.uid != 0 )
1448
    {
1449
        string tmpl_str = "";
1450

    
1451
        AuthRequest ar(att.uid, att.group_ids);
1452

    
1453
        ar.add_auth(AuthRequest::USE, perms);
1454

    
1455
        tmpl->to_xml(tmpl_str);
1456

    
1457
        ar.add_create_auth(att.uid, att.gid, PoolObjectSQL::TEMPLATE, tmpl_str);
1458

    
1459
        if (UserPool::authorize(ar) == -1)
1460
        {
1461
            delete tmpl;
1462

    
1463
            ostringstream error;
1464

    
1465
            error << authorization_error(ar.message, att)
1466
                  << "Image successfully saved with id: " << iid;
1467

    
1468
            failure_response(AUTHORIZATION, error.str(), att);
1469

    
1470
            return;
1471
        }
1472
    }
1473

    
1474
    //Allocate the template
1475

    
1476
    rc = tpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask,
1477
                tmpl, &ntid, error_str);
1478

    
1479
    if (rc < 0)
1480
    {
1481
        ostringstream error;
1482

    
1483
        error << allocate_error(PoolObjectSQL::TEMPLATE, error_str)
1484
              << "Image successfully saved with id: " << iid;
1485

    
1486
        failure_response(INTERNAL, error.str(), att);
1487

    
1488
        return;
1489
    }
1490

    
1491
    success_response(iid, att);
1492
}
1493

    
1494
/* -------------------------------------------------------------------------- */
1495
/* -------------------------------------------------------------------------- */
1496

    
1497
void VirtualMachineMonitoring::request_execute(
1498
        xmlrpc_c::paramList const&  paramList,
1499
        RequestAttributes&          att)
1500
{
1501
    int  id = xmlrpc_c::value_int(paramList.getInt(1));
1502
    int  rc;
1503

    
1504
    ostringstream oss;
1505

    
1506
    bool auth = vm_authorization(id, 0, 0, att, 0, 0, auth_op);
1507

    
1508
    if ( auth == false )
1509
    {
1510
        return;
1511
    }
1512

    
1513
    rc = (static_cast<VirtualMachinePool *>(pool))->dump_monitoring(oss, id);
1514

    
1515
    if ( rc != 0 )
1516
    {
1517
        failure_response(INTERNAL,request_error("Internal Error",""), att);
1518
        return;
1519
    }
1520

    
1521
    success_response(oss.str(), att);
1522

    
1523
    return;
1524
}
1525

    
1526
/* -------------------------------------------------------------------------- */
1527
/* -------------------------------------------------------------------------- */
1528

    
1529
void VirtualMachineAttach::request_execute(xmlrpc_c::paramList const& paramList,
1530
                                            RequestAttributes& att)
1531
{
1532
    Nebula&           nd = Nebula::instance();
1533
    DispatchManager * dm = nd.get_dm();
1534

    
1535
    VirtualMachineTemplate * tmpl = new VirtualMachineTemplate();
1536
    VirtualMachineTemplate * deltas = 0;
1537
    PoolObjectAuth           vm_perms;
1538

    
1539
    VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
1540
    VirtualMachine *     vm;
1541

    
1542
    int    rc;
1543
    string error_str;
1544
    bool   volatile_disk;
1545

    
1546
    int     id       = xmlrpc_c::value_int(paramList.getInt(1));
1547
    string  str_tmpl = xmlrpc_c::value_string(paramList.getString(2));
1548

    
1549
    // -------------------------------------------------------------------------
1550
    // Parse Disk template
1551
    // -------------------------------------------------------------------------
1552

    
1553
    rc = tmpl->parse_str_or_xml(str_tmpl, error_str);
1554

    
1555
    if ( rc != 0 )
1556
    {
1557
        failure_response(INTERNAL, error_str, att);
1558
        delete tmpl;
1559

    
1560
        return;
1561
    }
1562

    
1563
    // -------------------------------------------------------------------------
1564
    // Authorize the operation & check quotas
1565
    // -------------------------------------------------------------------------
1566

    
1567
    if ( vm_authorization(id, 0, tmpl, att, 0, 0, auth_op) == false )
1568
    {
1569
        delete tmpl;
1570
        return;
1571
    }
1572

    
1573
    vm = vmpool->get(id, true);
1574

    
1575
    if (vm == 0)
1576
    {
1577
        failure_response(NO_EXISTS,
1578
                get_error(object_name(PoolObjectSQL::VM),id),
1579
                att);
1580
        return;
1581
    }
1582

    
1583
    vm->get_permissions(vm_perms);
1584

    
1585
    vm->unlock();
1586

    
1587
    RequestAttributes att_quota(vm_perms.uid, vm_perms.gid, att);
1588

    
1589
    volatile_disk = VirtualMachine::isVolatile(tmpl);
1590

    
1591
    if ( volatile_disk )
1592
    {
1593
        deltas = new VirtualMachineTemplate(*tmpl);
1594

    
1595
        deltas->add("VMS", 0);
1596

    
1597
        if (quota_resize_authorization(id, deltas, att_quota) == false)
1598
        {
1599
            delete tmpl;
1600
            delete deltas;
1601

    
1602
            return;
1603
        }
1604
    }
1605
    else
1606
    {
1607
        if ( quota_authorization(tmpl, Quotas::IMAGE, att_quota) == false )
1608
        {
1609
            delete tmpl;
1610
            return;
1611
        }
1612
    }
1613

    
1614
    rc = dm->attach(id, tmpl, error_str);
1615

    
1616
    if ( rc != 0 )
1617
    {
1618
        if ( volatile_disk )
1619
        {
1620
            quota_rollback(deltas, Quotas::VM, att_quota);
1621
        }
1622
        else
1623
        {
1624
            quota_rollback(tmpl, Quotas::IMAGE, att_quota);
1625
        }
1626

    
1627
        failure_response(ACTION,
1628
                request_error(error_str, ""),
1629
                att);
1630
    }
1631
    else
1632
    {
1633
        success_response(id, att);
1634
    }
1635

    
1636
    delete tmpl;
1637
    delete deltas;
1638

    
1639
    return;
1640
}
1641

    
1642
/* -------------------------------------------------------------------------- */
1643
/* -------------------------------------------------------------------------- */
1644

    
1645
void VirtualMachineDetach::request_execute(xmlrpc_c::paramList const& paramList,
1646
                                            RequestAttributes& att)
1647
{
1648
    Nebula&             nd = Nebula::instance();
1649
    DispatchManager *   dm = nd.get_dm();
1650

    
1651
    int rc;
1652
    string error_str;
1653

    
1654
    int     id      = xmlrpc_c::value_int(paramList.getInt(1));
1655
    int     disk_id = xmlrpc_c::value_int(paramList.getInt(2));
1656

    
1657
    // -------------------------------------------------------------------------
1658
    // Authorize the operation
1659
    // -------------------------------------------------------------------------
1660

    
1661
    if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false )
1662
    {
1663
        return;
1664
    }
1665

    
1666
    rc = dm->detach(id, disk_id, error_str);
1667

    
1668
    if ( rc != 0 )
1669
    {
1670
        failure_response(ACTION,
1671
                request_error(error_str, ""),
1672
                att);
1673
    }
1674
    else
1675
    {
1676
        success_response(id, att);
1677
    }
1678

    
1679
    return;
1680
}
1681

    
1682
/* -------------------------------------------------------------------------- */
1683
/* -------------------------------------------------------------------------- */
1684

    
1685
void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList,
1686
                                           RequestAttributes& att)
1687
{
1688
    int     id              = xmlrpc_c::value_int(paramList.getInt(1));
1689
    string  str_tmpl        = xmlrpc_c::value_string(paramList.getString(2));
1690
    bool    enforce_param   = xmlrpc_c::value_boolean(paramList.getBoolean(3));
1691

    
1692
    float ncpu, ocpu, dcpu;
1693
    int   nmemory, omemory, dmemory;
1694
    int   nvcpu, ovcpu;
1695

    
1696
    Nebula&    nd    = Nebula::instance();
1697
    HostPool * hpool = nd.get_hpool();
1698
    Host *     host;
1699

    
1700
    Template deltas;
1701
    string   error_str;
1702
    bool     rc;
1703
    int      ret;
1704
    int      hid = -1;
1705

    
1706
    PoolObjectAuth vm_perms;
1707

    
1708
    VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
1709
    VirtualMachine * vm;
1710
    VirtualMachineTemplate tmpl;
1711

    
1712
    bool enforce = true;
1713

    
1714
    if (att.uid == UserPool::ONEADMIN_ID || att.gid == GroupPool::ONEADMIN_ID)
1715
    {
1716
        enforce = enforce_param;
1717
    }
1718

    
1719
    // -------------------------------------------------------------------------
1720
    // Parse template
1721
    // -------------------------------------------------------------------------
1722

    
1723
    rc = tmpl.parse_str_or_xml(str_tmpl, error_str);
1724

    
1725
    if ( rc != 0 )
1726
    {
1727
        failure_response(INTERNAL, error_str, att);
1728
        return;
1729
    }
1730

    
1731
    /* ---------------------------------------------------------------------- */
1732
    /*  Authorize the operation & restricted attributes                       */
1733
    /* ---------------------------------------------------------------------- */
1734

    
1735
    if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false )
1736
    {
1737
        return;
1738
    }
1739

    
1740
    if (att.uid != UserPool::ONEADMIN_ID && att.gid!=GroupPool::ONEADMIN_ID)
1741
    {
1742
        string aname;
1743

    
1744
        if (tmpl.check(aname))
1745
        {
1746
            ostringstream oss;
1747

    
1748
            oss << "Template includes a restricted attribute " << aname;
1749

    
1750
            failure_response(AUTHORIZATION,
1751
                    authorization_error(oss.str(), att),
1752
                    att);
1753
            return;
1754
        }
1755
    }
1756

    
1757
    /* ---------------------------------------------------------------------- */
1758
    /*  Get the resize values                                                 */
1759
    /* ---------------------------------------------------------------------- */
1760

    
1761
    tmpl.get("CPU", ncpu);
1762
    tmpl.get("VCPU", nvcpu);
1763
    tmpl.get("MEMORY", nmemory);
1764

    
1765
    vm = vmpool->get(id, true);
1766

    
1767
    if (vm == 0)
1768
    {
1769
        failure_response(NO_EXISTS,
1770
                get_error(object_name(PoolObjectSQL::VM),id),
1771
                att);
1772
        return;
1773
    }
1774

    
1775
    vm->get_permissions(vm_perms);
1776

    
1777
    vm->get_template_attribute("MEMORY", omemory);
1778
    vm->get_template_attribute("CPU", ocpu);
1779
    vm->get_template_attribute("VCPU", ovcpu);
1780

    
1781
    if (nmemory == 0)
1782
    {
1783
        nmemory = omemory;
1784
    }
1785

    
1786
    if (ncpu == 0)
1787
    {
1788
        ncpu = ocpu;
1789
    }
1790

    
1791
    if (nvcpu == 0)
1792
    {
1793
        nvcpu = ovcpu;
1794
    }
1795

    
1796
    dcpu    = ncpu - ocpu;
1797
    dmemory = nmemory - omemory;
1798

    
1799
    deltas.add("MEMORY", dmemory);
1800
    deltas.add("CPU", dcpu);
1801
    deltas.add("VMS", 0);
1802

    
1803
    switch (vm->get_state())
1804
    {
1805
        case VirtualMachine::POWEROFF: //Only check host capacity in POWEROFF
1806
            if (vm->hasHistory() == true)
1807
            {
1808
                hid = vm->get_hid();
1809
            }
1810
        break;
1811

    
1812
        case VirtualMachine::INIT:
1813
        case VirtualMachine::PENDING:
1814
        case VirtualMachine::HOLD:
1815
        case VirtualMachine::FAILED:
1816
        case VirtualMachine::UNDEPLOYED:
1817
        break;
1818

    
1819
        case VirtualMachine::STOPPED:
1820
        case VirtualMachine::DONE:
1821
        case VirtualMachine::SUSPENDED:
1822
        case VirtualMachine::ACTIVE:
1823
            failure_response(ACTION,
1824
                     request_error("Wrong state to perform action",""),
1825
                     att);
1826

    
1827
            vm->unlock();
1828
            return;
1829
    }
1830

    
1831
    ret = vm->check_resize(ncpu, nmemory, nvcpu, error_str);
1832

    
1833
    vm->unlock();
1834

    
1835
    if (ret != 0)
1836
    {
1837
        failure_response(INTERNAL,
1838
                request_error("Could resize the VM", error_str),
1839
                att);
1840
        return;
1841
    }
1842

    
1843
    /* ---------------------------------------------------------------------- */
1844
    /*  Check quotas                                                          */
1845
    /* ---------------------------------------------------------------------- */
1846

    
1847
    if (quota_resize_authorization(&deltas, att, vm_perms) == false)
1848
    {
1849
        return;
1850
    }
1851

    
1852
    RequestAttributes att_rollback(vm_perms.uid, vm_perms.gid, att);
1853

    
1854
    /* ---------------------------------------------------------------------- */
1855
    /*  Check & update host capacity                                          */
1856
    /* ---------------------------------------------------------------------- */
1857

    
1858
    if (hid != -1)
1859
    {
1860
        int dcpu_host = (int) (dcpu * 100);//now in 100%
1861
        int dmem_host = dmemory * 1024;    //now in Kilobytes
1862

    
1863
        host = hpool->get(hid, true);
1864

    
1865
        if (host == 0)
1866
        {
1867
            failure_response(NO_EXISTS,
1868
                get_error(object_name(PoolObjectSQL::HOST),hid),
1869
                att);
1870

    
1871
            quota_rollback(&deltas, Quotas::VM, att_rollback);
1872

    
1873
            return;
1874
        }
1875

    
1876
        if ( enforce && host->test_capacity(dcpu_host, dmem_host, 0) == false)
1877
        {
1878
            ostringstream oss;
1879

    
1880
            oss << object_name(PoolObjectSQL::HOST)
1881
                << " " << hid << " does not have enough capacity.";
1882

    
1883
            failure_response(ACTION, request_error(oss.str(),""), att);
1884

    
1885
            host->unlock();
1886

    
1887
            quota_rollback(&deltas, Quotas::VM, att_rollback);
1888

    
1889
            return;
1890
        }
1891

    
1892
        host->update_capacity(dcpu_host, dmem_host, 0);
1893

    
1894
        hpool->update(host);
1895

    
1896
        host->unlock();
1897
    }
1898

    
1899
    /* ---------------------------------------------------------------------- */
1900
    /*  Resize the VM                                                         */
1901
    /* ---------------------------------------------------------------------- */
1902

    
1903
    vm = vmpool->get(id, true);
1904

    
1905
    if (vm == 0)
1906
    {
1907
        failure_response(NO_EXISTS,
1908
                get_error(object_name(PoolObjectSQL::VM),id),
1909
                att);
1910

    
1911
        quota_rollback(&deltas, Quotas::VM, att_rollback);
1912

    
1913
        if (hid != -1)
1914
        {
1915
            host = hpool->get(hid, true);
1916

    
1917
            if (host != 0)
1918
            {
1919
                host->update_capacity(-dcpu, -dmemory, 0);
1920
                hpool->update(host);
1921

    
1922
                host->unlock();
1923
            }
1924
        }
1925
        return;
1926
    }
1927

    
1928
    //Check again state as the VM may transit to active (e.g. scheduled)
1929
    switch (vm->get_state())
1930
    {
1931
        case VirtualMachine::INIT:
1932
        case VirtualMachine::PENDING:
1933
        case VirtualMachine::HOLD:
1934
        case VirtualMachine::FAILED:
1935
        case VirtualMachine::POWEROFF:
1936
        case VirtualMachine::UNDEPLOYED:
1937
            ret = vm->resize(ncpu, nmemory, nvcpu, error_str);
1938

    
1939
            if (ret != 0)
1940
            {
1941
                vm->unlock();
1942

    
1943
                failure_response(INTERNAL,
1944
                        request_error("Could not resize the VM", error_str),
1945
                        att);
1946
                return;
1947
            }
1948

    
1949
            vmpool->update(vm);
1950
        break;
1951

    
1952
        case VirtualMachine::STOPPED:
1953
        case VirtualMachine::DONE:
1954
        case VirtualMachine::SUSPENDED:
1955
        case VirtualMachine::ACTIVE:
1956
            failure_response(ACTION,
1957
                     request_error("Wrong state to perform action",""),
1958
                     att);
1959

    
1960
            vm->unlock();
1961

    
1962
            quota_rollback(&deltas, Quotas::VM, att_rollback);
1963

    
1964
            if (hid != -1)
1965
            {
1966
                host = hpool->get(hid, true);
1967

    
1968
                if (host != 0)
1969
                {
1970
                    host->update_capacity(ocpu - ncpu, omemory - nmemory, 0);
1971
                    hpool->update(host);
1972

    
1973
                    host->unlock();
1974
                }
1975
            }
1976
            return;
1977
    }
1978

    
1979
    vm->unlock();
1980

    
1981
    success_response(id, att);
1982
}
1983

    
1984
/* -------------------------------------------------------------------------- */
1985
/* -------------------------------------------------------------------------- */
1986

    
1987
void VirtualMachineSnapshotCreate::request_execute(
1988
        xmlrpc_c::paramList const&  paramList,
1989
        RequestAttributes&          att)
1990
{
1991
    Nebula&           nd = Nebula::instance();
1992
    DispatchManager * dm = nd.get_dm();
1993

    
1994
    int     rc;
1995
    int     snap_id;
1996
    string  error_str;
1997

    
1998
    int     id   = xmlrpc_c::value_int(paramList.getInt(1));
1999
    string  name = xmlrpc_c::value_string(paramList.getString(2));
2000

    
2001
    // -------------------------------------------------------------------------
2002
    // Authorize the operation
2003
    // -------------------------------------------------------------------------
2004

    
2005
    if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false )
2006
    {
2007
        return;
2008
    }
2009

    
2010
    rc = dm->snapshot_create(id, name, snap_id, error_str);
2011

    
2012
    if ( rc != 0 )
2013
    {
2014
        failure_response(ACTION,
2015
                request_error(error_str, ""),
2016
                att);
2017
    }
2018
    else
2019
    {
2020
        success_response(snap_id, att);
2021
    }
2022

    
2023
    return;
2024
}
2025

    
2026
/* -------------------------------------------------------------------------- */
2027
/* -------------------------------------------------------------------------- */
2028

    
2029
void VirtualMachineSnapshotRevert::request_execute(
2030
        xmlrpc_c::paramList const&  paramList,
2031
        RequestAttributes&          att)
2032
{
2033
    Nebula&           nd = Nebula::instance();
2034
    DispatchManager * dm = nd.get_dm();
2035

    
2036
    int    rc;
2037
    string error_str;
2038

    
2039
    int id      = xmlrpc_c::value_int(paramList.getInt(1));
2040
    int snap_id = xmlrpc_c::value_int(paramList.getInt(2));
2041

    
2042
    // -------------------------------------------------------------------------
2043
    // Authorize the operation
2044
    // -------------------------------------------------------------------------
2045

    
2046
    if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false )
2047
    {
2048
        return;
2049
    }
2050

    
2051
    rc = dm->snapshot_revert(id, snap_id, error_str);
2052

    
2053
    if ( rc != 0 )
2054
    {
2055
        failure_response(ACTION,
2056
                request_error(error_str, ""),
2057
                att);
2058
    }
2059
    else
2060
    {
2061
        success_response(id, att);
2062
    }
2063

    
2064
    return;
2065
}
2066

    
2067
/* -------------------------------------------------------------------------- */
2068
/* -------------------------------------------------------------------------- */
2069

    
2070
void VirtualMachineSnapshotDelete::request_execute(
2071
        xmlrpc_c::paramList const&  paramList,
2072
        RequestAttributes&          att)
2073
{
2074
    Nebula&           nd = Nebula::instance();
2075
    DispatchManager * dm = nd.get_dm();
2076

    
2077
    int    rc;
2078
    string error_str;
2079

    
2080
    int id      = xmlrpc_c::value_int(paramList.getInt(1));
2081
    int snap_id = xmlrpc_c::value_int(paramList.getInt(2));
2082

    
2083
    // -------------------------------------------------------------------------
2084
    // Authorize the operation
2085
    // -------------------------------------------------------------------------
2086

    
2087
    if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false )
2088
    {
2089
        return;
2090
    }
2091

    
2092
    rc = dm->snapshot_delete(id, snap_id, error_str);
2093

    
2094
    if ( rc != 0 )
2095
    {
2096
        failure_response(ACTION,
2097
                request_error(error_str, ""),
2098
                att);
2099
    }
2100
    else
2101
    {
2102
        success_response(id, att);
2103
    }
2104

    
2105
    return;
2106
}
2107

    
2108
/* -------------------------------------------------------------------------- */
2109
/* -------------------------------------------------------------------------- */
2110

    
2111
void VirtualMachineAttachNic::request_execute(
2112
        xmlrpc_c::paramList const&  paramList,
2113
        RequestAttributes&          att)
2114
{
2115
    Nebula&           nd = Nebula::instance();
2116
    DispatchManager * dm = nd.get_dm();
2117

    
2118
    VirtualMachineTemplate tmpl;
2119

    
2120
    PoolObjectAuth       vm_perms;
2121
    VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
2122
    VirtualMachine *     vm;
2123

    
2124
    int    rc;
2125
    string error_str;
2126

    
2127
    int     id       = xmlrpc_c::value_int(paramList.getInt(1));
2128
    string  str_tmpl = xmlrpc_c::value_string(paramList.getString(2));
2129

    
2130
    // -------------------------------------------------------------------------
2131
    // Parse NIC template
2132
    // -------------------------------------------------------------------------
2133

    
2134
    rc = tmpl.parse_str_or_xml(str_tmpl, error_str);
2135

    
2136
    if ( rc != 0 )
2137
    {
2138
        failure_response(INTERNAL, error_str, att);
2139
        return;
2140
    }
2141

    
2142
    // -------------------------------------------------------------------------
2143
    // Authorize the operation, restricted attributes & check quotas
2144
    // -------------------------------------------------------------------------
2145

    
2146
    if ( vm_authorization(id, 0, &tmpl, att, 0, 0, auth_op) == false )
2147
    {
2148
        return;
2149
    }
2150

    
2151
    vm = vmpool->get(id, true);
2152

    
2153
    if (vm == 0)
2154
    {
2155
        failure_response(NO_EXISTS,
2156
                get_error(object_name(PoolObjectSQL::VM),id),
2157
                att);
2158
        return;
2159
    }
2160

    
2161
    vm->get_permissions(vm_perms);
2162

    
2163
    vm->unlock();
2164

    
2165
    RequestAttributes att_quota(vm_perms.uid, vm_perms.gid, att);
2166

    
2167
    if (att.uid != UserPool::ONEADMIN_ID && att.gid!=GroupPool::ONEADMIN_ID)
2168
    {
2169
        string aname;
2170

    
2171
        if (tmpl.check(aname))
2172
        {
2173
            ostringstream oss;
2174

    
2175
            oss << "NIC includes a restricted attribute " << aname;
2176

    
2177
            failure_response(AUTHORIZATION,
2178
                    authorization_error(oss.str(), att),
2179
                    att);
2180
            return;
2181
        }
2182
    }
2183

    
2184
    if ( quota_authorization(&tmpl, Quotas::NETWORK, att_quota) == false )
2185
    {
2186
        return;
2187
    }
2188

    
2189
    rc = dm->attach_nic(id, &tmpl, error_str);
2190

    
2191
    if ( rc != 0 )
2192
    {
2193
        quota_rollback(&tmpl, Quotas::NETWORK, att_quota);
2194

    
2195
        failure_response(ACTION,
2196
                request_error(error_str, ""),
2197
                att);
2198
    }
2199
    else
2200
    {
2201
        success_response(id, att);
2202
    }
2203

    
2204
    return;
2205
}
2206

    
2207
/* -------------------------------------------------------------------------- */
2208
/* -------------------------------------------------------------------------- */
2209

    
2210
void VirtualMachineDetachNic::request_execute(
2211
        xmlrpc_c::paramList const&  paramList,
2212
        RequestAttributes&          att)
2213
{
2214
    Nebula&             nd = Nebula::instance();
2215
    DispatchManager *   dm = nd.get_dm();
2216

    
2217
    int rc;
2218
    string error_str;
2219

    
2220
    int id      = xmlrpc_c::value_int(paramList.getInt(1));
2221
    int nic_id  = xmlrpc_c::value_int(paramList.getInt(2));
2222

    
2223
    // -------------------------------------------------------------------------
2224
    // Authorize the operation
2225
    // -------------------------------------------------------------------------
2226

    
2227
    if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false )
2228
    {
2229
        return;
2230
    }
2231

    
2232
    rc = dm->detach_nic(id, nic_id, error_str);
2233

    
2234
    if ( rc != 0 )
2235
    {
2236
        failure_response(ACTION,
2237
                request_error(error_str, ""),
2238
                att);
2239
    }
2240
    else
2241
    {
2242
        success_response(id, att);
2243
    }
2244

    
2245
    return;
2246
}
2247

    
2248
/* -------------------------------------------------------------------------- */
2249
/* -------------------------------------------------------------------------- */
2250

    
2251
void VirtualMachineRecover::request_execute(
2252
        xmlrpc_c::paramList const& paramList, RequestAttributes& att)
2253
{
2254
    int  id      = xmlrpc_c::value_int(paramList.getInt(1));
2255
    bool success = xmlrpc_c::value_boolean(paramList.getBoolean(2));
2256

    
2257
    VirtualMachine * vm;
2258

    
2259
    Nebula& nd             = Nebula::instance();
2260
    LifeCycleManager*  lcm = nd.get_lcm();
2261

    
2262
    if ( vm_authorization(id, 0, 0, att, 0, 0, auth_op) == false )
2263
    {
2264
        return;
2265
    }
2266

    
2267
    if ((vm = get_vm(id, att)) == 0)
2268
    {
2269
        return;
2270
    }
2271

    
2272
    if(vm->get_state() != VirtualMachine::ACTIVE)
2273
    {
2274
        failure_response(ACTION,
2275
                request_error("Wrong state to perform action",""),
2276
                att);
2277

    
2278
        vm->unlock();
2279
        return;
2280
    }
2281

    
2282
    lcm->recover(vm, success);
2283

    
2284
    success_response(id, att);
2285

    
2286
    vm->unlock();
2287

    
2288
    return;
2289
}
2290

    
2291
/* -------------------------------------------------------------------------- */
2292
/* -------------------------------------------------------------------------- */
2293

    
2294
void VirtualMachinePoolCalculateShowback::request_execute(
2295
        xmlrpc_c::paramList const& paramList,
2296
        RequestAttributes& att)
2297
{
2298
    int start_month = xmlrpc_c::value_int(paramList.getInt(1));
2299
    int start_year  = xmlrpc_c::value_int(paramList.getInt(2));
2300
    int end_month   = xmlrpc_c::value_int(paramList.getInt(3));
2301
    int end_year    = xmlrpc_c::value_int(paramList.getInt(4));
2302

    
2303
    ostringstream oss;
2304
    string        where;
2305
    int           rc;
2306
    string        error_str;
2307

    
2308
    if ( att.gid != 0 )
2309
    {
2310
        failure_response(AUTHORIZATION,
2311
                         authorization_error("Action reserved for group 0 only", att),
2312
                         att);
2313
        return;
2314
    }
2315

    
2316
    rc = (static_cast<VirtualMachinePool *>(pool))->calculate_showback(
2317
                    start_month, start_year, end_month, end_year, error_str);
2318

    
2319
    if (rc != 0)
2320
    {
2321
        failure_response(AUTHORIZATION,
2322
                         request_error(error_str, ""),
2323
                         att);
2324
        return;
2325
    }
2326

    
2327
    success_response("", att);
2328

    
2329
    return;
2330
}