Statistics
| Branch: | Tag: | Revision:

one / src / vm / VirtualMachine.cc @ 4697f1ee

History | View | Annotate | Download (112 KB)

1
/* -------------------------------------------------------------------------- */
2
/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems                */
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
#include <limits.h>
17
#include <string.h>
18
#include <time.h>
19
#include <sys/stat.h>
20
#include <sys/types.h>
21
#include <regex.h>
22
#include <unistd.h>
23

    
24
#include <iostream>
25
#include <sstream>
26
#include <queue>
27

    
28
#include "VirtualMachine.h"
29
#include "VirtualNetworkPool.h"
30
#include "ImagePool.h"
31
#include "NebulaLog.h"
32
#include "NebulaUtil.h"
33
#include "Snapshots.h"
34

    
35
#include "Nebula.h"
36

    
37
#include "vm_file_var_syntax.h"
38
#include "vm_var_syntax.h"
39

    
40
/* ************************************************************************** */
41
/* Virtual Machine :: Constructor/Destructor                                  */
42
/* ************************************************************************** */
43

    
44
VirtualMachine::VirtualMachine(int           id,
45
                               int           _uid,
46
                               int           _gid,
47
                               const string& _uname,
48
                               const string& _gname,
49
                               int           umask,
50
                               VirtualMachineTemplate * _vm_template):
51
        PoolObjectSQL(id,VM,"",_uid,_gid,_uname,_gname,table),
52
        last_poll(0),
53
        state(INIT),
54
        prev_state(INIT),
55
        lcm_state(LCM_INIT),
56
        prev_lcm_state(LCM_INIT),
57
        resched(0),
58
        stime(time(0)),
59
        etime(0),
60
        deploy_id(""),
61
        history(0),
62
        previous_history(0),
63
        _log(0)
64
{
65
    if (_vm_template != 0)
66
    {
67
        // This is a VM Template, with the root TEMPLATE.
68
        _vm_template->set_xml_root("USER_TEMPLATE");
69

    
70
        user_obj_template = _vm_template;
71
    }
72
    else
73
    {
74
        user_obj_template = new VirtualMachineTemplate(false,'=',"USER_TEMPLATE");
75
    }
76

    
77
    obj_template = new VirtualMachineTemplate;
78

    
79
    set_umask(umask);
80
}
81

    
82
VirtualMachine::~VirtualMachine()
83
{
84
    for (unsigned int i=0 ; i < history_records.size() ; i++)
85
    {
86
        delete history_records[i];
87
    }
88

    
89
    for (map<int, Snapshots *>::const_iterator it = snapshots.begin();
90
            it != snapshots.end() ; it++)
91
    {
92
        delete it->second;
93
    }
94

    
95
    delete _log;
96
    delete obj_template;
97
    delete user_obj_template;
98
}
99

    
100
/* ************************************************************************** */
101
/* Virtual Machine :: Database Access Functions                               */
102
/* ************************************************************************** */
103

    
104
const char * VirtualMachine::table = "vm_pool";
105

    
106
const char * VirtualMachine::db_names =
107
    "oid, name, body, uid, gid, last_poll, state, lcm_state, "
108
    "owner_u, group_u, other_u";
109

    
110
const char * VirtualMachine::db_bootstrap = "CREATE TABLE IF NOT EXISTS "
111
    "vm_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, "
112
    "gid INTEGER, last_poll INTEGER, state INTEGER, lcm_state INTEGER, "
113
    "owner_u INTEGER, group_u INTEGER, other_u INTEGER)";
114

    
115

    
116
const char * VirtualMachine::monit_table = "vm_monitoring";
117

    
118
const char * VirtualMachine::monit_db_names = "vmid, last_poll, body";
119

    
120
const char * VirtualMachine::monit_db_bootstrap = "CREATE TABLE IF NOT EXISTS "
121
    "vm_monitoring (vmid INTEGER, last_poll INTEGER, body MEDIUMTEXT, "
122
    "PRIMARY KEY(vmid, last_poll))";
123

    
124

    
125
const char * VirtualMachine::showback_table = "vm_showback";
126

    
127
const char * VirtualMachine::showback_db_names = "vmid, year, month, body";
128

    
129
const char * VirtualMachine::showback_db_bootstrap =
130
    "CREATE TABLE IF NOT EXISTS vm_showback "
131
    "(vmid INTEGER, year INTEGER, month INTEGER, body MEDIUMTEXT, "
132
    "PRIMARY KEY(vmid, year, month))";
133

    
134
const char * VirtualMachine::NO_NIC_DEFAULTS[] = {"NETWORK_ID", "NETWORK",
135
    "NETWORK_UID", "NETWORK_UNAME"};
136

    
137
const int VirtualMachine::NUM_NO_NIC_DEFAULTS = 4;
138

    
139
const char * VirtualMachine::NETWORK_CONTEXT[][2] = {
140
        {"IP", "IP"},
141
        {"MAC", "MAC"},
142
        {"MASK", "NETWORK_MASK"},
143
        {"NETWORK", "NETWORK_ADDRESS"},
144
        {"GATEWAY", "GATEWAY"},
145
        {"DNS", "DNS"},
146
        {"SEARCH_DOMAIN", "SEARCH_DOMAIN"},
147
        {"MTU", "GUEST_MTU"},
148
        {"VROUTER_IP", "VROUTER_IP"},
149
        {"VROUTER_MANAGEMENT", "VROUTER_MANAGEMENT"}};
150
const int VirtualMachine::NUM_NETWORK_CONTEXT = 10;
151

    
152
const char*  VirtualMachine::NETWORK6_CONTEXT[][2] = {
153
        {"IP6", "IP6_GLOBAL"},
154
        {"GATEWAY6", "GATEWAY6"},
155
        {"CONTEXT_FORCE_IPV4", "CONTEXT_FORCE_IPV4"},
156
        {"VROUTER_IP6", "VROUTER_IP6_GLOBAL"}};
157

    
158
const int VirtualMachine::NUM_NETWORK6_CONTEXT = 4;
159

    
160
const char*  VirtualMachine::VROUTER_ATTRIBUTES[] = {
161
        "VROUTER_ID",
162
        "VROUTER_KEEPALIVED_ID",
163
        "VROUTER_KEEPALIVED_PASSWORD"};
164
const int VirtualMachine::NUM_VROUTER_ATTRIBUTES = 3;
165

    
166
/* -------------------------------------------------------------------------- */
167
/* -------------------------------------------------------------------------- */
168

    
169
int VirtualMachine::select(SqlDB * db)
170
{
171
    ostringstream   oss;
172
    ostringstream   ose;
173

    
174
    string system_dir;
175
    int    rc;
176
    int    last_seq;
177

    
178
    Nebula& nd = Nebula::instance();
179

    
180
    // Rebuild the VirtualMachine object
181
    rc = PoolObjectSQL::select(db);
182

    
183
    if( rc != 0 )
184
    {
185
        return rc;
186
    }
187

    
188
    //Get History Records. Current history is built in from_xml() (if any).
189
    if( hasHistory() )
190
    {
191
        last_seq = history->seq - 1;
192

    
193
        for (int i = last_seq; i >= 0; i--)
194
        {
195
            History * hp;
196

    
197
            hp = new History(oid, i);
198
            rc = hp->select(db);
199

    
200
            if ( rc != 0)
201
            {
202
                goto error_previous_history;
203
            }
204

    
205
            history_records[i] = hp;
206

    
207
            if ( i == last_seq )
208
            {
209
                previous_history = hp;
210
            }
211
        }
212
    }
213

    
214
    if ( state == DONE ) //Do not recreate dirs. They may be deleted
215
    {
216
        _log = 0;
217

    
218
        return 0;
219
    }
220

    
221
    //--------------------------------------------------------------------------
222
    //Create support directories for this VM
223
    //--------------------------------------------------------------------------
224
    oss.str("");
225
    oss << nd.get_vms_location() << oid;
226

    
227
    mkdir(oss.str().c_str(), 0700);
228
    chmod(oss.str().c_str(), 0700);
229

    
230
    //--------------------------------------------------------------------------
231
    //Create Log support for this VM
232
    //--------------------------------------------------------------------------
233
    try
234
    {
235
        Log::MessageType   clevel;
236
        NebulaLog::LogType log_system;
237

    
238
        log_system  = nd.get_log_system();
239
        clevel      = nd.get_debug_level();
240

    
241
        switch(log_system)
242
        {
243
            case NebulaLog::FILE_TS:
244
            case NebulaLog::FILE:
245
                _log = new FileLog(nd.get_vm_log_filename(oid), clevel);
246
                break;
247

    
248
            case NebulaLog::SYSLOG:
249
                _log = new SysLog(clevel, oid, obj_type);
250
                break;
251

    
252
            case NebulaLog::STD:
253
                _log = new StdLog(clevel, oid, obj_type);
254
                break;
255

    
256
            default:
257
                throw runtime_error("Unknown log system.");
258
                break;
259
        }
260
    }
261
    catch(exception &e)
262
    {
263
        ose << "Error creating log: " << e.what();
264
        NebulaLog::log("ONE",Log::ERROR, ose);
265

    
266
        _log = 0;
267
    }
268

    
269
    return 0;
270

    
271
error_previous_history:
272
    ose << "Cannot get previous history record (seq:" << history->seq
273
        << ") for VM id: " << oid;
274

    
275
    log("ONE", Log::ERROR, ose);
276
    return -1;
277
}
278

    
279
/* -------------------------------------------------------------------------- */
280
/* -------------------------------------------------------------------------- */
281

    
282
int VirtualMachine::insert(SqlDB * db, string& error_str)
283
{
284
    int    rc;
285
    string name;
286
    string prefix;
287

    
288
    string value;
289
    int    ivalue;
290
    float  fvalue;
291

    
292
    ostringstream oss;
293

    
294
    // ------------------------------------------------------------------------
295
    // Set a name if the VM has not got one and VM_ID
296
    // ------------------------------------------------------------------------
297

    
298
    oss << oid;
299
    value = oss.str();
300

    
301
    user_obj_template->erase("VMID");
302
    obj_template->add("VMID", value);
303

    
304
    user_obj_template->get("TEMPLATE_ID", value);
305
    user_obj_template->erase("TEMPLATE_ID");
306

    
307
    if (!value.empty())
308
    {
309
        obj_template->add("TEMPLATE_ID", value);
310
    }
311

    
312
    user_obj_template->get("NAME",name);
313
    user_obj_template->erase("NAME");
314

    
315
    user_obj_template->get("TEMPLATE_NAME", prefix);
316
    user_obj_template->erase("TEMPLATE_NAME");
317

    
318
    if (prefix.empty())
319
    {
320
        prefix = "one";
321
    }
322

    
323
    if (name.empty() == true)
324
    {
325
        oss.str("");
326
        oss << prefix << "-" << oid;
327
        name = oss.str();
328
    }
329

    
330
    if ( !PoolObjectSQL::name_is_valid(name, error_str) )
331
    {
332
        goto error_name;
333
    }
334

    
335
    this->name = name;
336

    
337
    // ------------------------------------------------------------------------
338
    // Parse the Public Cloud specs for this VM
339
    // ------------------------------------------------------------------------
340

    
341
    if (parse_public_clouds(error_str) != 0)
342
    {
343
        goto error_public;
344
    }
345

    
346
    // ------------------------------------------------------------------------
347
    // Check for CPU, VCPU and MEMORY attributes
348
    // ------------------------------------------------------------------------
349

    
350
    if ( user_obj_template->get("MEMORY", ivalue) == false || ivalue <= 0 )
351
    {
352
        goto error_memory;
353
    }
354

    
355
    user_obj_template->erase("MEMORY");
356
    obj_template->add("MEMORY", ivalue);
357

    
358
    if ( user_obj_template->get("CPU", fvalue) == false || fvalue <= 0 )
359
    {
360
        goto error_cpu;
361
    }
362

    
363
    user_obj_template->erase("CPU");
364
    obj_template->add("CPU", fvalue);
365

    
366
    // VCPU is optional, first check if the attribute exists, then check it is
367
    // an integer
368
    user_obj_template->get("VCPU", value);
369

    
370
    if ( value.empty() == false )
371
    {
372
        if ( user_obj_template->get("VCPU", ivalue) == false || ivalue <= 0 )
373
        {
374
            goto error_vcpu;
375
        }
376

    
377
        user_obj_template->erase("VCPU");
378
        obj_template->add("VCPU", ivalue);
379
    }
380

    
381
    // ------------------------------------------------------------------------
382
    // Check the cost attributes
383
    // ------------------------------------------------------------------------
384

    
385
    if ( user_obj_template->get("CPU_COST", fvalue) == true )
386
    {
387
        if ( fvalue < 0 )
388
        {
389
            goto error_cpu_cost;
390
        }
391

    
392
        user_obj_template->erase("CPU_COST");
393
        obj_template->add("CPU_COST", fvalue);
394
    }
395

    
396
    if ( user_obj_template->get("MEMORY_COST", fvalue) == true )
397
    {
398
        if ( fvalue < 0 )
399
        {
400
            goto error_memory_cost;
401
        }
402

    
403
        user_obj_template->erase("MEMORY_COST");
404
        obj_template->add("MEMORY_COST", fvalue);
405
    }
406

    
407
    if ( user_obj_template->get("DISK_COST", fvalue) == true )
408
    {
409
        if ( fvalue < 0 )
410
        {
411
            goto error_disk_cost;
412
        }
413

    
414
        user_obj_template->erase("DISK_COST");
415
        obj_template->add("DISK_COST", fvalue);
416
    }
417

    
418
    // ------------------------------------------------------------------------
419
    // Check the OS attribute
420
    // ------------------------------------------------------------------------
421

    
422
    rc = parse_os(error_str);
423

    
424
    if ( rc != 0 )
425
    {
426
        goto error_os;
427
    }
428

    
429
    // ------------------------------------------------------------------------
430
    // Parse the defaults to merge
431
    // ------------------------------------------------------------------------
432

    
433
    rc = parse_defaults(error_str);
434

    
435
    if ( rc != 0 )
436
    {
437
        goto error_defaults;
438
    }
439

    
440
    // ------------------------------------------------------------------------
441
    // Parse the virtual router attributes
442
    // ------------------------------------------------------------------------
443

    
444
    rc = parse_vrouter(error_str);
445

    
446
    if ( rc != 0 )
447
    {
448
        goto error_vrouter;
449
    }
450

    
451
    // ------------------------------------------------------------------------
452
    // Get network leases
453
    // ------------------------------------------------------------------------
454

    
455
    rc = get_network_leases(error_str);
456

    
457
    if ( rc != 0 )
458
    {
459
        goto error_leases_rollback;
460
    }
461

    
462
    // ------------------------------------------------------------------------
463
    // Get disk images
464
    // ------------------------------------------------------------------------
465

    
466
    rc = get_disk_images(error_str);
467

    
468
    if ( rc != 0 )
469
    {
470
        // The get_disk_images method has an internal rollback for
471
        // the acquired images, release_disk_images() would release all disks
472
        goto error_leases_rollback;
473
    }
474

    
475
    // ------------------------------------------------------------------------
476
    // PCI Devices
477
    // ------------------------------------------------------------------------
478

    
479
    rc = parse_pci(error_str);
480

    
481
    if ( rc != 0 )
482
    {
483
        goto error_pci;
484
    }
485

    
486
    // -------------------------------------------------------------------------
487
    // Parse the context & requirements
488
    // -------------------------------------------------------------------------
489

    
490
    rc = parse_context(error_str);
491

    
492
    if ( rc != 0 )
493
    {
494
        goto error_context;
495
    }
496

    
497
    rc = parse_requirements(error_str);
498

    
499
    if ( rc != 0 )
500
    {
501
        goto error_requirements;
502
    }
503

    
504
    rc = automatic_requirements(error_str);
505

    
506
    if ( rc != 0 )
507
    {
508
        goto error_requirements;
509
    }
510

    
511
    if ( parse_graphics(error_str) != 0 )
512
    {
513
        goto error_graphics;
514
    }
515

    
516
    // -------------------------------------------------------------------------
517
    // Get and set DEPLOY_ID for imported VMs
518
    // -------------------------------------------------------------------------
519

    
520
    user_obj_template->get("IMPORT_VM_ID", value);
521
    user_obj_template->erase("IMPORT_VM_ID");
522

    
523
    if (!value.empty())
524
    {
525
        const char * one_vms = "^one-[[:digit:]]+$";
526

    
527
        if (one_util::regex_match(one_vms, value.c_str()) == 0)
528
        {
529
            goto error_one_vms;
530
        }
531
        else
532
        {
533
            deploy_id = value;
534
            obj_template->add("IMPORTED", "YES");
535
        }
536
    }
537

    
538
    // ------------------------------------------------------------------------
539

    
540
    parse_well_known_attributes();
541

    
542
    // ------------------------------------------------------------------------
543
    // Insert the VM
544
    // ------------------------------------------------------------------------
545

    
546
    rc = insert_replace(db, false, error_str);
547

    
548
    if ( rc != 0 )
549
    {
550
        goto error_update;
551
    }
552

    
553
    return 0;
554

    
555
error_update:
556
    goto error_rollback;
557

    
558
error_pci:
559
    goto error_rollback;
560

    
561
error_context:
562
    goto error_rollback;
563

    
564
error_requirements:
565
    goto error_rollback;
566

    
567
error_graphics:
568
    goto error_rollback;
569

    
570
error_rollback:
571
    release_disk_images();
572

    
573
error_leases_rollback:
574
    release_network_leases();
575
    goto error_common;
576

    
577
error_cpu:
578
    error_str = "CPU attribute must be a positive float or integer value.";
579
    goto error_common;
580

    
581
error_vcpu:
582
    error_str = "VCPU attribute must be a positive integer value.";
583
    goto error_common;
584

    
585
error_memory:
586
    error_str = "MEMORY attribute must be a positive integer value.";
587
    goto error_common;
588

    
589
error_cpu_cost:
590
    error_str = "CPU_COST attribute must be a positive float or integer value.";
591
    goto error_common;
592

    
593
error_memory_cost:
594
    error_str = "MEMORY_COST attribute must be a positive float or integer value.";
595
    goto error_common;
596

    
597
error_disk_cost:
598
    error_str = "DISK_COST attribute must be a positive float or integer value.";
599
    goto error_common;
600

    
601
error_one_vms:
602
    error_str = "Trying to import an OpenNebula VM: 'one-*'.";
603
    goto error_common;
604

    
605
error_os:
606
error_defaults:
607
error_vrouter:
608
error_public:
609
error_name:
610
error_common:
611
    NebulaLog::log("ONE",Log::ERROR, error_str);
612

    
613
    return -1;
614
}
615

    
616
/* -------------------------------------------------------------------------- */
617
/* -------------------------------------------------------------------------- */
618

    
619
int VirtualMachine::set_os_file(VectorAttribute *  os,
620
                                const string&      base_name,
621
                                Image::ImageType   base_type,
622
                                string&            error_str)
623
{
624
    vector<int>  img_ids;
625
    Nebula& nd = Nebula::instance();
626

    
627
    ImagePool * ipool = nd.get_ipool();
628
    Image *     img   = 0;
629

    
630
    int img_id;
631

    
632
    Image::ImageType  type;
633
    Image::ImageState state;
634

    
635
    DatastorePool * ds_pool = nd.get_dspool();
636
    Datastore *     ds;
637
    int             ds_id;
638

    
639
    string attr;
640
    string base_name_ds     = base_name + "_DS";
641
    string base_name_id     = base_name + "_DS_ID";
642
    string base_name_source = base_name + "_DS_SOURCE";
643
    string base_name_ds_id  = base_name + "_DS_DSID";
644
    string base_name_tm     = base_name + "_DS_TM";
645
    string base_name_cluster= base_name + "_DS_CLUSTER_IDS";
646

    
647
    string type_str;
648

    
649
    attr = os->vector_value(base_name_ds.c_str());
650

    
651
    if ( attr.empty() )
652
    {
653
        return 0;
654
    }
655

    
656
    if ( parse_file_attribute(attr, img_ids, error_str) != 0 )
657
    {
658
        return -1;
659
    }
660

    
661
    if ( img_ids.size() != 1 )
662
    {
663
        error_str = "Only one FILE variable can be used in: " + attr;
664
        return -1;
665
    }
666

    
667
    img_id = img_ids.back();
668

    
669
    img = ipool->get(img_id, true);
670

    
671
    if ( img == 0 )
672
    {
673
        error_str = "Image no longer exists in attribute: " + attr;
674
        return -1;
675
    }
676

    
677
    state = img->get_state();
678

    
679
    ds_id = img->get_ds_id();
680
    type  = img->get_type();
681

    
682
    os->remove(base_name);
683

    
684
    os->replace(base_name_id,     img->get_oid());
685
    os->replace(base_name_source, img->get_source());
686
    os->replace(base_name_ds_id,  img->get_ds_id());
687

    
688
    img->unlock();
689

    
690
    type_str = Image::type_to_str(type);
691

    
692
    if ( type != base_type )
693
    {
694
        ostringstream oss;
695

    
696
        oss << base_name << " needs an image of type "
697
            << Image::type_to_str(base_type) << " and not "
698
            << type_str;
699

    
700
        error_str = oss.str();
701
        return -1;
702
    }
703

    
704
    if ( state != Image::READY )
705
    {
706
        ostringstream oss;
707

    
708
        oss << type_str << " Image '" << img_id << " 'not in READY state.";
709

    
710
        error_str = oss.str();
711
        return -1;
712
    }
713

    
714
    ds = ds_pool->get(ds_id, true);
715

    
716
    if ( ds == 0 )
717
    {
718
        error_str = "Associated datastore for image does not exist";
719
        return -1;
720
    }
721

    
722
    os->replace(base_name_tm, ds->get_tm_mad());
723

    
724
    set<int> cluster_ids = ds->get_cluster_ids();
725

    
726
    if (!cluster_ids.empty())
727
    {
728
        os->replace(base_name_cluster, one_util::join(cluster_ids, ','));
729
    }
730

    
731
    ds->unlock();
732

    
733
    return 0;
734
}
735

    
736
/* -------------------------------------------------------------------------- */
737

    
738
int VirtualMachine::parse_os(string& error_str)
739
{
740
    int num;
741
    int rc;
742

    
743
    vector<Attribute *> os_attr;
744
    VectorAttribute *   os;
745

    
746
    vector<Attribute *>::iterator it;
747

    
748
    num = user_obj_template->remove("OS", os_attr);
749

    
750
    for (it=os_attr.begin(); it != os_attr.end(); it++)
751
    {
752
        obj_template->set(*it);
753
    }
754

    
755
    if ( num == 0 )
756
    {
757
        return 0;
758
    }
759
    else if ( num > 1 )
760
    {
761
        error_str = "Only one OS attribute can be defined.";
762
        return -1;
763
    }
764

    
765
    os = dynamic_cast<VectorAttribute *>(os_attr[0]);
766

    
767
    if ( os == 0 )
768
    {
769
        error_str = "Internal error parsing OS attribute.";
770
        return -1;
771
    }
772

    
773
    rc = set_os_file(os, "KERNEL", Image::KERNEL, error_str);
774

    
775
    if ( rc != 0 )
776
    {
777
        return -1;
778
    }
779

    
780
    rc = set_os_file(os, "INITRD", Image::RAMDISK, error_str);
781

    
782
    if ( rc != 0 )
783
    {
784
        return -1;
785
    }
786

    
787
    return 0;
788
}
789

    
790
/* -------------------------------------------------------------------------- */
791
/* -------------------------------------------------------------------------- */
792

    
793
int VirtualMachine::parse_defaults(string& error_str)
794
{
795
    int num;
796

    
797
    vector<Attribute *> attr;
798
    VectorAttribute*    vatt = 0;
799

    
800
    num = user_obj_template->remove("NIC_DEFAULT", attr);
801

    
802
    if ( num == 0 )
803
    {
804
        return 0;
805
    }
806

    
807
    if ( num > 1 )
808
    {
809
        error_str = "Only one NIC_DEFAULT attribute can be defined.";
810
        goto error_cleanup;
811
    }
812

    
813
    vatt = dynamic_cast<VectorAttribute *>(attr[0]);
814

    
815
    if ( vatt == 0 )
816
    {
817
        error_str = "Wrong format for NIC_DEFAULT attribute.";
818
        goto error_cleanup;
819
    }
820

    
821
    for (int i=0; i < NUM_NO_NIC_DEFAULTS; i++)
822
    {
823
        if(vatt->vector_value(NO_NIC_DEFAULTS[i]) != "")
824
        {
825
            ostringstream oss;
826
            oss << "Attribute " << NO_NIC_DEFAULTS[i]
827
                << " is not allowed inside NIC_DEFAULT.";
828

    
829
            error_str = oss.str();
830

    
831
            return -1;
832
        }
833
    }
834

    
835
    obj_template->set(vatt);
836

    
837
    return 0;
838

    
839
error_cleanup:
840

    
841
    for (int i = 0; i < num ; i++)
842
    {
843
        delete attr[i];
844
    }
845

    
846
    return -1;
847
}
848

    
849
/* -------------------------------------------------------------------------- */
850
/* -------------------------------------------------------------------------- */
851

    
852
int VirtualMachine::parse_vrouter(string& error_str)
853
{
854
    string st;
855

    
856
    for (int i = 0; i < NUM_VROUTER_ATTRIBUTES; i++)
857
    {
858
        user_obj_template->get(VROUTER_ATTRIBUTES[i], st);
859

    
860
        if (!st.empty())
861
        {
862
            obj_template->replace(VROUTER_ATTRIBUTES[i], st);
863
        }
864

    
865
        user_obj_template->erase(VROUTER_ATTRIBUTES[i]);
866
    }
867

    
868
    return 0;
869
}
870

    
871
/* -------------------------------------------------------------------------- */
872
/* -------------------------------------------------------------------------- */
873

    
874
static void parse_context_network(const char* vars[][2], int num_vars,
875
        VectorAttribute * context, VectorAttribute * nic)
876
{
877
    string nic_id = nic->vector_value("NIC_ID");
878

    
879
    for (int i=0; i < num_vars; i++)
880
    {
881
        ostringstream cvar;
882
        string cval;
883

    
884
        cvar << "ETH" << nic_id << "_" << vars[i][0];
885

    
886
        cval = context->vector_value(cvar.str().c_str());
887

    
888
        if (!cval.empty())
889
        {
890
            continue;
891
        }
892

    
893
        cval = nic->vector_value(vars[i][1]); //Check the NIC
894

    
895
        if (cval.empty()) //Will check the AR and VNET
896
        {
897
            ostringstream cval_ss;
898

    
899
            cval_ss << "$NETWORK["<< vars[i][1] <<", NIC_ID=\""<< nic_id <<"\"]";
900
            cval = cval_ss.str();
901
        }
902

    
903
        context->replace(cvar.str(), cval);
904
    }
905
}
906

    
907
/* -------------------------------------------------------------------------- */
908

    
909
static void clear_context_network(const char* vars[][2], int num_vars,
910
        VectorAttribute * context, int nic_id)
911
{
912
    ostringstream att_name;
913

    
914
    for (int i=0; i < num_vars; i++)
915
    {
916
        att_name.str("");
917

    
918
        att_name << "ETH" << nic_id << "_" << vars[i][0];
919

    
920
        context->remove(att_name.str());
921
    }
922
}
923

    
924
/* -------------------------------------------------------------------------- */
925

    
926
int VirtualMachine::parse_context(string& error_str)
927
{
928
    VectorAttribute * context = obj_template->get("CONTEXT");
929

    
930
    if ( context == 0 )
931
    {
932
        return 0;
933
    }
934

    
935
    string files_ds = context->vector_value("FILES_DS");
936

    
937
    context->remove("FILES_DS");
938

    
939
    // -------------------------------------------------------------------------
940
    // Inject Network context in marshalled string
941
    // -------------------------------------------------------------------------
942
    bool net_context;
943
    context->vector_value("NETWORK", net_context);
944

    
945
    if (net_context)
946
    {
947
        vector<VectorAttribute *> vatts;
948
        int num_vatts = obj_template->get("NIC", vatts);
949

    
950
        for(int i=0; i<num_vatts; i++)
951
        {
952
            parse_context_network(NETWORK_CONTEXT, NUM_NETWORK_CONTEXT,
953
                    context, vatts[i]);
954

    
955
            if (!vatts[i]->vector_value("IP6_GLOBAL").empty())
956
            {
957
                parse_context_network(NETWORK6_CONTEXT, NUM_NETWORK6_CONTEXT,
958
                        context, vatts[i]);
959
            }
960
        }
961
    }
962

    
963
    // -------------------------------------------------------------------------
964
    // Parse CONTEXT variables
965
    // -------------------------------------------------------------------------
966
    if (parse_context_variables(&context, error_str) == -1)
967
    {
968
        return -1;
969
    }
970

    
971
    // -------------------------------------------------------------------------
972
    // Parse FILE_DS variables
973
    // -------------------------------------------------------------------------
974
    if (!files_ds.empty())
975
    {
976
        string files_ds_parsed;
977
        string st;
978

    
979
        ostringstream oss_parsed;
980

    
981
        vector<int> img_ids;
982

    
983
        if ( parse_file_attribute(files_ds, img_ids, error_str) != 0 )
984
        {
985
            return -1;
986
        }
987

    
988
        if ( img_ids.size() > 0 )
989
        {
990
            vector<int>::iterator it;
991

    
992
            Nebula& nd = Nebula::instance();
993

    
994
            ImagePool * ipool = nd.get_ipool();
995
            Image  *    img   = 0;
996

    
997
            Image::ImageType type;
998
            Image::ImageState state;
999

    
1000
            for ( it=img_ids.begin() ; it < img_ids.end(); it++ )
1001
            {
1002
                img = ipool->get(*it, true);
1003

    
1004
                if ( img != 0 )
1005
                {
1006
                    oss_parsed << img->get_source() << ":'"
1007
                               << img->get_name() << "' ";
1008

    
1009
                    type  = img->get_type();
1010
                    state = img->get_state();
1011

    
1012
                    img->unlock();
1013

    
1014
                    if (type != Image::CONTEXT)
1015
                    {
1016
                        error_str = "Only images of type CONTEXT can be used in"
1017
                                    " FILE_DS attribute.";
1018
                        return -1;
1019
                    }
1020

    
1021
                    if ( state != Image::READY )
1022
                    {
1023
                        ostringstream oss;
1024

    
1025
                        oss << Image::type_to_str(type)
1026
                            << " Image '" << *it << "' not in READY state.";
1027

    
1028
                        error_str = oss.str();
1029

    
1030
                        return -1;
1031
                    }
1032

    
1033
                }
1034
            }
1035
        }
1036

    
1037
        files_ds_parsed = oss_parsed.str();
1038

    
1039
        if ( !files_ds_parsed.empty() )
1040
        {
1041
            context->replace("FILES_DS", files_ds_parsed);
1042
        }
1043
    }
1044

    
1045
    // -------------------------------------------------------------------------
1046
    // OneGate URL
1047
    // -------------------------------------------------------------------------
1048
    bool token;
1049
    context->vector_value("TOKEN", token);
1050

    
1051
    if (token)
1052
    {
1053
        string ep;
1054

    
1055
        Nebula::instance().get_configuration_attribute("ONEGATE_ENDPOINT", ep);
1056

    
1057
        if ( ep.empty() )
1058
        {
1059
            error_str = "CONTEXT/TOKEN set, but OneGate endpoint was not "
1060
                "defined in oned.conf or CONTEXT.";
1061
            return -1;
1062
        }
1063

    
1064
        context->replace("ONEGATE_ENDPOINT", ep);
1065
        context->replace("VMID", oid);
1066

    
1067
        // Store the original owner to compute token_password in case of a chown
1068
        add_template_attribute("CREATED_BY", uid);
1069
    }
1070

    
1071
    // -------------------------------------------------------------------------
1072
    // Virtual Router attributes
1073
    // -------------------------------------------------------------------------
1074
    string st;
1075

    
1076
    for (int i = 0; i < NUM_VROUTER_ATTRIBUTES; i++)
1077
    {
1078
        obj_template->get(VROUTER_ATTRIBUTES[i], st);
1079

    
1080
        if (!st.empty())
1081
        {
1082
            context->replace(VROUTER_ATTRIBUTES[i], st);
1083
        }
1084
    }
1085

    
1086
    return 0;
1087
}
1088

    
1089
/* -------------------------------------------------------------------------- */
1090
/* -------------------------------------------------------------------------- */
1091

    
1092
int VirtualMachine::parse_context_variables(VectorAttribute ** context,
1093
        string& error_str)
1094
{
1095
    int rc;
1096

    
1097
    string   parsed;
1098
    string * str = (*context)->marshall();
1099

    
1100
    if (str == 0)
1101
    {
1102
        return -1;
1103
    }
1104

    
1105
    rc = parse_template_attribute(*str, parsed, error_str);
1106

    
1107
    delete str;
1108

    
1109
    if (rc != 0)
1110
    {
1111
        return -1;
1112
    }
1113

    
1114
    *context = new VectorAttribute("CONTEXT");
1115
    (*context)->unmarshall(parsed);
1116

    
1117
    obj_template->erase("CONTEXT");
1118
    obj_template->set(*context);
1119

    
1120
    return 0;
1121
}
1122

    
1123
/* -------------------------------------------------------------------------- */
1124
/* -------------------------------------------------------------------------- */
1125

    
1126
int VirtualMachine::parse_pci(string& error_str)
1127
{
1128
    VectorAttribute *               pci;
1129
    vector<Attribute *>             array_pci;
1130
    vector<Attribute *>::iterator   it;
1131

    
1132
    unsigned int val;
1133

    
1134
    user_obj_template->remove("PCI", array_pci);
1135

    
1136
    static string attrs[] = {"VENDOR", "DEVICE", "CLASS"};
1137

    
1138
    for (it = array_pci.begin(); it !=array_pci.end(); it++)
1139
    {
1140
        obj_template->set(*it);
1141
    }
1142

    
1143
    for (it = array_pci.begin(); it !=array_pci.end(); it++)
1144
    {
1145
        bool found = false;
1146

    
1147
        pci = dynamic_cast<VectorAttribute * >(*it);
1148

    
1149
        if ( pci == 0 )
1150
        {
1151
            error_str = "PCI attribute must be a vector attribute";
1152
            return -1;
1153
        }
1154

    
1155
        for (int i=0; i<3; i++)
1156
        {
1157
            int rc = HostSharePCI::get_pci_value(attrs[i].c_str(), pci, val);
1158

    
1159
            if (rc == -1)
1160
            {
1161
                ostringstream oss;
1162
                oss << "Wrong value for PCI/" << attrs[i] << ": "
1163
                    << pci->vector_value(attrs[i].c_str())
1164
                    <<". It must be a hex value";
1165

    
1166
                error_str = oss.str();
1167
                return -1;
1168
            }
1169
            else if ( rc != 0 )
1170
            {
1171
                found = true;
1172
            }
1173
        }
1174

    
1175
        if (!found)
1176
        {
1177
            error_str = "Missing mandatory attributes inside PCI. "
1178
                        "Either DEVICE, VENDOR or CLASS must be defined";
1179

    
1180
            return -1;
1181
        }
1182
    }
1183

    
1184
    return 0;
1185
}
1186

    
1187
/* -------------------------------------------------------------------------- */
1188
/* -------------------------------------------------------------------------- */
1189

    
1190
int VirtualMachine::parse_graphics(string& error_str)
1191
{
1192
    vector<Attribute *> array_graphics;
1193
    VectorAttribute *   graphics;
1194

    
1195
    vector<Attribute *>::iterator it;
1196

    
1197
    int num = user_obj_template->remove("GRAPHICS", array_graphics);
1198

    
1199
    for (it=array_graphics.begin(); it != array_graphics.end(); it++)
1200
    {
1201
        obj_template->set(*it);
1202
    }
1203

    
1204
    if ( num == 0 )
1205
    {
1206
        return 0;
1207
    }
1208

    
1209
    graphics = dynamic_cast<VectorAttribute * >(array_graphics[0]);
1210

    
1211
    if ( graphics == 0 )
1212
    {
1213
        return 0;
1214
    }
1215

    
1216
    string port = graphics->vector_value("PORT");
1217
    int    port_i;
1218

    
1219
    int rc = graphics->vector_value("PORT", port_i);
1220

    
1221
    if ( port.empty() )
1222
    {
1223
        Nebula&       nd = Nebula::instance();
1224

    
1225
        ostringstream oss;
1226
        istringstream iss;
1227

    
1228
        int           base_port;
1229
        string        base_port_s;
1230

    
1231
        int limit = 65535;
1232

    
1233
        nd.get_configuration_attribute("VNC_BASE_PORT",base_port_s);
1234
        iss.str(base_port_s);
1235
        iss >> base_port;
1236

    
1237
        oss << ( base_port + ( oid % (limit - base_port) ));
1238
        graphics->replace("PORT", oss.str());
1239
    }
1240
    else if ( rc == -1 || port_i < 0 )
1241
    {
1242
        error_str = "Wrong PORT number in GRAPHICS attribute";
1243
        return -1;
1244
    }
1245

    
1246
    string random_passwd = graphics->vector_value("RANDOM_PASSWD");
1247

    
1248
    if ( !random_passwd.empty() )
1249
    {
1250
        graphics->replace("PASSWD", one_util::random_password());
1251
    }
1252

    
1253
    return 0;
1254
}
1255

    
1256
/* -------------------------------------------------------------------------- */
1257
/* -------------------------------------------------------------------------- */
1258

    
1259
int VirtualMachine::parse_requirements(string& error_str)
1260
{
1261
    int rc, num;
1262

    
1263
    vector<Attribute *> array_reqs;
1264
    SingleAttribute *   reqs;
1265

    
1266
    string              parsed;
1267

    
1268
    num = user_obj_template->remove("SCHED_REQUIREMENTS", array_reqs);
1269

    
1270
    if ( num == 0 ) // Compatibility with old REQUIREMENTS attribute
1271
    {
1272
        num = user_obj_template->remove("REQUIREMENTS", array_reqs);
1273
    }
1274
    else
1275
    {
1276
        user_obj_template->erase("REQUIREMENTS");
1277
    }
1278

    
1279
    if ( num == 0 )
1280
    {
1281
        return 0;
1282
    }
1283
    else if ( num > 1 )
1284
    {
1285
        error_str = "Only one SCHED_REQUIREMENTS attribute can be defined.";
1286
        goto error_cleanup;
1287
    }
1288

    
1289
    reqs = dynamic_cast<SingleAttribute *>(array_reqs[0]);
1290

    
1291
    if ( reqs == 0 )
1292
    {
1293
        error_str = "Wrong format for SCHED_REQUIREMENTS attribute.";
1294
        goto error_cleanup;
1295
    }
1296

    
1297
    rc = parse_template_attribute(reqs->value(), parsed, error_str);
1298

    
1299
    if ( rc == 0 )
1300
    {
1301
        SingleAttribute * reqs_parsed;
1302

    
1303
        reqs_parsed = new SingleAttribute("SCHED_REQUIREMENTS",parsed);
1304
        user_obj_template->set(reqs_parsed);
1305
    }
1306

    
1307
    /* --- Delete old requirements attribute --- */
1308

    
1309
    delete array_reqs[0];
1310

    
1311
    return rc;
1312

    
1313
error_cleanup:
1314
    for (int i = 0; i < num ; i++)
1315
    {
1316
        delete array_reqs[i];
1317
    }
1318

    
1319
    return -1;
1320
}
1321

    
1322
/* ------------------------------------------------------------------------ */
1323
/* ------------------------------------------------------------------------ */
1324

    
1325
void VirtualMachine::parse_well_known_attributes()
1326
{
1327
    /*
1328
     * List of meaningful attributes, used in other places and expected in
1329
     * obj_template:
1330
     *
1331
     * DISK
1332
     * NIC
1333
     * VCPU
1334
     * MEMORY
1335
     * CPU
1336
     * CONTEXT
1337
     * OS
1338
     * GRAPHICS
1339
     *
1340
     * INPUT
1341
     * FEATURES
1342
     * RAW
1343
     */
1344

    
1345
    vector<Attribute *>             v_attr;
1346
    vector<Attribute *>::iterator   it;
1347

    
1348
    string names[] = {"INPUT", "FEATURES", "RAW"};
1349

    
1350
    for (int i=0; i<3; i++)
1351
    {
1352
        v_attr.clear();
1353

    
1354
        user_obj_template->remove(names[i], v_attr);
1355

    
1356
        for (it=v_attr.begin(); it != v_attr.end(); it++)
1357
        {
1358
            obj_template->set(*it);
1359
        }
1360
    }
1361
}
1362

    
1363
/* ------------------------------------------------------------------------ */
1364
/* ------------------------------------------------------------------------ */
1365

    
1366
static int check_and_set_cluster_id(
1367
        const char *           id_name,
1368
        const VectorAttribute* vatt,
1369
        set<int>               &cluster_ids)
1370
{
1371
    set<int> vatt_cluster_ids;
1372

    
1373
    one_util::split_unique(vatt->vector_value(id_name), ',', vatt_cluster_ids);
1374

    
1375
    if ( cluster_ids.empty() )
1376
    {
1377
        cluster_ids = vatt_cluster_ids;
1378
    }
1379
    else if ( !vatt_cluster_ids.empty() )
1380
    {
1381
        set<int> intersection = one_util::set_intersection(
1382
                                            cluster_ids, vatt_cluster_ids);
1383

    
1384
        if (intersection.empty())
1385
        {
1386
            return -1;
1387
        }
1388

    
1389
        cluster_ids = intersection;
1390
    }
1391

    
1392
    return 0;
1393
}
1394

    
1395
/* ------------------------------------------------------------------------ */
1396

    
1397
int VirtualMachine::automatic_requirements(string& error_str)
1398
{
1399
    int num_vatts;
1400
    vector<const VectorAttribute  *> vatts;
1401

    
1402
    ostringstream   oss;
1403
    string          requirements;
1404
    set<int>        cluster_ids;
1405

    
1406
    set<string> clouds;
1407

    
1408
    int num_public = get_public_clouds(clouds);
1409

    
1410
    int incomp_id;
1411
    int rc;
1412

    
1413
    // Get cluster id from the KERNEL and INITRD (FILE Datastores)
1414
    const VectorAttribute * osatt = obj_template->get("OS");
1415

    
1416
    if ( osatt != 0 )
1417
    {
1418
        rc = check_and_set_cluster_id("KERNEL_CLUSTER_IDS", osatt, cluster_ids);
1419

    
1420
        if ( rc != 0 )
1421
        {
1422
            goto error_kernel;
1423
        }
1424

    
1425
        rc = check_and_set_cluster_id("INITRD_CLUSTER_IDS", osatt, cluster_ids);
1426

    
1427
        if ( rc != 0 )
1428
        {
1429
            goto error_initrd;
1430
        }
1431
    }
1432

    
1433
    // Get cluster id from all DISK vector attributes (IMAGE Datastore)
1434
    num_vatts = obj_template->get("DISK",vatts);
1435

    
1436
    for(int i=0; i<num_vatts; i++)
1437
    {
1438
        rc = check_and_set_cluster_id("CLUSTER_IDS", vatts[i], cluster_ids);
1439

    
1440
        if ( rc != 0 )
1441
        {
1442
            incomp_id = i;
1443
            goto error_disk;
1444
        }
1445
    }
1446

    
1447
    vatts.clear();
1448

    
1449
    // Get cluster id from all NIC vector attributes
1450
    num_vatts = obj_template->get("NIC", vatts);
1451

    
1452
    for(int i=0; i<num_vatts; i++)
1453
    {
1454
        rc = check_and_set_cluster_id("CLUSTER_IDS", vatts[i], cluster_ids);
1455

    
1456
        if ( rc != 0 )
1457
        {
1458
            incomp_id = i;
1459
            goto error_nic;
1460
        }
1461
    }
1462

    
1463
    if ( !cluster_ids.empty() )
1464
    {
1465
        set<int>::iterator i = cluster_ids.begin();
1466

    
1467
        oss << "(ID = " << *i;
1468

    
1469
        for (++i; i != cluster_ids.end(); i++)
1470
        {
1471
            oss << " | ID = " << *i;
1472
        }
1473

    
1474
        oss << ")";
1475

    
1476
        obj_template->add("AUTOMATIC_CLUSTER_REQUIREMENTS", oss.str());
1477
    }
1478

    
1479
    oss.str("");
1480
    oss << "!(PUBLIC_CLOUD = YES)";
1481

    
1482
    if (num_public != 0)
1483
    {
1484
        set<string>::iterator it = clouds.begin();
1485

    
1486
        oss << " | (PUBLIC_CLOUD = YES & (";
1487

    
1488
        oss << "HYPERVISOR = " << *it ;
1489

    
1490
        for (++it; it != clouds.end() ; ++it)
1491
        {
1492
            oss << " | HYPERVISOR = " << *it;
1493
        }
1494

    
1495
        oss << "))";
1496
    }
1497

    
1498
    obj_template->add("AUTOMATIC_REQUIREMENTS", oss.str());
1499

    
1500
    return 0;
1501

    
1502
error_disk:
1503
    oss << "Incompatible clusters in DISK. Datastore for DISK "<< incomp_id
1504
        << " is not the same as the one used by other VM elements (cluster "
1505
        << one_util::join(cluster_ids, ',') << ")";
1506
    goto error_common;
1507

    
1508
error_kernel:
1509
    oss << "Incompatible cluster in KERNEL datastore, it should be in cluster "
1510
        << one_util::join(cluster_ids, ',') << ".";
1511
    goto error_common;
1512

    
1513
error_initrd:
1514
    oss << "Incompatible cluster in INITRD datastore, it should be in cluster "
1515
        << one_util::join(cluster_ids, ',') << ".";
1516
    goto error_common;
1517

    
1518
error_nic:
1519
    oss << "Incompatible clusters in NIC. Network for NIC "<< incomp_id
1520
        << " is not the same as the one used by other VM elements (cluster "
1521
        << one_util::join(cluster_ids, ',') << ")";
1522
    goto error_common;
1523

    
1524
error_common:
1525
    error_str = oss.str();
1526

    
1527
    return -1;
1528
}
1529

    
1530
/* ------------------------------------------------------------------------ */
1531
/* ------------------------------------------------------------------------ */
1532

    
1533
int VirtualMachine::insert_replace(SqlDB *db, bool replace, string& error_str)
1534
{
1535
    ostringstream   oss;
1536
    int             rc;
1537

    
1538
    string xml_body;
1539
    char * sql_name;
1540
    char * sql_xml;
1541

    
1542
    sql_name =  db->escape_str(name.c_str());
1543

    
1544
    if ( sql_name == 0 )
1545
    {
1546
        goto error_generic;
1547
    }
1548

    
1549
    sql_xml = db->escape_str(to_xml(xml_body).c_str());
1550

    
1551
    if ( sql_xml == 0 )
1552
    {
1553
        goto error_body;
1554
    }
1555

    
1556
    if ( validate_xml(sql_xml) != 0 )
1557
    {
1558
        goto error_xml;
1559
    }
1560

    
1561
    if(replace)
1562
    {
1563
        oss << "REPLACE";
1564
    }
1565
    else
1566
    {
1567
        oss << "INSERT";
1568
    }
1569

    
1570
    oss << " INTO " << table << " ("<< db_names <<") VALUES ("
1571
        <<          oid             << ","
1572
        << "'" <<   sql_name        << "',"
1573
        << "'" <<   sql_xml         << "',"
1574
        <<          uid             << ","
1575
        <<          gid             << ","
1576
        <<          last_poll       << ","
1577
        <<          state           << ","
1578
        <<          lcm_state       << ","
1579
        <<          owner_u         << ","
1580
        <<          group_u         << ","
1581
        <<          other_u         << ")";
1582

    
1583
    db->free_str(sql_name);
1584
    db->free_str(sql_xml);
1585

    
1586
    rc = db->exec(oss);
1587

    
1588
    return rc;
1589

    
1590
error_xml:
1591
    db->free_str(sql_name);
1592
    db->free_str(sql_xml);
1593

    
1594
    error_str = "Error transforming the VM to XML.";
1595

    
1596
    goto error_common;
1597

    
1598
error_body:
1599
    db->free_str(sql_name);
1600
    goto error_generic;
1601

    
1602
error_generic:
1603
    error_str = "Error inserting VM in DB.";
1604
error_common:
1605
    return -1;
1606
}
1607

    
1608
/* -------------------------------------------------------------------------- */
1609
/* -------------------------------------------------------------------------- */
1610

    
1611
int VirtualMachine::update_monitoring(SqlDB * db)
1612
{
1613
    ostringstream oss;
1614
    int           rc;
1615

    
1616
    string xml_body;
1617
    string error_str;
1618
    char * sql_xml;
1619

    
1620
    oss << "<VM>"
1621
        << "<ID>" << oid << "</ID>"
1622
        << "<LAST_POLL>" << last_poll << "</LAST_POLL>"
1623
        << monitoring.to_xml(xml_body)
1624
        << "</VM>";
1625

    
1626
    sql_xml = db->escape_str(oss.str().c_str());
1627

    
1628
    if ( sql_xml == 0 )
1629
    {
1630
        goto error_body;
1631
    }
1632

    
1633
    if ( validate_xml(sql_xml) != 0 )
1634
    {
1635
        goto error_xml;
1636
    }
1637

    
1638
    oss.str("");
1639

    
1640
    oss << "REPLACE INTO " << monit_table << " ("<< monit_db_names <<") VALUES ("
1641
        <<          oid             << ","
1642
        <<          last_poll       << ","
1643
        << "'" <<   sql_xml         << "')";
1644

    
1645
    db->free_str(sql_xml);
1646

    
1647
    rc = db->exec(oss);
1648

    
1649
    return rc;
1650

    
1651
error_xml:
1652
    db->free_str(sql_xml);
1653

    
1654
    error_str = "could not transform the VM to XML.";
1655

    
1656
    goto error_common;
1657

    
1658
error_body:
1659
    error_str = "could not insert the VM in the DB.";
1660

    
1661
error_common:
1662
    oss.str("");
1663
    oss << "Error updating VM monitoring information, " << error_str;
1664

    
1665
    NebulaLog::log("ONE",Log::ERROR, oss);
1666

    
1667
    return -1;
1668
}
1669

    
1670
/* -------------------------------------------------------------------------- */
1671
/* -------------------------------------------------------------------------- */
1672

    
1673
void VirtualMachine::add_history(
1674
    int   hid,
1675
    int   cid,
1676
    const string& hostname,
1677
    const string& vmm_mad,
1678
    const string& vnm_mad,
1679
    const string& tm_mad,
1680
    const string& ds_location,
1681
    int           ds_id)
1682
{
1683
    ostringstream os;
1684
    int           seq;
1685
    string        vm_xml;
1686

    
1687
    if (history == 0)
1688
    {
1689
        seq = 0;
1690
    }
1691
    else
1692
    {
1693
        seq = history->seq + 1;
1694

    
1695
        previous_history = history;
1696
    }
1697

    
1698
    to_xml_extended(vm_xml, 0);
1699

    
1700
    history = new History(oid,
1701
                          seq,
1702
                          hid,
1703
                          hostname,
1704
                          cid,
1705
                          vmm_mad,
1706
                          vnm_mad,
1707
                          tm_mad,
1708
                          ds_location,
1709
                          ds_id,
1710
                          vm_xml);
1711

    
1712
    history_records.push_back(history);
1713
};
1714

    
1715
/* -------------------------------------------------------------------------- */
1716
/* -------------------------------------------------------------------------- */
1717

    
1718
void VirtualMachine::cp_history()
1719
{
1720
    History * htmp;
1721
    string    vm_xml;
1722

    
1723
    if (history == 0)
1724
    {
1725
        return;
1726
    }
1727

    
1728
    to_xml_extended(vm_xml, 0);
1729

    
1730
    htmp = new History(oid,
1731
                       history->seq + 1,
1732
                       history->hid,
1733
                       history->hostname,
1734
                       history->cid,
1735
                       history->vmm_mad_name,
1736
                       history->vnm_mad_name,
1737
                       history->tm_mad_name,
1738
                       history->ds_location,
1739
                       history->ds_id,
1740
                       vm_xml);
1741

    
1742
    previous_history = history;
1743
    history          = htmp;
1744

    
1745
    history_records.push_back(history);
1746
}
1747

    
1748
/* -------------------------------------------------------------------------- */
1749
/* -------------------------------------------------------------------------- */
1750

    
1751
void VirtualMachine::cp_previous_history()
1752
{
1753
    History * htmp;
1754
    string    vm_xml;
1755

    
1756
    if ( previous_history == 0 || history == 0)
1757
    {
1758
        return;
1759
    }
1760

    
1761
    to_xml_extended(vm_xml, 0);
1762

    
1763
    htmp = new History(oid,
1764
                       history->seq + 1,
1765
                       previous_history->hid,
1766
                       previous_history->hostname,
1767
                       previous_history->cid,
1768
                       previous_history->vmm_mad_name,
1769
                       previous_history->vnm_mad_name,
1770
                       previous_history->tm_mad_name,
1771
                       previous_history->ds_location,
1772
                       previous_history->ds_id,
1773
                       vm_xml);
1774

    
1775
    previous_history = history;
1776
    history          = htmp;
1777

    
1778
    history_records.push_back(history);
1779
}
1780

    
1781
/* -------------------------------------------------------------------------- */
1782
/* -------------------------------------------------------------------------- */
1783

    
1784
void VirtualMachine::get_requirements (int& cpu, int& memory, int& disk,
1785
        vector<VectorAttribute *>& pci_devs)
1786
{
1787
    istringstream   iss;
1788
    float           fcpu;
1789

    
1790
    pci_devs.clear();
1791

    
1792
    if ((get_template_attribute("MEMORY",memory) == false) ||
1793
        (get_template_attribute("CPU",fcpu) == false))
1794
    {
1795
        cpu    = 0;
1796
        memory = 0;
1797
        disk   = 0;
1798

    
1799
        return;
1800
    }
1801

    
1802
    cpu    = (int) (fcpu * 100);//now in 100%
1803
    memory = memory * 1024;     //now in Kilobytes
1804
    disk   = 0;
1805

    
1806
    obj_template->get("PCI", pci_devs);
1807

    
1808
    return;
1809
}
1810

    
1811
/* -------------------------------------------------------------------------- */
1812
/* -------------------------------------------------------------------------- */
1813

    
1814
int VirtualMachine::check_resize (
1815
        float cpu, int memory, int vcpu, string& error_str)
1816
{
1817
    if (cpu < 0)
1818
    {
1819
        error_str = "CPU must be a positive float or integer value.";
1820
        return -1;
1821
    }
1822

    
1823
    if (memory < 0)
1824
    {
1825
        error_str = "MEMORY must be a positive integer value.";
1826
        return -1;
1827
    }
1828

    
1829
    if (vcpu < 0)
1830
    {
1831
        error_str = "VCPU must be a positive integer value.";
1832
        return -1;
1833
    }
1834

    
1835
    return 0;
1836
}
1837

    
1838
/* -------------------------------------------------------------------------- */
1839
/* -------------------------------------------------------------------------- */
1840

    
1841
int VirtualMachine::resize(float cpu, int memory, int vcpu, string& error_str)
1842
{
1843
    ostringstream oss;
1844

    
1845
    int rc = check_resize(cpu, memory, vcpu, error_str);
1846

    
1847
    if (rc != 0)
1848
    {
1849
        return rc;
1850
    }
1851

    
1852
    if (cpu > 0)
1853
    {
1854
        oss << cpu;
1855
        replace_template_attribute("CPU", oss.str());
1856
        oss.str("");
1857
    }
1858

    
1859
    if (memory > 0)
1860
    {
1861
        oss << memory;
1862
        replace_template_attribute("MEMORY", oss.str());
1863
        oss.str("");
1864
    }
1865

    
1866
    if (vcpu > 0)
1867
    {
1868
        oss << vcpu;
1869
        replace_template_attribute("VCPU", oss.str());
1870
    }
1871

    
1872
    return 0;
1873
}
1874

    
1875
/* -------------------------------------------------------------------------- */
1876
/* -------------------------------------------------------------------------- */
1877

    
1878
static void assign_disk_targets(queue<pair <string, VectorAttribute *> >& _queue,
1879
                                set<string>& used_targets)
1880
{
1881
    int    index = 0;
1882
    string target;
1883

    
1884
    pair <string, VectorAttribute *> disk_pair;
1885

    
1886
    while (_queue.size() > 0 )
1887
    {
1888
        disk_pair = _queue.front();
1889
        index     = 0;
1890

    
1891
        do
1892
        {
1893
            target = disk_pair.first + static_cast<char>(('a'+ index));
1894
            index++;
1895
        }
1896
        while ( used_targets.count(target) > 0 && index < 26 );
1897

    
1898
        disk_pair.second->replace("TARGET", target);
1899
        used_targets.insert(target);
1900

    
1901
        _queue.pop();
1902
    }
1903
}
1904

    
1905
/* -------------------------------------------------------------------------- */
1906

    
1907
int VirtualMachine::get_disk_images(string& error_str)
1908
{
1909
    vector<Attribute *> disks;
1910
    vector<Attribute *> context_disks;
1911

    
1912
    int               num_disks, num_context, rc;
1913
    ImagePool *       ipool;
1914
    VectorAttribute * disk;
1915
    vector<int>       acquired_images;
1916

    
1917
    int     image_id;
1918
    string  dev_prefix;
1919
    string  target;
1920

    
1921
    queue<pair <string, VectorAttribute *> > os_disk;
1922
    queue<pair <string, VectorAttribute *> > cdrom_disks;
1923
    queue<pair <string, VectorAttribute *> > datablock_disks;
1924

    
1925
    set<string> used_targets;
1926

    
1927
    ostringstream    oss;
1928
    Image::ImageType img_type;
1929

    
1930
    Nebula& nd = Nebula::instance();
1931
    ipool      = nd.get_ipool();
1932

    
1933
    vector<Attribute*>::iterator it;
1934

    
1935
    num_context = user_obj_template->remove("CONTEXT", context_disks);
1936
    num_disks   = user_obj_template->remove("DISK", disks);
1937

    
1938
    for (it=context_disks.begin(); it != context_disks.end(); )
1939
    {
1940
        if ( (*it)->type() != Attribute::VECTOR )
1941
        {
1942
            delete *it;
1943
            num_context--;
1944
            it = context_disks.erase(it);
1945
        }
1946
        else
1947
        {
1948
            obj_template->set(*it);
1949
            ++it;
1950
        }
1951
    }
1952

    
1953
    for (it=disks.begin(); it != disks.end(); )
1954
    {
1955
        if ( (*it)->type() != Attribute::VECTOR )
1956
        {
1957
            delete *it;
1958
            num_disks--;
1959
            it = disks.erase(it);
1960
        }
1961
        else
1962
        {
1963
            obj_template->set(*it);
1964
            ++it;
1965
        }
1966
    }
1967

    
1968
    if ( num_disks > 20 )
1969
    {
1970
        goto error_max_disks;
1971
    }
1972

    
1973
    // -------------------------------------------------------------------------
1974
    // Set DISK attributes & Targets
1975
    // -------------------------------------------------------------------------
1976
    for(int i=0; i<num_disks; i++)
1977
    {
1978
        Snapshots * snap;
1979

    
1980
        disk = static_cast<VectorAttribute * >(disks[i]);
1981

    
1982
        rc = ipool->acquire_disk(oid,
1983
                                 disk,
1984
                                 i,
1985
                                 img_type,
1986
                                 dev_prefix,
1987
                                 uid,
1988
                                 image_id,
1989
                                 &snap,
1990
                                 error_str);
1991
        if (rc == 0 )
1992
        {
1993
            if (snap != 0)
1994
            {
1995
                if (img_type == Image::OS || img_type == Image::DATABLOCK)
1996
                {
1997
                    snapshots.insert(pair<int, Snapshots *>(i, snap));
1998
                }
1999
                else
2000
                {
2001
                    delete snap;
2002
                }
2003
            }
2004

    
2005
            acquired_images.push_back(image_id);
2006

    
2007
            target = disk->vector_value("TARGET");
2008

    
2009
            if ( !target.empty() )
2010
            {
2011
                if (  used_targets.insert(target).second == false )
2012
                {
2013
                    goto error_duplicated_target;
2014
                }
2015
            }
2016
            else
2017
            {
2018
                switch(img_type)
2019
                {
2020
                    case Image::OS:
2021
                        // The first OS disk gets the first device (a),
2022
                        // other OS's will be managed as DATABLOCK's
2023
                        if ( os_disk.empty() )
2024
                        {
2025
                            os_disk.push( make_pair(dev_prefix, disk) );
2026
                        }
2027
                        else
2028
                        {
2029
                            datablock_disks.push( make_pair(dev_prefix, disk) );
2030
                        }
2031
                        break;
2032

    
2033
                    case Image::CDROM:
2034
                        cdrom_disks.push( make_pair(dev_prefix, disk) );
2035
                        break;
2036

    
2037
                    case Image::DATABLOCK:
2038
                        datablock_disks.push( make_pair(dev_prefix, disk) );
2039
                        break;
2040

    
2041
                    default:
2042
                        break;
2043
                }
2044
            }
2045
        }
2046
        else
2047
        {
2048
            oss << "DISK " << i << ": " << error_str;
2049
            error_str = oss.str();
2050

    
2051
            goto error_common;
2052
        }
2053
    }
2054

    
2055
    // -------------------------------------------------------------------------
2056
    // The context is the last of the cdroms
2057
    // -------------------------------------------------------------------------
2058
    if ( num_context > 0 )
2059
    {
2060
        disk = static_cast<VectorAttribute * >(context_disks[0]);
2061

    
2062
        target = disk->vector_value("TARGET");
2063

    
2064
        if ( !target.empty() )
2065
        {
2066
            if (  used_targets.insert(target).second == false )
2067
            {
2068
                goto error_duplicated_target;
2069
            }
2070
        }
2071
        else
2072
        {
2073
            dev_prefix = disk->vector_value("DEV_PREFIX");
2074

    
2075
            if ( dev_prefix.empty() )
2076
            {
2077
                dev_prefix = ipool->default_cdrom_dev_prefix();
2078
            }
2079

    
2080
            cdrom_disks.push(make_pair(dev_prefix, disk));
2081
        }
2082

    
2083
        // Disk IDs are 0..num-1, context disk is is num
2084
        disk->replace("DISK_ID", num_disks);
2085
    }
2086

    
2087
    assign_disk_targets(os_disk, used_targets);
2088
    assign_disk_targets(cdrom_disks, used_targets);
2089
    assign_disk_targets(datablock_disks, used_targets);
2090

    
2091
    return 0;
2092

    
2093
error_max_disks:
2094
    error_str = "Exceeded the maximum number of disks (20)";
2095
    return -1;
2096

    
2097
error_duplicated_target:
2098
    oss << "Two disks have defined the same target " << target;
2099
    error_str = oss.str();
2100

    
2101
error_common:
2102
    ImageManager *  imagem  = nd.get_imagem();
2103

    
2104
    vector<int>::iterator img_it;
2105

    
2106
    for ( img_it=acquired_images.begin() ; img_it < acquired_images.end(); img_it++ )
2107
    {
2108
        imagem->release_image(oid, *img_it, false);
2109
    }
2110

    
2111
    return -1;
2112
}
2113

    
2114
/* -------------------------------------------------------------------------- */
2115
/* -------------------------------------------------------------------------- */
2116

    
2117
void VirtualMachine::get_disk_info(int&         max_disk_id,
2118
                                   set<string>& used_targets)
2119
{
2120
    vector<VectorAttribute  *> disk;
2121
    VectorAttribute * context;
2122

    
2123
    string target;
2124

    
2125
    int disk_id;
2126
    int num_disks;
2127

    
2128
    max_disk_id = -1;
2129

    
2130
    num_disks = obj_template->get("DISK", disk);
2131

    
2132
    for(int i=0; i<num_disks; i++)
2133
    {
2134
        target = disk[i]->vector_value("TARGET");
2135

    
2136
        if ( !target.empty() )
2137
        {
2138
            used_targets.insert(target);
2139
        }
2140

    
2141
        disk[i]->vector_value("DISK_ID", disk_id);
2142

    
2143
        if ( disk_id > max_disk_id )
2144
        {
2145
            max_disk_id = disk_id;
2146
        }
2147
    }
2148

    
2149
    disk.clear();
2150

    
2151
    context = obj_template->get("CONTEXT");
2152

    
2153
    if ( context != 0 )
2154
    {
2155
        target = context->vector_value("TARGET");
2156

    
2157
        if ( !target.empty() )
2158
        {
2159
            used_targets.insert(target);
2160
        }
2161

    
2162
        context->vector_value("DISK_ID", disk_id);
2163

    
2164
        if ( disk_id > max_disk_id )
2165
        {
2166
            max_disk_id = disk_id;
2167
        }
2168
    }
2169
}
2170

    
2171
/* -------------------------------------------------------------------------- */
2172
/* -------------------------------------------------------------------------- */
2173

    
2174
VectorAttribute * VirtualMachine::set_up_attach_disk(
2175
                int                      vm_id,
2176
                VirtualMachineTemplate * tmpl,
2177
                set<string>&             used_targets,
2178
                int                      max_disk_id,
2179
                int                      uid,
2180
                int&                     image_id,
2181
                Snapshots **             snap,
2182
                string&                  error_str)
2183
{
2184
    VectorAttribute * new_disk;
2185

    
2186
    string target;
2187

    
2188
    Nebula&       nd     = Nebula::instance();
2189
    ImagePool *   ipool  = nd.get_ipool();
2190
    ImageManager* imagem = nd.get_imagem();
2191

    
2192
    string           dev_prefix;
2193
    Image::ImageType img_type;
2194

    
2195
    image_id = -1;
2196
    *snap    = 0;
2197

    
2198
    // -------------------------------------------------------------------------
2199
    // Get the DISK attribute from the template
2200
    // -------------------------------------------------------------------------
2201
    new_disk = tmpl->get("DISK");
2202

    
2203
    if ( new_disk == 0 )
2204
    {
2205
        error_str = "Internal error parsing DISK attribute";
2206
        return 0;
2207
    }
2208

    
2209
    new_disk = new_disk->clone();
2210

    
2211
    // -------------------------------------------------------------------------
2212
    // Acquire the new disk image
2213
    // -------------------------------------------------------------------------
2214
    int rc = ipool->acquire_disk(vm_id,
2215
                                 new_disk,
2216
                                 max_disk_id + 1,
2217
                                 img_type,
2218
                                 dev_prefix,
2219
                                 uid,
2220
                                 image_id,
2221
                                 snap,
2222
                                 error_str);
2223
    if ( rc != 0 )
2224
    {
2225
        delete new_disk;
2226
        return 0;
2227
    }
2228

    
2229
    target = new_disk->vector_value("TARGET");
2230

    
2231
    if ( !target.empty() )
2232
    {
2233
        if (  used_targets.insert(target).second == false )
2234
        {
2235
            ostringstream oss;
2236

    
2237
            oss << "Target " << target << " is already in use.";
2238
            error_str = oss.str();
2239

    
2240
            imagem->release_image(vm_id, image_id, false);
2241

    
2242
            delete new_disk;
2243
            delete *snap;
2244

    
2245
            *snap    = 0;
2246
            image_id = -1;
2247

    
2248
            return 0;
2249
        }
2250
    }
2251
    else
2252
    {
2253
        queue<pair <string, VectorAttribute *> > disks_queue;
2254

    
2255
        disks_queue.push(make_pair(dev_prefix, new_disk));
2256

    
2257
        assign_disk_targets(disks_queue, used_targets);
2258
    }
2259

    
2260
    return new_disk;
2261
}
2262

    
2263
/* -------------------------------------------------------------------------- */
2264
/* -------------------------------------------------------------------------- */
2265

    
2266
int VirtualMachine::set_attach_disk(int disk_id)
2267
{
2268
    VectorAttribute * disk;
2269

    
2270
    disk = get_disk(disk_id);
2271

    
2272
    if ( disk != 0 )
2273
    {
2274
        disk->replace("ATTACH", "YES");
2275
        return 0;
2276
    }
2277

    
2278
    return -1;
2279
}
2280

    
2281
/* -------------------------------------------------------------------------- */
2282
/* -------------------------------------------------------------------------- */
2283

    
2284
VectorAttribute* VirtualMachine::get_attach_disk()
2285
{
2286
    vector<VectorAttribute *> disk;
2287

    
2288
    int num_disks = obj_template->get("DISK", disk);
2289

    
2290
    for(int i=0; i<num_disks; i++)
2291
    {
2292
        if ( disk[i]->vector_value("ATTACH") == "YES" )
2293
        {
2294
            return disk[i];
2295
        }
2296
    }
2297

    
2298
    return 0;
2299
}
2300

    
2301
/* -------------------------------------------------------------------------- */
2302
/* -------------------------------------------------------------------------- */
2303

    
2304
void VirtualMachine::clear_attach_disk()
2305
{
2306
    vector<VectorAttribute *> disks;
2307

    
2308
    int num_disks = obj_template->get("DISK", disks);
2309

    
2310
    for(int i=0; i < num_disks; i++)
2311
    {
2312
        if ( disks[i]->vector_value("ATTACH") == "YES" )
2313
        {
2314
            disks[i]->remove("ATTACH");
2315
            return;
2316
        }
2317
    }
2318
}
2319

    
2320
/* -------------------------------------------------------------------------- */
2321
/* -------------------------------------------------------------------------- */
2322

    
2323
VectorAttribute * VirtualMachine::delete_attach_disk(Snapshots **snap)
2324
{
2325
    vector<VectorAttribute  *> disks;
2326

    
2327
    int num_disks = obj_template->get("DISK", disks);
2328

    
2329
    *snap = 0;
2330

    
2331
    for(int i=0; i<num_disks; i++)
2332
    {
2333
        if ( disks[i]->vector_value("ATTACH") == "YES" )
2334
        {
2335
            int disk_id;
2336

    
2337
            disks[i]->vector_value("DISK_ID", disk_id);
2338

    
2339
            map<int, Snapshots *>::iterator it = snapshots.find(disk_id);
2340

    
2341
            if (it != snapshots.end())
2342
            {
2343
                *snap = it->second;
2344
                snapshots.erase(it);
2345
            }
2346

    
2347
            return static_cast<VectorAttribute *>(obj_template->remove(disks[i]));
2348
        }
2349
    }
2350

    
2351
    return 0;
2352
}
2353

    
2354
/* -------------------------------------------------------------------------- */
2355
/* -------------------------------------------------------------------------- */
2356

    
2357
bool VirtualMachine::is_volatile(const VectorAttribute * disk)
2358
{
2359
    string type = disk->vector_value("TYPE");
2360

    
2361
    one_util::toupper(type);
2362

    
2363
    return ( type == "SWAP" || type == "FS");
2364
}
2365

    
2366
/* -------------------------------------------------------------------------- */
2367
/* -------------------------------------------------------------------------- */
2368

    
2369
bool VirtualMachine::is_persistent(const VectorAttribute * disk)
2370
{
2371
    bool pers_disk;
2372

    
2373
    disk->vector_value("PERSISTENT", pers_disk);
2374

    
2375
    return pers_disk;
2376
}
2377

    
2378
/* -------------------------------------------------------------------------- */
2379
/* -------------------------------------------------------------------------- */
2380

    
2381
bool VirtualMachine::is_imported() const
2382
{
2383
    bool imported = false;
2384

    
2385
    get_template_attribute("IMPORTED", imported);
2386

    
2387
    return imported;
2388
}
2389

    
2390
/* -------------------------------------------------------------------------- */
2391
/* -------------------------------------------------------------------------- */
2392

    
2393
bool VirtualMachine::is_imported_action_supported(History::VMAction action) const
2394
{
2395
    if (!hasHistory())
2396
    {
2397
        return false;
2398
    }
2399

    
2400
    VirtualMachineManager * vmm = Nebula::instance().get_vmm();
2401

    
2402
    return vmm->is_imported_action_supported(get_vmm_mad(), action);
2403
}
2404

    
2405
/* -------------------------------------------------------------------------- */
2406
/* -------------------------------------------------------------------------- */
2407

    
2408
long long VirtualMachine::get_system_disk_size(Template * tmpl)
2409
{
2410
    long long size = 0;
2411
    long long disk_size, snapshot_size;
2412

    
2413
    vector<const VectorAttribute*> disks;
2414

    
2415
    int num_disks = tmpl->get("DISK", disks);
2416

    
2417
    for (int i = 0 ; i < num_disks ; i++)
2418
    {
2419
        if (disks[i]->vector_value("SIZE", disk_size) != 0)
2420
        {
2421
            continue;
2422
        }
2423

    
2424
        if (is_volatile(disks[i]))
2425
        {
2426
            size += disk_size;
2427
        }
2428
        else if ( disk_tm_target(disks[i]) == "SYSTEM")
2429
        {
2430
            size += disk_size;
2431

    
2432
            if (disks[i]->vector_value("DISK_SNAPSHOT_TOTAL_SIZE", snapshot_size) == 0)
2433
            {
2434
                size += snapshot_size;
2435
            }
2436
        }
2437
    }
2438

    
2439
    return size;
2440
}
2441

    
2442
/* -------------------------------------------------------------------------- */
2443
/* -------------------------------------------------------------------------- */
2444

    
2445
string VirtualMachine::disk_tm_target(const VectorAttribute *  disk)
2446
{
2447
    bool    clone;
2448
    string  target;
2449

    
2450
    if (disk->vector_value("CLONE", clone) != 0)
2451
    {
2452
        return "";
2453
    }
2454

    
2455
    if (clone)
2456
    {
2457
        target = disk->vector_value("CLONE_TARGET");
2458
    }
2459
    else
2460
    {
2461
        target = disk->vector_value("LN_TARGET");
2462
    }
2463

    
2464
    return one_util::toupper(target);
2465
}
2466

    
2467
/* -------------------------------------------------------------------------- */
2468
/* -------------------------------------------------------------------------- */
2469

    
2470
VectorAttribute * VirtualMachine::get_attach_nic_info(
2471
                            VirtualMachineTemplate * tmpl,
2472
                            int&                     max_nic_id,
2473
                            string&                  error_str)
2474
{
2475
    vector<VectorAttribute *> nics;
2476
    VectorAttribute * nic;
2477

    
2478
    int nic_id;
2479
    int num_nics;
2480

    
2481
    // -------------------------------------------------------------------------
2482
    // Get the highest NIC_ID
2483
    // -------------------------------------------------------------------------
2484
    max_nic_id = -1;
2485

    
2486
    num_nics = obj_template->get("NIC", nics);
2487

    
2488
    for(int i=0; i<num_nics; i++)
2489
    {
2490
        nics[i]->vector_value("NIC_ID", nic_id);
2491

    
2492
        if ( nic_id > max_nic_id )
2493
        {
2494
            max_nic_id = nic_id;
2495
        }
2496
    }
2497

    
2498
    // -------------------------------------------------------------------------
2499
    // Get the new NIC attribute from the template
2500
    // -------------------------------------------------------------------------
2501
    nic = tmpl->get("NIC");
2502

    
2503
    if ( nic == 0 )
2504
    {
2505
        error_str = "Wrong format or missing NIC attribute";
2506
        return 0;
2507
    }
2508

    
2509
    nic = nic->clone();
2510

    
2511
    merge_nic_defaults(nic);
2512

    
2513
    return nic;
2514
}
2515

    
2516
/* -------------------------------------------------------------------------- */
2517
/* -------------------------------------------------------------------------- */
2518

    
2519
int VirtualMachine::set_up_attach_nic(
2520
                        int                      vm_id,
2521
                        set<int>&                vm_sgs,
2522
                        VectorAttribute *        new_nic,
2523
                        vector<VectorAttribute*> &rules,
2524
                        int                      max_nic_id,
2525
                        int                      uid,
2526
                        string&                  error_str)
2527
{
2528
    Nebula&             nd     = Nebula::instance();
2529
    VirtualNetworkPool* vnpool = nd.get_vnpool();
2530
    SecurityGroupPool*  sgpool = nd.get_secgrouppool();
2531

    
2532
    set<int> nic_sgs;
2533

    
2534
    int rc = vnpool->nic_attribute(PoolObjectSQL::VM,
2535
                        new_nic, max_nic_id+1, uid, vm_id, error_str);
2536

    
2537
    if ( rc == -1 ) //-2 is not using a pre-defined network
2538
    {
2539
        return -1;
2540
    }
2541

    
2542
    get_security_groups(new_nic, nic_sgs);
2543

    
2544
    for (set<int>::iterator it = vm_sgs.begin(); it != vm_sgs.end(); it++)
2545
    {
2546
        nic_sgs.erase(*it);
2547
    }
2548

    
2549
    sgpool->get_security_group_rules(vm_id, nic_sgs, rules);
2550

    
2551
    return 0;
2552
}
2553

    
2554
/* -------------------------------------------------------------------------- */
2555
/* -------------------------------------------------------------------------- */
2556

    
2557
VectorAttribute* VirtualMachine::get_attach_nic()
2558
{
2559
    vector<VectorAttribute  *> nics;
2560
    int num_nics;
2561

    
2562
    num_nics = obj_template->get("NIC", nics);
2563

    
2564
    for(int i=0; i<num_nics; i++)
2565
    {
2566
        if ( nics[i]->vector_value("ATTACH") == "YES" )
2567
        {
2568
            return nics[i];
2569
        }
2570
    }
2571

    
2572
    return 0;
2573
}
2574

    
2575
/* -------------------------------------------------------------------------- */
2576
/* -------------------------------------------------------------------------- */
2577

    
2578
void VirtualMachine::attach_nic_success()
2579
{
2580
    VectorAttribute * nic = get_attach_nic();
2581

    
2582
    if (nic != 0)
2583
    {
2584
        nic->remove("ATTACH");
2585
    }
2586
}
2587

    
2588
/* -------------------------------------------------------------------------- */
2589
/* -------------------------------------------------------------------------- */
2590

    
2591
VectorAttribute * VirtualMachine::attach_nic_failure()
2592
{
2593

    
2594
    VectorAttribute * nic = get_attach_nic();
2595

    
2596
    if (nic == 0)
2597
    {
2598
        return 0;
2599
    }
2600

    
2601
    obj_template->remove(nic);
2602

    
2603
    VectorAttribute * context = obj_template->get("CONTEXT");
2604

    
2605
    if (context != 0)
2606
    {
2607
        int nic_id;
2608

    
2609
        nic->vector_value("NIC_ID", nic_id);
2610

    
2611
        clear_context_network(NETWORK_CONTEXT,  NUM_NETWORK_CONTEXT,  context, nic_id);
2612
        clear_context_network(NETWORK6_CONTEXT, NUM_NETWORK6_CONTEXT, context, nic_id);
2613
    }
2614

    
2615
    return nic;
2616
}
2617

    
2618
/* -------------------------------------------------------------------------- */
2619
/* -------------------------------------------------------------------------- */
2620

    
2621
void VirtualMachine::detach_nic_failure()
2622
{
2623
    bool   net_context;
2624
    string err;
2625

    
2626
    VectorAttribute * nic = get_attach_nic();
2627

    
2628
    if (nic == 0)
2629
    {
2630
        return;
2631
    }
2632

    
2633
    nic->remove("ATTACH");
2634

    
2635
    VectorAttribute * context = obj_template->get("CONTEXT");
2636

    
2637
    if (context == 0)
2638
    {
2639
        return;
2640
    }
2641

    
2642
    context->vector_value("NETWORK", net_context);
2643

    
2644
    if (net_context)
2645
    {
2646
        parse_context_network(NETWORK_CONTEXT, NUM_NETWORK_CONTEXT,
2647
                context, nic);
2648

    
2649
        if (!nic->vector_value("IP6_GLOBAL").empty())
2650
        {
2651
            parse_context_network(NETWORK6_CONTEXT, NUM_NETWORK6_CONTEXT,
2652
                    context, nic);
2653
        }
2654

    
2655
        parse_context_variables(&context, err);
2656
    }
2657
}
2658

    
2659
/* -------------------------------------------------------------------------- */
2660
/* -------------------------------------------------------------------------- */
2661

    
2662
VectorAttribute * VirtualMachine::detach_nic_success()
2663
{
2664
    VectorAttribute * nic = get_attach_nic();
2665

    
2666
    if (nic == 0)
2667
    {
2668
        return 0;
2669
    }
2670

    
2671
    obj_template->remove(nic);
2672

    
2673
    return nic;
2674
}
2675

    
2676
/* -------------------------------------------------------------------------- */
2677
/* -------------------------------------------------------------------------- */
2678

    
2679
void VirtualMachine::set_attach_nic(
2680
        VectorAttribute *       new_nic,
2681
        vector<VectorAttribute*> &rules)
2682
{
2683
    bool   net_context;
2684
    string err;
2685

    
2686
    vector<VectorAttribute*>::iterator it;
2687

    
2688
    new_nic->replace("ATTACH", "YES");
2689

    
2690
    obj_template->set(new_nic);
2691

    
2692
    for(it = rules.begin(); it != rules.end(); it++ )
2693
    {
2694
        obj_template->set(*it);
2695
    }
2696

    
2697
    VectorAttribute * context = obj_template->get("CONTEXT");
2698

    
2699
    if (context == 0)
2700
    {
2701
        return;
2702
    }
2703

    
2704
    context->vector_value("NETWORK", net_context);
2705

    
2706
    if (net_context)
2707
    {
2708
        parse_context_network(NETWORK_CONTEXT, NUM_NETWORK_CONTEXT,
2709
                context, new_nic);
2710

    
2711
        if (!new_nic->vector_value("IP6_GLOBAL").empty())
2712
        {
2713
            parse_context_network(NETWORK6_CONTEXT, NUM_NETWORK6_CONTEXT,
2714
                    context, new_nic);
2715
        }
2716

    
2717
        parse_context_variables(&context, err);
2718
    }
2719
}
2720

    
2721
/* -------------------------------------------------------------------------- */
2722
/* -------------------------------------------------------------------------- */
2723

    
2724
int VirtualMachine::set_detach_nic(int nic_id)
2725
{
2726
    int n_id;
2727

    
2728
    vector<VectorAttribute *> nics;
2729

    
2730
    bool found = false;
2731

    
2732
    int num_nics = obj_template->get("NIC", nics);
2733

    
2734
    for(int i=0; !found && i<num_nics; i++)
2735
    {
2736
        nics[i]->vector_value("NIC_ID", n_id);
2737

    
2738
        if ( n_id == nic_id )
2739
        {
2740
            nics[i]->replace("ATTACH", "YES");
2741
            found = true;
2742
        }
2743
    }
2744

    
2745
    if (!found)
2746
    {
2747
        return -1;
2748
    }
2749

    
2750
    VectorAttribute * context = obj_template->get("CONTEXT");
2751

    
2752
    if (context != 0)
2753
    {
2754
        clear_context_network(NETWORK_CONTEXT,  NUM_NETWORK_CONTEXT,
2755
                            context, nic_id);
2756

    
2757
        clear_context_network(NETWORK6_CONTEXT, NUM_NETWORK6_CONTEXT,
2758
                            context, nic_id);
2759
    }
2760

    
2761
    return 0;
2762
}
2763

    
2764
/* -------------------------------------------------------------------------- */
2765
/* -------------------------------------------------------------------------- */
2766

    
2767
void VirtualMachine::release_disk_images()
2768
{
2769
    int iid;
2770
    int num_disks;
2771
    int did = -1;
2772

    
2773
    bool img_error;
2774

    
2775
    vector<const VectorAttribute * > disks;
2776
    ImageManager *              imagem;
2777

    
2778
    string  disk_base_path = "";
2779

    
2780
    Nebula& nd = Nebula::instance();
2781
    imagem     = nd.get_imagem();
2782

    
2783
    num_disks  = get_template_attribute("DISK",disks);
2784

    
2785
    for(int i=0; i<num_disks; i++)
2786
    {
2787
        img_error = (state == ACTIVE && lcm_state != EPILOG) &&
2788
                     state != PENDING && state != HOLD;
2789

    
2790
        if ( disks[i]->vector_value("IMAGE_ID", iid) == 0 )
2791
        {
2792
            disks[i]->vector_value("DISK_ID", did);
2793

    
2794
            map<int, Snapshots *>::iterator it = snapshots.find(did);
2795

    
2796
            if (it != snapshots.end())
2797
            {
2798
                imagem->set_image_snapshots(iid, *(it->second));
2799
            }
2800

    
2801
            imagem->release_image(oid, iid, img_error);
2802
        }
2803
    }
2804
}
2805

    
2806
/* -------------------------------------------------------------------------- */
2807
/* -------------------------------------------------------------------------- */
2808

    
2809
int VirtualMachine::new_snapshot(string& name, int& snap_id)
2810
{
2811
    int num_snaps;
2812
    int id;
2813
    int max_id = -1;
2814

    
2815
    vector<VectorAttribute *> snaps;
2816

    
2817
    num_snaps = obj_template->get("SNAPSHOT", snaps);
2818

    
2819
    for(int i=0; i<num_snaps; i++)
2820
    {
2821
        snaps[i]->vector_value("SNAPSHOT_ID", id);
2822

    
2823
        if (id > max_id)
2824
        {
2825
            max_id = id;
2826
        }
2827
    }
2828

    
2829
    snap_id = max_id + 1;
2830

    
2831
    if (name.empty())
2832
    {
2833
        ostringstream oss;
2834

    
2835
        oss << "snapshot-" << snap_id;
2836

    
2837
        name = oss.str();
2838
    }
2839

    
2840
    VectorAttribute * snap = new VectorAttribute("SNAPSHOT");
2841
    snap->replace("SNAPSHOT_ID", snap_id);
2842
    snap->replace("NAME", name);
2843
    snap->replace("TIME", (int)time(0));
2844
    snap->replace("HYPERVISOR_ID", "");
2845

    
2846
    snap->replace("ACTIVE", "YES");
2847

    
2848
    obj_template->set(snap);
2849

    
2850
    return 0;
2851
}
2852

    
2853
/* -------------------------------------------------------------------------- */
2854
/* -------------------------------------------------------------------------- */
2855

    
2856
int VirtualMachine::set_active_snapshot(int snap_id)
2857
{
2858
    int s_id;
2859

    
2860
    vector<VectorAttribute *> snaps;
2861
    int num_snaps = obj_template->get("SNAPSHOT", snaps);
2862

    
2863
    for(int i=0; i<num_snaps; i++)
2864
    {
2865
        snaps[i]->vector_value("SNAPSHOT_ID", s_id);
2866

    
2867
        if ( s_id == snap_id )
2868
        {
2869
            snaps[i]->replace("ACTIVE", "YES");
2870
            return 0;
2871
        }
2872
    }
2873

    
2874
    return -1;
2875
}
2876

    
2877
/* -------------------------------------------------------------------------- */
2878
/* -------------------------------------------------------------------------- */
2879

    
2880
void VirtualMachine::update_snapshot_id(string& hypervisor_id)
2881
{
2882
    vector<VectorAttribute  *> snaps;
2883
    int num_snaps = obj_template->get("SNAPSHOT", snaps);
2884

    
2885
    for(int i=0; i<num_snaps; i++)
2886
    {
2887
        if ( snaps[i]->vector_value("ACTIVE") == "YES" )
2888
        {
2889
            snaps[i]->replace("HYPERVISOR_ID", hypervisor_id);
2890
            break;
2891
        }
2892
    }
2893
}
2894

    
2895
/* -------------------------------------------------------------------------- */
2896
/* -------------------------------------------------------------------------- */
2897

    
2898
void VirtualMachine::clear_active_snapshot()
2899
{
2900
    vector<VectorAttribute  *> snaps;
2901

    
2902
    int num_snaps = obj_template->get("SNAPSHOT", snaps);
2903

    
2904
    for(int i=0; i<num_snaps; i++)
2905
    {
2906
        if ( snaps[i]->vector_value("ACTIVE") == "YES" )
2907
        {
2908
            snaps[i]->remove("ACTIVE");
2909
            return;
2910
        }
2911
    }
2912
}
2913

    
2914
/* -------------------------------------------------------------------------- */
2915
/* -------------------------------------------------------------------------- */
2916

    
2917
void VirtualMachine::delete_active_snapshot()
2918
{
2919
    vector<VectorAttribute *> snaps;
2920
    int num_snaps = obj_template->get("SNAPSHOT", snaps);
2921

    
2922
    for(int i=0; i<num_snaps; i++)
2923
    {
2924
        if ( snaps[i]->vector_value("ACTIVE") == "YES" )
2925
        {
2926
            delete obj_template->remove(snaps[i]);
2927

    
2928
            return;
2929
        }
2930
    }
2931
}
2932

    
2933
/* -------------------------------------------------------------------------- */
2934
/* -------------------------------------------------------------------------- */
2935

    
2936
void VirtualMachine::delete_snapshots()
2937
{
2938
    obj_template->erase("SNAPSHOT");
2939
}
2940

    
2941
/* -------------------------------------------------------------------------- */
2942
/* -------------------------------------------------------------------------- */
2943

    
2944
int VirtualMachine::get_network_leases(string& estr)
2945
{
2946
    int                   num_nics, rc;
2947
    vector<Attribute  * > nics;
2948
    VectorAttribute *     nic;
2949

    
2950
    Nebula& nd = Nebula::instance();
2951
    VirtualNetworkPool * vnpool = nd.get_vnpool();
2952
    SecurityGroupPool*   sgpool = nd.get_secgrouppool();
2953

    
2954
    vector<VectorAttribute*> sg_rules;
2955

    
2956
    set<int> vm_sgs;
2957

    
2958
    num_nics = user_obj_template->remove("NIC",nics);
2959

    
2960
    for (vector<Attribute*>::iterator it=nics.begin(); it != nics.end(); )
2961
    {
2962
        if ( (*it)->type() != Attribute::VECTOR )
2963
        {
2964
            delete *it;
2965
            num_nics--;
2966
            it = nics.erase(it);
2967
        }
2968
        else
2969
        {
2970
            obj_template->set(*it);
2971
            ++it;
2972
        }
2973
    }
2974

    
2975
    for(int i=0; i<num_nics; i++)
2976
    {
2977
        nic = static_cast<VectorAttribute * >(nics[i]);
2978

    
2979
        merge_nic_defaults(nic);
2980

    
2981
        rc = vnpool->nic_attribute(PoolObjectSQL::VM, nic, i, uid, oid, estr);
2982

    
2983
        if (rc == -1)
2984
        {
2985
            return -1;
2986
        }
2987
    }
2988

    
2989
    get_security_groups(vm_sgs);
2990

    
2991
    sgpool->get_security_group_rules(get_oid(), vm_sgs, sg_rules);
2992

    
2993
    obj_template->set(sg_rules);
2994

    
2995
    return 0;
2996
}
2997

    
2998
/* -------------------------------------------------------------------------- */
2999
/* -------------------------------------------------------------------------- */
3000

    
3001
void VirtualMachine::merge_nic_defaults(VectorAttribute* nic)
3002
{
3003
    VectorAttribute * nic_def = obj_template->get("NIC_DEFAULT");
3004

    
3005
    if (nic_def == 0)
3006
    {
3007
        return;
3008
    }
3009

    
3010
    nic->merge(nic_def, false);
3011
}
3012

    
3013
/* -------------------------------------------------------------------------- */
3014
/* -------------------------------------------------------------------------- */
3015

    
3016
void VirtualMachine::release_network_leases()
3017
{
3018
    string vnid;
3019
    string ip;
3020

    
3021
    vector<VectorAttribute const  * > nics;
3022
    int num_nics = get_template_attribute("NIC",nics);
3023

    
3024
    for(int i=0; i<num_nics; i++)
3025
    {
3026
        release_network_leases(nics[i], oid);
3027
    }
3028
}
3029

    
3030
/* -------------------------------------------------------------------------- */
3031
/* -------------------------------------------------------------------------- */
3032

    
3033
int VirtualMachine::release_network_leases(const VectorAttribute * nic, int vmid)
3034
{
3035
    VirtualNetworkPool* vnpool = Nebula::instance().get_vnpool();
3036
    SecurityGroupPool*  sgpool = Nebula::instance().get_secgrouppool();
3037

    
3038
    VirtualNetwork*     vn;
3039

    
3040
    int     vnid;
3041
    int     ar_id;
3042
    string  mac;
3043
    string  error_msg;
3044

    
3045
    set<int> sgs;
3046

    
3047
    if ( nic == 0 )
3048
    {
3049
        return -1;
3050
    }
3051

    
3052
    get_security_groups(nic, sgs);
3053

    
3054
    sgpool->release_security_groups(vmid, sgs);
3055

    
3056
    if (nic->vector_value("NETWORK_ID", vnid) != 0)
3057
    {
3058
        return -1;
3059
    }
3060

    
3061
    mac = nic->vector_value("MAC");
3062

    
3063
    if (mac.empty())
3064
    {
3065
        return -1;
3066
    }
3067

    
3068
    vn = vnpool->get(vnid, true);
3069

    
3070
    if ( vn == 0 )
3071
    {
3072
        return -1;
3073
    }
3074

    
3075
    if (nic->vector_value("AR_ID", ar_id) == 0)
3076
    {
3077
        vn->free_addr(ar_id, PoolObjectSQL::VM, vmid, mac);
3078
    }
3079
    else
3080
    {
3081
        vn->free_addr(PoolObjectSQL::VM, vmid, mac);
3082
    }
3083

    
3084
    vnpool->update(vn);
3085

    
3086
    vn->unlock();
3087

    
3088
    return 0;
3089
}
3090

    
3091
/* -------------------------------------------------------------------------- */
3092
/* -------------------------------------------------------------------------- */
3093

    
3094
void VirtualMachine::get_security_groups(set<int>& sgs) const
3095
{
3096
    vector<VectorAttribute *> ns;
3097

    
3098
    int num_nics = obj_template->get("NIC", ns);
3099

    
3100
    for(int i=0; i<num_nics; i++)
3101
    {
3102
        get_security_groups(ns[i], sgs);
3103
    }
3104
}
3105

    
3106
/* -------------------------------------------------------------------------- */
3107
/* -------------------------------------------------------------------------- */
3108

    
3109
void VirtualMachine::remove_security_group(int sgid)
3110
{
3111
    int num_sgs;
3112
    int ssgid;
3113

    
3114
    vector<VectorAttribute  *> sgs;
3115

    
3116
    num_sgs = obj_template->get("SECURITY_GROUP_RULE", sgs);
3117

    
3118
    for(int i=0; i<num_sgs; i++)
3119
    {
3120
        sgs[i]->vector_value("SECURITY_GROUP_ID", ssgid);
3121

    
3122
        if ( ssgid == sgid )
3123
        {
3124
            obj_template->remove(sgs[i]);
3125
            delete sgs[i];
3126
        }
3127
    }
3128
}
3129

    
3130
/* -------------------------------------------------------------------------- */
3131
/* -------------------------------------------------------------------------- */
3132

    
3133
int VirtualMachine::get_vrouter_id()
3134
{
3135
    int vrid;
3136

    
3137
    if (!obj_template->get("VROUTER_ID", vrid))
3138
    {
3139
        vrid = -1;
3140
    }
3141

    
3142
    return vrid;
3143
}
3144

    
3145
/* -------------------------------------------------------------------------- */
3146
/* -------------------------------------------------------------------------- */
3147

    
3148
bool VirtualMachine::is_vrouter()
3149
{
3150
    return get_vrouter_id() != -1;
3151
}
3152

    
3153
/* -------------------------------------------------------------------------- */
3154
/* -------------------------------------------------------------------------- */
3155

    
3156

    
3157
int VirtualMachine::generate_context(string &files, int &disk_id,
3158
        const string& token_password)
3159
{
3160
    ofstream file;
3161
    string   files_ds;
3162

    
3163
    vector<const VectorAttribute*> attrs;
3164

    
3165
    map<string, string>::const_iterator it;
3166

    
3167
    files = "";
3168
    bool token;
3169

    
3170
    if ( history == 0 )
3171
    {
3172
        return -1;
3173
    }
3174

    
3175
    const VectorAttribute * context = obj_template->get("CONTEXT");
3176

    
3177
    if ( context == 0 )
3178
    {
3179
        log("VM", Log::INFO, "Virtual Machine has no context");
3180
        return 0;
3181
    }
3182

    
3183
    file.open(history->context_file.c_str(),ios::out);
3184

    
3185
    if (file.fail() == true)
3186
    {
3187
        ostringstream oss;
3188

    
3189
        oss << "Could not open context file: " << history->context_file;
3190
        log("VM", Log::ERROR, oss);
3191
        return -1;
3192
    }
3193

    
3194
    files    = context->vector_value("FILES");
3195
    files_ds = context->vector_value("FILES_DS");
3196

    
3197
    if (!files_ds.empty())
3198
    {
3199
        files += " ";
3200
        files += files_ds;
3201
    }
3202

    
3203
    for (size_t i=0;i<files.length();i++)
3204
    {
3205
        if (files[i] == '\n')
3206
        {
3207
            files[i] = ' ';
3208
        }
3209
    }
3210

    
3211
    context->vector_value("TOKEN", token);
3212

    
3213
    if (token)
3214
    {
3215
        ofstream      token_file;
3216
        ostringstream oss;
3217

    
3218
        string* encrypted;
3219
        string  tk_error;
3220

    
3221
        if (token_password.empty())
3222
        {
3223
            tk_error = "CONTEXT/TOKEN set, but TOKEN_PASSWORD is not defined"
3224
                " in the user template.";
3225

    
3226
            file.close();
3227

    
3228
            log("VM", Log::ERROR, tk_error.c_str());
3229
            set_template_error_message(tk_error);
3230

    
3231
            return -1;
3232
        }
3233

    
3234
        token_file.open(history->token_file.c_str(), ios::out);
3235

    
3236
        if (token_file.fail())
3237
        {
3238
            tk_error = "Cannot create token file";
3239

    
3240
            file.close();
3241

    
3242
            log("VM", Log::ERROR, tk_error.c_str());
3243
            set_template_error_message(tk_error);
3244

    
3245
            return -1;
3246
        }
3247

    
3248
        oss << oid << ':' << stime;
3249

    
3250
        encrypted = one_util::aes256cbc_encrypt(oss.str(), token_password);
3251

    
3252
        token_file << *encrypted << endl;
3253

    
3254
        token_file.close();
3255

    
3256
        delete encrypted;
3257

    
3258
        files += (" " + history->token_file);
3259
    }
3260

    
3261
    const map<string, string> values = context->value();
3262

    
3263
    file << "# Context variables generated by OpenNebula\n";
3264

    
3265
    for (it=values.begin(); it != values.end(); it++ )
3266
    {
3267
        //Replace every ' in value by '\''
3268
        string escape_str(it->second);
3269
        size_t pos = 0;
3270

    
3271
        while ((pos = escape_str.find('\'', pos)) != string::npos)
3272
        {
3273
            escape_str.replace(pos,1,"'\\''");
3274
            pos = pos + 4;
3275
        }
3276

    
3277
        file << it->first <<"='" << escape_str << "'" << endl;
3278
    }
3279

    
3280
    file.close();
3281

    
3282
    context->vector_value("DISK_ID", disk_id);
3283

    
3284
    return 1;
3285
}
3286

    
3287
/* -------------------------------------------------------------------------- */
3288
/* -------------------------------------------------------------------------- */
3289

    
3290
int VirtualMachine::get_created_by_uid() const
3291
{
3292
    int created_by_uid;
3293

    
3294
    if (obj_template->get("CREATED_BY", created_by_uid))
3295
    {
3296
        return created_by_uid;
3297
    }
3298

    
3299
    return get_uid();
3300
}
3301

    
3302

    
3303
/* -------------------------------------------------------------------------- */
3304
/* -------------------------------------------------------------------------- */
3305

    
3306
const VectorAttribute* VirtualMachine::get_disk(int disk_id) const
3307
{
3308
    int tdisk_id;
3309

    
3310
    vector<const VectorAttribute  *> disks;
3311
    int num_disks = obj_template->get("DISK", disks);
3312

    
3313
    for(int i=0; i<num_disks; i++)
3314
    {
3315
        disks[i]->vector_value("DISK_ID", tdisk_id);
3316

    
3317
        if ( tdisk_id == disk_id )
3318
        {
3319
            return disks[i];
3320
        }
3321
    }
3322

    
3323
    return 0;
3324
}
3325

    
3326
/* -------------------------------------------------------------------------- */
3327
/* -------------------------------------------------------------------------- */
3328

    
3329
const VectorAttribute* VirtualMachine::get_nic(int nic_id) const
3330
{
3331
    int num_nics;
3332
    int tnic_id;
3333

    
3334
    vector<const VectorAttribute  *> nics;
3335

    
3336
    num_nics = obj_template->get("NIC", nics);
3337

    
3338
    for(int i=0; i<num_nics; i++)
3339
    {
3340
        nics[i]->vector_value("NIC_ID", tnic_id);
3341

    
3342
        if ( tnic_id == nic_id )
3343
        {
3344
            return nics[i];
3345
        }
3346
    }
3347

    
3348
    return 0;
3349
}
3350

    
3351
/* -------------------------------------------------------------------------- */
3352
/* -------------------------------------------------------------------------- */
3353

    
3354
int VirtualMachine::set_saveas_disk(int disk_id, int snap_id, int &iid,
3355
                                    long long &size, string& err_str)
3356
{
3357
    iid = -1;
3358

    
3359
    VectorAttribute * disk = get_disk(disk_id);
3360

    
3361
    if (disk == 0)
3362
    {
3363
        err_str = "DISK does not exist.";
3364
        return -1;
3365
    }
3366

    
3367
    if (disk->vector_value("IMAGE_ID", iid) != 0)
3368
    {
3369
        iid = -1;
3370
        err_str = "DISK does not have a valid IMAGE_ID.";
3371
        return -1;
3372
    }
3373

    
3374
    const Snapshots * snaps = get_disk_snapshots(disk_id, err_str);
3375

    
3376
    if (snap_id != -1)
3377
    {
3378
        if (snaps == 0 || !snaps->exists(snap_id))
3379
        {
3380
            err_str = "Snapshot does not exist.";
3381
            return -1;
3382
        }
3383
    }
3384

    
3385
    disk->replace("HOTPLUG_SAVE_AS_ACTIVE", "YES");
3386
    disk->replace("HOTPLUG_SAVE_AS_SNAPSHOT_ID", snap_id);
3387

    
3388
    size = 0;
3389
    disk->vector_value("SIZE", size);
3390

    
3391
    return 0;
3392
}
3393

    
3394
/* -------------------------------------------------------------------------- */
3395
/* -------------------------------------------------------------------------- */
3396

    
3397
int VirtualMachine::set_saveas_disk(int disk_id, const string& source, int iid)
3398
{
3399
    if (lcm_state != HOTPLUG_SAVEAS && lcm_state != HOTPLUG_SAVEAS_SUSPENDED
3400
        && lcm_state != HOTPLUG_SAVEAS_POWEROFF )
3401
    {
3402
        return -1;
3403
    }
3404

    
3405
    VectorAttribute * disk = get_disk(disk_id);
3406

    
3407
    if ( disk == 0 )
3408
    {
3409
        return -1;
3410
    }
3411

    
3412
    disk->replace("HOTPLUG_SAVE_AS", iid);
3413
    disk->replace("HOTPLUG_SAVE_AS_SOURCE", source);
3414

    
3415
    return 0;
3416
}
3417

    
3418
/* -------------------------------------------------------------------------- */
3419
/* -------------------------------------------------------------------------- */
3420

    
3421
int VirtualMachine::set_saveas_state()
3422
{
3423
    switch (state)
3424
    {
3425
        case ACTIVE:
3426
            if (lcm_state != RUNNING)
3427
            {
3428
                return -1;
3429
            }
3430

    
3431
            set_state(HOTPLUG_SAVEAS);
3432
            break;
3433

    
3434
        case POWEROFF:
3435
            set_state(ACTIVE);
3436
            set_state(HOTPLUG_SAVEAS_POWEROFF);
3437
            break;
3438

    
3439
        case SUSPENDED:
3440
            set_state(ACTIVE);
3441
            set_state(HOTPLUG_SAVEAS_SUSPENDED);
3442
            break;
3443

    
3444
        default:
3445
            return -1;
3446
    }
3447

    
3448
    return 0;
3449
}
3450

    
3451
/* -------------------------------------------------------------------------- */
3452
/* -------------------------------------------------------------------------- */
3453

    
3454
int VirtualMachine::clear_saveas_state()
3455
{
3456
    switch (lcm_state)
3457
    {
3458
        case HOTPLUG_SAVEAS:
3459
            set_state(RUNNING);
3460
            break;
3461

    
3462
        case HOTPLUG_SAVEAS_POWEROFF:
3463
            set_state(POWEROFF);
3464
            set_state(LCM_INIT);
3465
            break;
3466

    
3467
        case HOTPLUG_SAVEAS_SUSPENDED:
3468
            set_state(SUSPENDED);
3469
            set_state(LCM_INIT);
3470
            break;
3471

    
3472
        default:
3473
            return -1;
3474
    }
3475

    
3476
    return 0;
3477
}
3478

    
3479
/* -------------------------------------------------------------------------- */
3480
/* -------------------------------------------------------------------------- */
3481

    
3482
int VirtualMachine::clear_saveas_disk()
3483
{
3484
    vector<VectorAttribute  *> disks;
3485

    
3486
    int  image_id;
3487
    bool active;
3488

    
3489
    int num_disks = obj_template->get("DISK", disks);
3490

    
3491
    for(int i=0; i<num_disks; i++)
3492
    {
3493
        disks[i]->vector_value("HOTPLUG_SAVE_AS_ACTIVE", active);
3494

    
3495
        if (active)
3496
        {
3497
            disks[i]->vector_value("HOTPLUG_SAVE_AS", image_id);
3498

    
3499
            disks[i]->remove("HOTPLUG_SAVE_AS_ACTIVE");
3500
            disks[i]->remove("HOTPLUG_SAVE_AS");
3501
            disks[i]->remove("HOTPLUG_SAVE_AS_SOURCE");
3502
            disks[i]->remove("HOTPLUG_SAVE_AS_SNAPSHOT_ID");
3503

    
3504
            return image_id;
3505
        }
3506
    }
3507

    
3508
    return -1;
3509
}
3510

    
3511

    
3512
/* -------------------------------------------------------------------------- */
3513
/* -------------------------------------------------------------------------- */
3514

    
3515
int VirtualMachine::get_saveas_disk(int& disk_id, string& source,
3516
        int& image_id, string& snap_id, string& tm_mad, string& ds_id)
3517
{
3518
    vector<VectorAttribute  *> disks;
3519

    
3520
    int rc;
3521
    int num_disks = obj_template->get("DISK", disks);
3522

    
3523
    for(int i=0; i<num_disks; i++)
3524
    {
3525
        if ( disks[i]->vector_value("HOTPLUG_SAVE_AS_ACTIVE") == "YES" )
3526
        {
3527
            rc  = disks[i]->vector_value("HOTPLUG_SAVE_AS_SOURCE", source);
3528
            rc += disks[i]->vector_value("HOTPLUG_SAVE_AS", image_id);
3529
            rc += disks[i]->vector_value("HOTPLUG_SAVE_AS_SNAPSHOT_ID", snap_id);
3530
            rc += disks[i]->vector_value("DISK_ID",  disk_id);
3531
            rc += disks[i]->vector_value("DATASTORE_ID", ds_id);
3532
            rc += disks[i]->vector_value("TM_MAD", tm_mad);
3533

    
3534
            return rc;
3535
        }
3536
    }
3537

    
3538
    return -1;
3539
}
3540

    
3541
/* -------------------------------------------------------------------------- */
3542
/* -------------------------------------------------------------------------- */
3543

    
3544
void VirtualMachine::set_auth_request(int uid,
3545
                                      AuthRequest& ar,
3546
                                      VirtualMachineTemplate *tmpl)
3547
{
3548
    int num;
3549
    vector<VectorAttribute  *> vectors;
3550

    
3551
    Nebula& nd = Nebula::instance();
3552

    
3553
    ImagePool *          ipool  = nd.get_ipool();
3554
    VirtualNetworkPool * vnpool = nd.get_vnpool();
3555
    SecurityGroupPool *  sgpool = nd.get_secgrouppool();
3556

    
3557
    set<int>        sgroups;
3558
    SecurityGroup * sgroup;
3559

    
3560
    num = tmpl->get("DISK", vectors);
3561

    
3562
    for(int i=0; i<num; i++)
3563
    {
3564
        ipool->authorize_disk(vectors[i], uid, &ar);
3565
    }
3566

    
3567
    vectors.clear();
3568

    
3569
    num = tmpl->get("NIC", vectors);
3570

    
3571
    for(int i=0; i<num; i++, sgroups.clear())
3572
    {
3573
        vnpool->authorize_nic(PoolObjectSQL::VM, vectors[i], uid, &ar);
3574

    
3575
        get_security_groups(vectors[i], sgroups);
3576

    
3577
        for(set<int>::iterator it = sgroups.begin(); it != sgroups.end(); it++)
3578
        {
3579
            sgroup = sgpool->get(*it, true);
3580

    
3581
            if(sgroup != 0)
3582
            {
3583
                PoolObjectAuth perm;
3584
                sgroup->get_permissions(perm);
3585

    
3586
                sgroup->unlock();
3587

    
3588
                ar.add_auth(AuthRequest::USE, perm);
3589
            }
3590
        }
3591
    }
3592
}
3593

    
3594
/* -------------------------------------------------------------------------- */
3595
/* -------------------------------------------------------------------------- */
3596

    
3597
void VirtualMachine::disk_extended_info(int uid,
3598
                                       VirtualMachineTemplate *tmpl)
3599
{
3600
    ImagePool * ipool  = Nebula::instance().get_ipool();
3601

    
3602
    vector<VectorAttribute  * > disks;
3603
    int num = tmpl->get("DISK",disks);
3604

    
3605
    for(int i=0; i<num; i++)
3606
    {
3607
        ipool->disk_attribute(disks[i], i, uid);
3608
    }
3609
}
3610

    
3611
/* -------------------------------------------------------------------------- */
3612
/* -------------------------------------------------------------------------- */
3613

    
3614
bool VirtualMachine::volatile_disk_extended_info(Template *tmpl)
3615
{
3616
    int  num;
3617
    vector<VectorAttribute  * > disks;
3618
    DatastorePool * ds_pool = Nebula::instance().get_dspool();
3619

    
3620
    bool found = false;
3621

    
3622
    num = tmpl->get("DISK", disks);
3623

    
3624
    for(int i=0; i<num; i++)
3625
    {
3626
        if ( !is_volatile(disks[i]) )
3627
        {
3628
            continue;
3629
        }
3630

    
3631
        found = true;
3632

    
3633
        if (hasHistory())
3634
        {
3635
            ds_pool->disk_attribute(get_ds_id(), disks[i]);
3636
        }
3637
    }
3638

    
3639
    return found;
3640
}
3641

    
3642
/* -------------------------------------------------------------------------- */
3643
/* -------------------------------------------------------------------------- */
3644

    
3645
pthread_mutex_t VirtualMachine::lex_mutex = PTHREAD_MUTEX_INITIALIZER;
3646

    
3647
extern "C"
3648
{
3649
    typedef struct yy_buffer_state * YY_BUFFER_STATE;
3650

    
3651
    int vm_var_parse (VirtualMachine * vm,
3652
                      ostringstream *  parsed,
3653
                      char **          errmsg);
3654

    
3655
    int vm_file_var_parse (VirtualMachine * vm,
3656
                           vector<int> *    img_ids,
3657
                           char **          errmsg);
3658

    
3659
    int vm_var_lex_destroy();
3660

    
3661
    YY_BUFFER_STATE vm_var__scan_string(const char * str);
3662

    
3663
    void vm_var__delete_buffer(YY_BUFFER_STATE);
3664
}
3665

    
3666
/* -------------------------------------------------------------------------- */
3667

    
3668
int VirtualMachine::parse_template_attribute(const string& attribute,
3669
                                             string&       parsed,
3670
                                             string&       error_str)
3671
{
3672
    YY_BUFFER_STATE  str_buffer = 0;
3673
    const char *     str;
3674
    int              rc;
3675
    ostringstream    oss_parsed;
3676
    char *           error_msg = 0;
3677

    
3678
    pthread_mutex_lock(&lex_mutex);
3679

    
3680
    str        = attribute.c_str();
3681
    str_buffer = vm_var__scan_string(str);
3682

    
3683
    if (str_buffer == 0)
3684
    {
3685
        goto error_yy;
3686
    }
3687

    
3688
    rc = vm_var_parse(this, &oss_parsed, &error_msg);
3689

    
3690
    vm_var__delete_buffer(str_buffer);
3691

    
3692
    vm_var_lex_destroy();
3693

    
3694
    pthread_mutex_unlock(&lex_mutex);
3695

    
3696
    if ( rc != 0 && error_msg != 0 )
3697
    {
3698
        ostringstream oss;
3699

    
3700
        oss << "Error parsing: " << attribute << ". " << error_msg;
3701
        log("VM", Log::ERROR, oss);
3702

    
3703
        error_str = oss.str();
3704

    
3705
        free(error_msg);
3706
    }
3707

    
3708
    parsed = oss_parsed.str();
3709

    
3710
    return rc;
3711

    
3712
error_yy:
3713
    log("VM",Log::ERROR,"Error setting scan buffer");
3714
    pthread_mutex_unlock(&lex_mutex);
3715
    return -1;
3716
}
3717

    
3718
/* -------------------------------------------------------------------------- */
3719

    
3720
int VirtualMachine::parse_file_attribute(string       attribute,
3721
                                         vector<int>& img_ids,
3722
                                         string&      error)
3723
{
3724
    YY_BUFFER_STATE  str_buffer = 0;
3725
    const char *     str;
3726
    int              rc;
3727
    ostringstream    oss_parsed;
3728
    char *           error_msg = 0;
3729

    
3730
    size_t non_blank_pos;
3731

    
3732
    //Removes leading blanks from attribute, these are not managed
3733
    //by the parser as it is common to the other VM varibales
3734
    non_blank_pos = attribute.find_first_not_of(" \t\n\v\f\r");
3735

    
3736
    if ( non_blank_pos != string::npos )
3737
    {
3738
        attribute.erase(0, non_blank_pos);
3739
    }
3740

    
3741
    pthread_mutex_lock(&lex_mutex);
3742

    
3743
    str        = attribute.c_str();
3744
    str_buffer = vm_var__scan_string(str);
3745

    
3746
    if (str_buffer == 0)
3747
    {
3748
        goto error_yy;
3749
    }
3750

    
3751
    rc = vm_file_var_parse(this, &img_ids, &error_msg);
3752

    
3753
    vm_var__delete_buffer(str_buffer);
3754

    
3755
    vm_var_lex_destroy();
3756

    
3757
    pthread_mutex_unlock(&lex_mutex);
3758

    
3759
    if ( rc != 0  )
3760
    {
3761
        ostringstream oss;
3762

    
3763
        if ( error_msg != 0 )
3764
        {
3765
            oss << "Error parsing: " << attribute << ". " << error_msg;
3766
            free(error_msg);
3767
        }
3768
        else
3769
        {
3770
            oss << "Unknown error parsing: " << attribute << ".";
3771
        }
3772

    
3773
        error = oss.str();
3774
    }
3775

    
3776
    return rc;
3777

    
3778
error_yy:
3779
    log("VM",Log::ERROR,"Error setting scan buffer");
3780
    pthread_mutex_unlock(&lex_mutex);
3781
    return -1;
3782
}
3783
/* -------------------------------------------------------------------------- */
3784
/* -------------------------------------------------------------------------- */
3785

    
3786
string& VirtualMachine::to_xml_extended(string& xml, int n_history) const
3787
{
3788
    string template_xml;
3789
    string user_template_xml;
3790
    string monitoring_xml;
3791
    string history_xml;
3792
    string perm_xml;
3793
    string snap_xml;
3794

    
3795
    ostringstream   oss;
3796

    
3797
    oss << "<VM>"
3798
        << "<ID>"        << oid       << "</ID>"
3799
        << "<UID>"       << uid       << "</UID>"
3800
        << "<GID>"       << gid       << "</GID>"
3801
        << "<UNAME>"     << uname     << "</UNAME>"
3802
        << "<GNAME>"     << gname     << "</GNAME>"
3803
        << "<NAME>"      << name      << "</NAME>"
3804
        << perms_to_xml(perm_xml)
3805
        << "<LAST_POLL>" << last_poll << "</LAST_POLL>"
3806
        << "<STATE>"     << state     << "</STATE>"
3807
        << "<LCM_STATE>" << lcm_state << "</LCM_STATE>"
3808
        << "<PREV_STATE>"     << prev_state     << "</PREV_STATE>"
3809
        << "<PREV_LCM_STATE>" << prev_lcm_state << "</PREV_LCM_STATE>"
3810
        << "<RESCHED>"   << resched   << "</RESCHED>"
3811
        << "<STIME>"     << stime     << "</STIME>"
3812
        << "<ETIME>"     << etime     << "</ETIME>"
3813
        << "<DEPLOY_ID>" << deploy_id << "</DEPLOY_ID>"
3814
        << monitoring.to_xml(monitoring_xml)
3815
        << obj_template->to_xml(template_xml)
3816
        << user_obj_template->to_xml(user_template_xml);
3817

    
3818
    if ( hasHistory() && n_history > 0 )
3819
    {
3820
        oss << "<HISTORY_RECORDS>";
3821

    
3822
        if ( n_history == 2 )
3823
        {
3824
            for (unsigned int i=0; i < history_records.size(); i++)
3825
            {
3826
                oss << history_records[i]->to_xml(history_xml);
3827
            }
3828
        }
3829
        else
3830
        {
3831
            oss << history->to_xml(history_xml);
3832
        }
3833

    
3834
        oss << "</HISTORY_RECORDS>";
3835
    }
3836
    else
3837
    {
3838
        oss << "<HISTORY_RECORDS/>";
3839
    }
3840

    
3841
    for (map<int, Snapshots *>::const_iterator it = snapshots.begin();
3842
            it != snapshots.end() ; it++)
3843
    {
3844
        oss << it->second->to_xml(snap_xml);
3845
    }
3846

    
3847
    oss << "</VM>";
3848

    
3849
    xml = oss.str();
3850

    
3851
    return xml;
3852
}
3853

    
3854
/* -------------------------------------------------------------------------- */
3855
/* -------------------------------------------------------------------------- */
3856

    
3857
int VirtualMachine::from_xml(const string &xml_str)
3858
{
3859
    vector<xmlNodePtr> content;
3860

    
3861
    int istate;
3862
    int ilcmstate;
3863
    int rc = 0;
3864

    
3865
    // Initialize the internal XML object
3866
    update_from_str(xml_str);
3867

    
3868
    // Get class base attributes
3869
    rc += xpath(oid,       "/VM/ID",    -1);
3870

    
3871
    rc += xpath(uid,       "/VM/UID",   -1);
3872
    rc += xpath(gid,       "/VM/GID",   -1);
3873

    
3874
    rc += xpath(uname,     "/VM/UNAME", "not_found");
3875
    rc += xpath(gname,     "/VM/GNAME", "not_found");
3876
    rc += xpath(name,      "/VM/NAME",  "not_found");
3877

    
3878
    rc += xpath<time_t>(last_poll, "/VM/LAST_POLL", 0);
3879
    rc += xpath(resched, "/VM/RESCHED", 0);
3880

    
3881
    rc += xpath<time_t>(stime, "/VM/STIME", 0);
3882
    rc += xpath<time_t>(etime, "/VM/ETIME", 0);
3883
    rc += xpath(deploy_id, "/VM/DEPLOY_ID","");
3884

    
3885
    // Permissions
3886
    rc += perms_from_xml();
3887

    
3888
    //VM states
3889
    rc += xpath(istate,    "/VM/STATE",     0);
3890
    rc += xpath(ilcmstate, "/VM/LCM_STATE", 0);
3891

    
3892
    state     = static_cast<VmState>(istate);
3893
    lcm_state = static_cast<LcmState>(ilcmstate);
3894

    
3895
    xpath(istate,    "/VM/PREV_STATE",     istate);
3896
    xpath(ilcmstate, "/VM/PREV_LCM_STATE", ilcmstate);
3897

    
3898
    prev_state     = static_cast<VmState>(istate);
3899
    prev_lcm_state = static_cast<LcmState>(ilcmstate);
3900

    
3901
    // Virtual Machine template
3902
    ObjectXML::get_nodes("/VM/TEMPLATE", content);
3903

    
3904
    if (content.empty())
3905
    {
3906
        return -1;
3907
    }
3908
    rc += obj_template->from_xml_node(content[0]);
3909

    
3910
    ObjectXML::free_nodes(content);
3911
    content.clear();
3912

    
3913
    // Virtual Machine Monitoring
3914

    
3915
    ObjectXML::get_nodes("/VM/MONITORING", content);
3916

    
3917
    if (content.empty())
3918
    {
3919
        return -1;
3920
    }
3921

    
3922
    rc += monitoring.from_xml_node(content[0]);
3923

    
3924
    ObjectXML::free_nodes(content);
3925
    content.clear();
3926

    
3927
    // Virtual Machine user template
3928

    
3929
    ObjectXML::get_nodes("/VM/USER_TEMPLATE", content);
3930

    
3931
    if (content.empty())
3932
    {
3933
        return -1;
3934
    }
3935

    
3936
    rc += user_obj_template->from_xml_node(content[0]);
3937

    
3938
    ObjectXML::free_nodes(content);
3939
    content.clear();
3940

    
3941
    // Last history entry
3942

    
3943
    ObjectXML::get_nodes("/VM/HISTORY_RECORDS/HISTORY", content);
3944

    
3945
    if (!content.empty())
3946
    {
3947
        history = new History(oid);
3948
        rc += history->from_xml_node(content[0]);
3949

    
3950
        history_records.resize(history->seq + 1);
3951
        history_records[history->seq] = history;
3952

    
3953
        ObjectXML::free_nodes(content);
3954
        content.clear();
3955
    }
3956

    
3957
    // Virtual Machine user template
3958

    
3959
    ObjectXML::get_nodes("/VM/SNAPSHOTS", content);
3960

    
3961
    for (vector<xmlNodePtr>::iterator it=content.begin();it!=content.end();it++)
3962
    {
3963
        Snapshots * snap = new Snapshots(-1);
3964

    
3965
        rc += snap->from_xml_node(*it);
3966

    
3967
        if ( rc != 0)
3968
        {
3969
            delete snap;
3970
            break;
3971
        }
3972

    
3973
        snapshots.insert(pair<int, Snapshots *>(snap->get_disk_id(), snap));
3974
    }
3975

    
3976
    if (!content.empty())
3977
    {
3978
        ObjectXML::free_nodes(content);
3979
        content.clear();
3980
    }
3981

    
3982
    if (rc != 0)
3983
    {
3984
        return -1;
3985
    }
3986

    
3987
    return 0;
3988
}
3989

    
3990
/* -------------------------------------------------------------------------- */
3991
/* -------------------------------------------------------------------------- */
3992

    
3993
string VirtualMachine::get_system_dir() const
3994
{
3995
    ostringstream oss;
3996

    
3997
    oss << history->ds_location << "/" << history->ds_id << "/"<< oid;
3998

    
3999
    return oss.str();
4000
};
4001

    
4002
/* -------------------------------------------------------------------------- */
4003
/* -------------------------------------------------------------------------- */
4004

    
4005
int VirtualMachine::update_info(const string& monitor_data)
4006
{
4007
    int    rc;
4008
    string error;
4009

    
4010
    ostringstream oss;
4011

    
4012
    last_poll = time(0);
4013

    
4014
    rc = monitoring.update(monitor_data, error);
4015

    
4016
    if ( rc != 0)
4017
    {
4018
        oss << "Ignoring monitoring information, error:" << error
4019
            << ". Monitor information was: " << monitor_data;
4020

    
4021
        NebulaLog::log("VMM", Log::ERROR, oss);
4022

    
4023
        set_template_error_message(oss.str());
4024

    
4025
        log("VMM", Log::ERROR, oss);
4026

    
4027
        return -1;
4028
    }
4029

    
4030
    set_vm_info();
4031

    
4032
    clear_template_monitor_error();
4033

    
4034
    oss << "VM " << oid << " successfully monitored: " << monitor_data;
4035

    
4036
    NebulaLog::log("VMM", Log::DEBUG, oss);
4037

    
4038
    return 0;
4039
};
4040

    
4041
/* -------------------------------------------------------------------------- */
4042
/* -------------------------------------------------------------------------- */
4043

    
4044
int VirtualMachine::replace_template(
4045
        const string&   tmpl_str,
4046
        bool            keep_restricted,
4047
        string&         error)
4048
{
4049
    VirtualMachineTemplate * new_tmpl =
4050
            new VirtualMachineTemplate(false,'=',"USER_TEMPLATE");
4051

    
4052
    if ( new_tmpl == 0 )
4053
    {
4054
        error = "Cannot allocate a new template";
4055
        return -1;
4056
    }
4057

    
4058
    if ( new_tmpl->parse_str_or_xml(tmpl_str, error) != 0 )
4059
    {
4060
        delete new_tmpl;
4061
        return -1;
4062
    }
4063

    
4064
    if (keep_restricted)
4065
    {
4066
        new_tmpl->remove_restricted();
4067

    
4068
        if (user_obj_template != 0)
4069
        {
4070
            user_obj_template->remove_all_except_restricted();
4071

    
4072
            string aux_error;
4073
            new_tmpl->merge(user_obj_template, aux_error);
4074
        }
4075
    }
4076

    
4077
    delete user_obj_template;
4078

    
4079
    user_obj_template = new_tmpl;
4080

    
4081
    return 0;
4082
}
4083

    
4084
/* -------------------------------------------------------------------------- */
4085
/* -------------------------------------------------------------------------- */
4086

    
4087
int VirtualMachine::append_template(
4088
        const string&   tmpl_str,
4089
        bool            keep_restricted,
4090
        string&         error)
4091
{
4092
    VirtualMachineTemplate * new_tmpl =
4093
            new VirtualMachineTemplate(false,'=',"USER_TEMPLATE");
4094

    
4095
    if ( new_tmpl == 0 )
4096
    {
4097
        error = "Cannot allocate a new template";
4098
        return -1;
4099
    }
4100

    
4101
    if ( new_tmpl->parse_str_or_xml(tmpl_str, error) != 0 )
4102
    {
4103
        delete new_tmpl;
4104
        return -1;
4105
    }
4106

    
4107
    if (keep_restricted)
4108
    {
4109
        new_tmpl->remove_restricted();
4110
    }
4111

    
4112
    if (user_obj_template != 0)
4113
    {
4114
        user_obj_template->merge(new_tmpl, error);
4115
        delete new_tmpl;
4116
    }
4117
    else
4118
    {
4119
        user_obj_template = new_tmpl;
4120
    }
4121

    
4122
    return 0;
4123
}
4124

    
4125
/* -------------------------------------------------------------------------- */
4126
/* -------------------------------------------------------------------------- */
4127

    
4128
void VirtualMachine::set_template_error_message(const string& message)
4129
{
4130
    set_template_error_message("ERROR", message);
4131
}
4132

    
4133
/* -------------------------------------------------------------------------- */
4134

    
4135
void VirtualMachine::set_template_error_message(const string& name,
4136
                                               const string& message)
4137
{
4138
    SingleAttribute * attr;
4139
    ostringstream     error_value;
4140

    
4141
    error_value << one_util::log_time() << " : " << message;
4142

    
4143
    attr = new SingleAttribute(name, error_value.str());
4144

    
4145
    user_obj_template->erase(name);
4146
    user_obj_template->set(attr);
4147
}
4148

    
4149
/* -------------------------------------------------------------------------- */
4150
/* -------------------------------------------------------------------------- */
4151

    
4152
void VirtualMachine::clear_template_error_message()
4153
{
4154
    user_obj_template->erase("ERROR");
4155
}
4156

    
4157
/* -------------------------------------------------------------------------- */
4158
/* -------------------------------------------------------------------------- */
4159

    
4160
void VirtualMachine::set_template_monitor_error(const string& message)
4161
{
4162
    set_template_error_message("ERROR_MONITOR", message);
4163
}
4164

    
4165
/* -------------------------------------------------------------------------- */
4166

    
4167
void VirtualMachine::clear_template_monitor_error()
4168
{
4169
    user_obj_template->erase("ERROR_MONITOR");
4170
}
4171

    
4172
/* -------------------------------------------------------------------------- */
4173
/* -------------------------------------------------------------------------- */
4174

    
4175
void VirtualMachine::get_public_clouds(const string& pname, set<string> &clouds) const
4176
{
4177
    vector<VectorAttribute *>                 attrs;
4178
    vector<VectorAttribute *>::const_iterator it;
4179

    
4180
    user_obj_template->get(pname, attrs);
4181

    
4182
    if ( !attrs.empty() && pname == "EC2" )
4183
    {
4184
            clouds.insert("ec2");
4185
    }
4186

    
4187
    for (it = attrs.begin(); it != attrs.end(); it++)
4188
    {
4189
        string type = (*it)->vector_value("TYPE");
4190

    
4191
        if (!type.empty())
4192
        {
4193
            clouds.insert(type);
4194
        }
4195
    }
4196
}
4197

    
4198
/* -------------------------------------------------------------------------- */
4199
/* -------------------------------------------------------------------------- */
4200

    
4201
int VirtualMachine::parse_public_clouds(const char * pname, string& error)
4202
{
4203
    vector<VectorAttribute *>           attrs;
4204
    vector<VectorAttribute *>::iterator it;
4205

    
4206
    string * str;
4207
    string p_vatt;
4208

    
4209
    int rc  = 0;
4210
    int num = user_obj_template->remove(pname, attrs);
4211

    
4212
    for (it = attrs.begin(); it != attrs.end(); it++)
4213
    {
4214
        str = (*it)->marshall();
4215

    
4216
        if ( str == 0 )
4217
        {
4218
            ostringstream oss;
4219
            oss << "Internal error processing " << pname;
4220
            error = oss.str();
4221
            rc    = -1;
4222
            break;
4223
        }
4224

    
4225
        rc = parse_template_attribute(*str, p_vatt, error);
4226

    
4227
        delete str;
4228

    
4229
        if ( rc != 0 )
4230
        {
4231
            rc = -1;
4232
            break;
4233
        }
4234

    
4235
        VectorAttribute * nvatt = new VectorAttribute(pname);
4236

    
4237
        nvatt->unmarshall(p_vatt);
4238

    
4239
        user_obj_template->set(nvatt);
4240
    }
4241

    
4242
    for (int i = 0; i < num ; i++)
4243
    {
4244
        delete attrs[i];
4245
    }
4246

    
4247
    return rc;
4248
}
4249

    
4250
/* -------------------------------------------------------------------------- */
4251
/* -------------------------------------------------------------------------- */
4252

    
4253
int VirtualMachine::set_snapshot_disk(int did, int snap_id)
4254
{
4255
    VectorAttribute * disk;
4256

    
4257
    disk = get_disk(did);
4258

    
4259
    if ( disk == 0 )
4260
    {
4261
        return -1;
4262
    }
4263

    
4264
    disk->replace("DISK_SNAPSHOT_ACTIVE", "YES");
4265
    disk->replace("DISK_SNAPSHOT_ID", snap_id);
4266

    
4267
    return 0;
4268
}
4269

    
4270
/* -------------------------------------------------------------------------- */
4271

    
4272
void VirtualMachine::clear_snapshot_disk()
4273
{
4274
    vector<VectorAttribute  *> disks;
4275
    int num_disks = obj_template->get("DISK", disks);
4276

    
4277
    for(int i=0; i<num_disks; i++)
4278
    {
4279
        if ( disks[i]->vector_value("DISK_SNAPSHOT_ACTIVE") == "YES" )
4280
        {
4281
            disks[i]->remove("DISK_SNAPSHOT_ACTIVE");
4282
            disks[i]->remove("DISK_SNAPSHOT_ID");
4283
            return;
4284
        }
4285
    }
4286
}
4287

    
4288
/* -------------------------------------------------------------------------- */
4289

    
4290
int VirtualMachine::get_snapshot_disk(int& ds_id, string& tm_mad,
4291
        int& disk_id, int& snap_id)
4292
{
4293
    vector<VectorAttribute *> disks;
4294
    int num_disks = obj_template->get("DISK", disks);
4295

    
4296
    for(int i=0; i<num_disks; i++)
4297
    {
4298
        if ( disks[i]->vector_value("DISK_SNAPSHOT_ACTIVE") == "YES" )
4299
        {
4300
            map<int, Snapshots *>::iterator it;
4301
            int did, rc;
4302

    
4303
            if (disks[i]->vector_value("DISK_ID", did) == -1)
4304
            {
4305
                return -1;
4306
            }
4307

    
4308
            it = snapshots.find(did);
4309

    
4310
            if (it == snapshots.end())
4311
            {
4312
                return -1;
4313
            }
4314

    
4315
            tm_mad  = disks[i]->vector_value("TM_MAD");
4316
            rc =  disks[i]->vector_value("DATASTORE_ID", ds_id);
4317
            rc += disks[i]->vector_value("DISK_ID", disk_id);
4318
            rc += disks[i]->vector_value("DISK_SNAPSHOT_ID", snap_id);
4319

    
4320
            if (tm_mad.empty() || rc != 0)
4321
            {
4322
                return -1;
4323
            }
4324

    
4325
            return 0;
4326
        }
4327
    }
4328

    
4329
    return -1;
4330
}
4331

    
4332
/* -------------------------------------------------------------------------- */
4333
/* -------------------------------------------------------------------------- */
4334

    
4335
int VirtualMachine::new_disk_snapshot(int did, const string& name, string& error)
4336
{
4337
    map<int, Snapshots *>::iterator it;
4338
    long long size_mb, snap_size;
4339
    int snap_id;
4340

    
4341
    VectorAttribute * disk;
4342

    
4343
    disk = get_disk(did);
4344

    
4345
    if ( disk == 0 )
4346
    {
4347
        error = "VM disk does not exist";
4348
        return -1;
4349
    }
4350

    
4351
    if (is_volatile(disk))
4352
    {
4353
        error = "Cannot make snapshots on volatile disks";
4354
        return -1;
4355
    }
4356

    
4357
    if (disk->vector_value("SIZE", size_mb) != 0 )
4358
    {
4359
        error = "Wrong size in disk";
4360
        return -1;
4361
    }
4362

    
4363
    it = snapshots.find(did);
4364

    
4365
    if ( it == snapshots.end() )
4366
    {
4367
        Snapshots * snap = new Snapshots(did);
4368

    
4369
        snap_id   = snap->create_snapshot(name, size_mb);
4370
        snap_size = size_mb;
4371

    
4372
        if (snap_id != -1)
4373
        {
4374
            snapshots.insert(pair<int, Snapshots *>(did, snap));
4375
        }
4376
        else
4377
        {
4378
            delete snap;
4379
        }
4380
    }
4381
    else
4382
    {
4383
        snap_id   = it->second->create_snapshot(name, size_mb);
4384
        snap_size = it->second->get_total_size();
4385
    }
4386

    
4387
    if (snap_id != -1)
4388
    {
4389
        disk->replace("DISK_SNAPSHOT_ACTIVE", "YES");
4390
        disk->replace("DISK_SNAPSHOT_ID", snap_id);
4391
        disk->replace("DISK_SNAPSHOT_TOTAL_SIZE", snap_size);
4392
    }
4393

    
4394
    return snap_id;
4395
}
4396

    
4397
/* -------------------------------------------------------------------------- */
4398
/* -------------------------------------------------------------------------- */
4399

    
4400
const Snapshots * VirtualMachine::get_disk_snapshots(int did, string& error) const
4401
{
4402
    const VectorAttribute * disk = get_disk(did);
4403

    
4404
    if ( disk == 0 )
4405
    {
4406
        error = "VM disk does not exist";
4407
        return 0;
4408
    }
4409

    
4410
    map<int, Snapshots *>::const_iterator it = snapshots.find(did);
4411

    
4412
    if (it == snapshots.end())
4413
    {
4414
        error = "Snapshot does not exist";
4415
        return 0;
4416
    }
4417

    
4418
    return it->second;
4419
}
4420

    
4421
/* -------------------------------------------------------------------------- */
4422
/* -------------------------------------------------------------------------- */
4423

    
4424
int VirtualMachine::revert_disk_snapshot(int did, int snap_id)
4425
{
4426
    map<int, Snapshots *>::iterator it;
4427

    
4428
    VectorAttribute * disk = get_disk(did);
4429

    
4430
    if ( disk == 0 )
4431
    {
4432
        return -1;
4433
    }
4434

    
4435
    it = snapshots.find(did);
4436

    
4437
    if (it == snapshots.end())
4438
    {
4439
        return -1;
4440
    }
4441

    
4442
    return it->second->active_snapshot(snap_id);
4443
}
4444

    
4445
/* -------------------------------------------------------------------------- */
4446
/* -------------------------------------------------------------------------- */
4447

    
4448
void VirtualMachine::delete_disk_snapshot(int did, int snap_id,
4449
        Template **ds_quotas, Template **vm_quotas)
4450
{
4451
    map<int, Snapshots *>::iterator it;
4452
    long long snap_size;
4453

    
4454
    VectorAttribute * delta_disk;
4455
    VectorAttribute * disk = get_disk(did);
4456

    
4457
    *ds_quotas = 0;
4458
    *vm_quotas = 0;
4459

    
4460
    if ( disk == 0 )
4461
    {
4462
        return;
4463
    }
4464

    
4465
    it = snapshots.find(did);
4466

    
4467
    if (it == snapshots.end())
4468
    {
4469
        return;
4470
    }
4471

    
4472
    long long ssize = it->second->get_snapshot_size(snap_id);
4473

    
4474
    it->second->delete_snapshot(snap_id);
4475

    
4476
    snap_size = it->second->get_total_size();
4477

    
4478
    disk->replace("DISK_SNAPSHOT_TOTAL_SIZE", snap_size);
4479

    
4480
    if (it->second->size() == 0)
4481
    {
4482
        Snapshots * tmp = it->second;
4483

    
4484
        snapshots.erase(it);
4485

    
4486
        delete tmp;
4487
    }
4488

    
4489
        if (is_persistent(disk) || disk_tm_target(disk) != "SYSTEM")
4490
        {
4491
        *ds_quotas = new Template();
4492

    
4493
        (*ds_quotas)->add("DATASTORE", disk->vector_value("DATASTORE_ID"));
4494
        (*ds_quotas)->add("SIZE", ssize);
4495
        (*ds_quotas)->add("IMAGES",0 );
4496
        }
4497

    
4498
    if (disk_tm_target(disk) == "SYSTEM")
4499
    {
4500
        *vm_quotas = new Template();
4501

    
4502
        delta_disk = new VectorAttribute("DISK");
4503
        delta_disk->replace("TYPE", "FS");
4504
        delta_disk->replace("SIZE", ssize);
4505

    
4506
        (*vm_quotas)->add("VMS", 0);
4507
        (*vm_quotas)->set(delta_disk);
4508
    }
4509
}
4510

    
4511
//  +--------+-------------------------------------+
4512
//  |LN/CLONE|     PERSISTENT    |   NO PERSISTENT |
4513
//  |        |---------+---------+-----------------+
4514
//  | TARGET | created |  quota  | created | quota |
4515
//  +--------+---------+---------+-----------------+
4516
//  | SYSTEM | system  | VM + DS | system  | VM    |
4517
//  | SELF   | image   | DS      | image   | DS    |
4518
//  | NONE   | image   | DS      | image   | DS    |
4519
//  +----------------------------------------------+
4520

    
4521
/* -------------------------------------------------------------------------- */
4522
/* -------------------------------------------------------------------------- */
4523

    
4524
void VirtualMachine::delete_non_persistent_disk_snapshots(Template **vm_quotas,
4525
        map<int, Template *>& ds_quotas)
4526
{
4527
    vector<VectorAttribute *> disks;
4528

    
4529
    map<int, Snapshots *>::iterator it;
4530

    
4531
    int  disk_id;
4532

    
4533
    long long system_disk = 0;
4534

    
4535
    int num_disks = obj_template->get("DISK", disks);
4536

    
4537
    for(int i=0; i<num_disks; i++)
4538
    {
4539
        if (disks[i]->vector_value("DISK_ID", disk_id) != 0)
4540
        {
4541
            continue;
4542
        }
4543

    
4544
        it = snapshots.find(disk_id);
4545

    
4546
        if (it == snapshots.end())
4547
        {
4548
            continue;
4549
        }
4550

    
4551
                if ( disk_tm_target(disks[i]) != "SYSTEM" )
4552
                {
4553
                        continue;
4554
                }
4555

    
4556
        if (is_persistent(disks[i]))
4557
        {
4558
            int image_id;
4559

    
4560
            if ( disks[i]->vector_value("IMAGE_ID", image_id) != 0 )
4561
            {
4562
                continue;
4563
            }
4564

    
4565
            Template * d_ds = new Template();
4566

    
4567
            d_ds->add("DATASTORE", disks[i]->vector_value("DATASTORE_ID"));
4568
            d_ds->add("SIZE", it->second->get_total_size());
4569
            d_ds->add("IMAGES", 0);
4570

    
4571
            ds_quotas.insert(pair<int, Template *>(image_id, d_ds));
4572
        }
4573

    
4574
                system_disk += it->second->get_total_size();
4575

    
4576
        it->second->clear();
4577

    
4578
        Snapshots * tmp = it->second;
4579

    
4580
        snapshots.erase(it);
4581

    
4582
        delete tmp;
4583

    
4584
        disks[i]->remove("DISK_SNAPSHOT_ACTIVE");
4585
        disks[i]->remove("DISK_SNAPSHOT_ID");
4586
        disks[i]->remove("DISK_SNAPSHOT_TOTAL_SIZE");
4587
    }
4588

    
4589
    if ( system_disk > 0 )
4590
    {
4591
        VectorAttribute * delta_disk;
4592

    
4593
        *vm_quotas = new Template();
4594

    
4595
        delta_disk = new VectorAttribute("DISK");
4596
        delta_disk->replace("TYPE", "FS");
4597
        delta_disk->replace("SIZE", system_disk);
4598

    
4599
        (*vm_quotas)->add("VMS", 0);
4600
        (*vm_quotas)->set(delta_disk);
4601
    }
4602
}
4603