Statistics
| Branch: | Tag: | Revision:

one / src / vm / VirtualMachine.cc @ 4b66f92b

History | View | Annotate | Download (99.2 KB)

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

    
34
#include "Nebula.h"
35

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

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

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

    
73
        user_obj_template = _vm_template;
74
    }
75
    else
76
    {
77
        user_obj_template = new VirtualMachineTemplate(false,'=',"USER_TEMPLATE");
78
    }
79

    
80
    obj_template = new VirtualMachineTemplate;
81

    
82
    set_umask(umask);
83
}
84

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

    
92
    delete _log;
93
    delete obj_template;
94
    delete user_obj_template;
95
}
96

    
97
/* ************************************************************************** */
98
/* Virtual Machine :: Database Access Functions                               */
99
/* ************************************************************************** */
100

    
101
const char * VirtualMachine::table = "vm_pool";
102

    
103
const char * VirtualMachine::db_names =
104
    "oid, name, body, uid, gid, last_poll, state, lcm_state, "
105
    "owner_u, group_u, other_u";
106

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

    
112

    
113
const char * VirtualMachine::monit_table = "vm_monitoring";
114

    
115
const char * VirtualMachine::monit_db_names = "vmid, last_poll, body";
116

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

    
121

    
122
const char * VirtualMachine::showback_table = "vm_showback";
123

    
124
const char * VirtualMachine::showback_db_names = "vmid, year, month, body";
125

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

    
131
const char * VirtualMachine::NO_NIC_DEFAULTS[] = {"NETWORK_ID", "NETWORK",
132
    "NETWORK_UID", "NETWORK_UNAME"};
133

    
134
const int VirtualMachine::NUM_NO_NIC_DEFAULTS = 4;
135

    
136
const char * VirtualMachine::NETWORK_CONTEXT[][2] = {
137
        {"IP", "IP"},
138
        {"MAC", "MAC"},
139
        {"MASK", "NETWORK_MASK"},
140
        {"NETWORK", "NETWORK_ADDRESS"},
141
        {"GATEWAY", "GATEWAY"},
142
        {"DNS", "DNS"},
143
        {"SEARCH_DOMAIN", "SEARCH_DOMAIN"}};
144
const int VirtualMachine::NUM_NETWORK_CONTEXT = 7;
145

    
146
const char*  VirtualMachine::NETWORK6_CONTEXT[][2] = {
147
        {"IP6", "IP6_GLOBAL"},
148
        {"GATEWAY6", "GATEWAY6"},
149
        {"CONTEXT_FORCE_IPV4", "CONTEXT_FORCE_IPV4"}};
150

    
151
const int VirtualMachine::NUM_NETWORK6_CONTEXT = 3;
152

    
153
/* -------------------------------------------------------------------------- */
154
/* -------------------------------------------------------------------------- */
155

    
156
int VirtualMachine::select(SqlDB * db)
157
{
158
    ostringstream   oss;
159
    ostringstream   ose;
160

    
161
    string system_dir;
162
    int    rc;
163
    int    last_seq;
164

    
165
    Nebula& nd = Nebula::instance();
166

    
167
    // Rebuild the VirtualMachine object
168
    rc = PoolObjectSQL::select(db);
169

    
170
    if( rc != 0 )
171
    {
172
        return rc;
173
    }
174

    
175
    //Get History Records. Current history is built in from_xml() (if any).
176
    if( hasHistory() )
177
    {
178
        last_seq = history->seq - 1;
179

    
180
        for (int i = last_seq; i >= 0; i--)
181
        {
182
            History * hp;
183

    
184
            hp = new History(oid, i);
185
            rc = hp->select(db);
186

    
187
            if ( rc != 0)
188
            {
189
                goto error_previous_history;
190
            }
191

    
192
            history_records[i] = hp;
193

    
194
            if ( i == last_seq )
195
            {
196
                previous_history = hp;
197
            }
198
        }
199
    }
200

    
201
    if ( state == DONE ) //Do not recreate dirs. They may be deleted
202
    {
203
        _log = 0;
204

    
205
        return 0;
206
    }
207

    
208
    //--------------------------------------------------------------------------
209
    //Create support directories for this VM
210
    //--------------------------------------------------------------------------
211
    oss.str("");
212
    oss << nd.get_vms_location() << oid;
213

    
214
    mkdir(oss.str().c_str(), 0700);
215
    chmod(oss.str().c_str(), 0700);
216

    
217
    //--------------------------------------------------------------------------
218
    //Create Log support for this VM
219
    //--------------------------------------------------------------------------
220
    try
221
    {
222
        Log::MessageType   clevel;
223
        NebulaLog::LogType log_system;
224

    
225
        log_system  = nd.get_log_system();
226
        clevel      = nd.get_debug_level();
227

    
228
        switch(log_system)
229
        {
230
            case NebulaLog::FILE_TS:
231
            case NebulaLog::FILE:
232
                _log = new FileLog(nd.get_vm_log_filename(oid), clevel);
233
                break;
234

    
235
            case NebulaLog::SYSLOG:
236
                _log = new SysLogResource(oid, obj_type, clevel);
237
                break;
238

    
239
            case NebulaLog::CERR:
240
                _log = new CerrLog(clevel);
241
                break;
242

    
243
            default:
244
                throw runtime_error("Unknown log system.");
245
                break;
246
        }
247
    }
248
    catch(exception &e)
249
    {
250
        ose << "Error creating log: " << e.what();
251
        NebulaLog::log("ONE",Log::ERROR, ose);
252

    
253
        _log = 0;
254
    }
255

    
256
    return 0;
257

    
258
error_previous_history:
259
    ose << "Cannot get previous history record (seq:" << history->seq
260
        << ") for VM id: " << oid;
261

    
262
    log("ONE", Log::ERROR, ose);
263
    return -1;
264
}
265

    
266
/* -------------------------------------------------------------------------- */
267
/* -------------------------------------------------------------------------- */
268

    
269
int VirtualMachine::insert(SqlDB * db, string& error_str)
270
{
271
    int    rc;
272
    string name;
273
    string prefix;
274

    
275
    string value;
276
    int    ivalue;
277
    float  fvalue;
278

    
279
    ostringstream oss;
280

    
281
    // ------------------------------------------------------------------------
282
    // Set a name if the VM has not got one and VM_ID
283
    // ------------------------------------------------------------------------
284

    
285
    oss << oid;
286
    value = oss.str();
287

    
288
    user_obj_template->erase("VMID");
289
    obj_template->add("VMID", value);
290

    
291
    user_obj_template->get("TEMPLATE_ID", value);
292
    user_obj_template->erase("TEMPLATE_ID");
293

    
294
    if (!value.empty())
295
    {
296
        obj_template->add("TEMPLATE_ID", value);
297
    }
298

    
299
    user_obj_template->get("NAME",name);
300
    user_obj_template->erase("NAME");
301

    
302
    user_obj_template->get("TEMPLATE_NAME", prefix);
303
    user_obj_template->erase("TEMPLATE_NAME");
304

    
305
    if (prefix.empty())
306
    {
307
        prefix = "one";
308
    }
309

    
310
    if (name.empty() == true)
311
    {
312
        oss.str("");
313
        oss << prefix << "-" << oid;
314
        name = oss.str();
315
    }
316

    
317
    if ( !PoolObjectSQL::name_is_valid(name, error_str) )
318
    {
319
        goto error_name;
320
    }
321

    
322
    this->name = name;
323

    
324
    // ------------------------------------------------------------------------
325
    // Check for CPU, VCPU and MEMORY attributes
326
    // ------------------------------------------------------------------------
327

    
328
    if ( user_obj_template->get("MEMORY", ivalue) == false || ivalue <= 0 )
329
    {
330
        goto error_memory;
331
    }
332

    
333
    user_obj_template->erase("MEMORY");
334
    obj_template->add("MEMORY", ivalue);
335

    
336
    if ( user_obj_template->get("CPU", fvalue) == false || fvalue <= 0 )
337
    {
338
        goto error_cpu;
339
    }
340

    
341
    user_obj_template->erase("CPU");
342
    obj_template->add("CPU", fvalue);
343

    
344
    // VCPU is optional, first check if the attribute exists, then check it is
345
    // an integer
346
    user_obj_template->get("VCPU", value);
347

    
348
    if ( value.empty() == false )
349
    {
350
        if ( user_obj_template->get("VCPU", ivalue) == false || ivalue <= 0 )
351
        {
352
            goto error_vcpu;
353
        }
354

    
355
        user_obj_template->erase("VCPU");
356
        obj_template->add("VCPU", ivalue);
357
    }
358

    
359
    // ------------------------------------------------------------------------
360
    // Check the cost attributes
361
    // ------------------------------------------------------------------------
362

    
363
    if ( user_obj_template->get("CPU_COST", fvalue) == true )
364
    {
365
        if ( fvalue < 0 )
366
        {
367
            goto error_cpu_cost;
368
        }
369

    
370
        user_obj_template->erase("CPU_COST");
371
        obj_template->add("CPU_COST", fvalue);
372
    }
373

    
374
    if ( user_obj_template->get("MEMORY_COST", fvalue) == true )
375
    {
376
        if ( fvalue < 0 )
377
        {
378
            goto error_memory_cost;
379
        }
380

    
381
        user_obj_template->erase("MEMORY_COST");
382
        obj_template->add("MEMORY_COST", fvalue);
383
    }
384

    
385
    // ------------------------------------------------------------------------
386
    // Check the OS attribute
387
    // ------------------------------------------------------------------------
388

    
389
    rc = parse_os(error_str);
390

    
391
    if ( rc != 0 )
392
    {
393
        goto error_os;
394
    }
395

    
396
    // ------------------------------------------------------------------------
397
    // Parse the defaults to merge
398
    // ------------------------------------------------------------------------
399

    
400
    rc = parse_defaults(error_str);
401

    
402
    if ( rc != 0 )
403
    {
404
        goto error_defaults;
405
    }
406

    
407
    // ------------------------------------------------------------------------
408
    // Get network leases
409
    // ------------------------------------------------------------------------
410

    
411
    rc = get_network_leases(error_str);
412

    
413
    if ( rc != 0 )
414
    {
415
        goto error_leases_rollback;
416
    }
417

    
418
    // ------------------------------------------------------------------------
419
    // Get disk images
420
    // ------------------------------------------------------------------------
421

    
422
    rc = get_disk_images(error_str);
423

    
424
    if ( rc != 0 )
425
    {
426
        // The get_disk_images method has an internal rollback for
427
        // the acquired images, release_disk_images() would release all disks
428
        goto error_leases_rollback;
429
    }
430

    
431
    // -------------------------------------------------------------------------
432
    // Parse the context & requirements
433
    // -------------------------------------------------------------------------
434

    
435
    rc = parse_context(error_str);
436

    
437
    if ( rc != 0 )
438
    {
439
        goto error_context;
440
    }
441

    
442
    rc = parse_requirements(error_str);
443

    
444
    if ( rc != 0 )
445
    {
446
        goto error_requirements;
447
    }
448

    
449
    rc = automatic_requirements(error_str);
450

    
451
    if ( rc != 0 )
452
    {
453
        goto error_requirements;
454
    }
455

    
456
    if ( parse_graphics(error_str) != 0 )
457
    {
458
        goto error_graphics;
459
    }
460

    
461
    // -------------------------------------------------------------------------
462
    // Get and set DEPLOY_ID for imported VMs
463
    // -------------------------------------------------------------------------
464

    
465
    user_obj_template->get("IMPORT_VM_ID", value);
466
    user_obj_template->erase("IMPORT_VM_ID");
467

    
468
    if (!value.empty())
469
    {
470
        const char * one_vms = "^one-[[:digit:]]+$";
471

    
472
        if (one_util::regex_match(one_vms, value.c_str()) == 0)
473
        {
474
            goto error_one_vms;
475
        }
476
        else
477
        {
478
            deploy_id = value;
479
            obj_template->add("IMPORTED", "YES");
480
        }
481
    }
482

    
483
    // ------------------------------------------------------------------------
484

    
485
    parse_well_known_attributes();
486

    
487
    // ------------------------------------------------------------------------
488
    // Insert the VM
489
    // ------------------------------------------------------------------------
490

    
491
    rc = insert_replace(db, false, error_str);
492

    
493
    if ( rc != 0 )
494
    {
495
        goto error_update;
496
    }
497

    
498
    return 0;
499

    
500
error_update:
501
    goto error_rollback;
502

    
503
error_context:
504
    goto error_rollback;
505

    
506
error_requirements:
507
    goto error_rollback;
508

    
509
error_graphics:
510
    goto error_rollback;
511

    
512
error_rollback:
513
    release_disk_images();
514

    
515
error_leases_rollback:
516
    release_network_leases();
517
    goto error_common;
518

    
519
error_cpu:
520
    error_str = "CPU attribute must be a positive float or integer value.";
521
    goto error_common;
522

    
523
error_vcpu:
524
    error_str = "VCPU attribute must be a positive integer value.";
525
    goto error_common;
526

    
527
error_memory:
528
    error_str = "MEMORY attribute must be a positive integer value.";
529
    goto error_common;
530

    
531
error_cpu_cost:
532
    error_str = "CPU_COST attribute must be a positive float or integer value.";
533
    goto error_common;
534

    
535
error_memory_cost:
536
    error_str = "MEMORY_COST attribute must be a positive float or integer value.";
537
    goto error_common;
538

    
539
error_one_vms:
540
    error_str = "Trying to import an OpenNebula VM: 'one-*'.";
541
    goto error_common;
542

    
543
error_os:
544
error_defaults:
545
error_name:
546
error_common:
547
    NebulaLog::log("ONE",Log::ERROR, error_str);
548

    
549
    return -1;
550
}
551

    
552
/* -------------------------------------------------------------------------- */
553
/* -------------------------------------------------------------------------- */
554

    
555
int VirtualMachine::set_os_file(VectorAttribute *  os,
556
                                const string&      base_name,
557
                                Image::ImageType   base_type,
558
                                string&            error_str)
559
{
560
    vector<int>  img_ids;
561
    Nebula& nd = Nebula::instance();
562

    
563
    ImagePool * ipool = nd.get_ipool();
564
    Image *     img   = 0;
565

    
566
    int img_id;
567

    
568
    Image::ImageType  type;
569
    Image::ImageState state;
570

    
571
    DatastorePool * ds_pool = nd.get_dspool();
572
    Datastore *     ds;
573
    int             ds_id;
574

    
575
    string attr;
576
    string base_name_ds     = base_name + "_DS";
577
    string base_name_id     = base_name + "_DS_ID";
578
    string base_name_source = base_name + "_DS_SOURCE";
579
    string base_name_ds_id  = base_name + "_DS_DSID";
580
    string base_name_tm     = base_name + "_DS_TM";
581
    string base_name_cluster= base_name + "_DS_CLUSTER_ID";
582

    
583
    string type_str;
584

    
585
    attr = os->vector_value(base_name_ds.c_str());
586

    
587
    if ( attr.empty() )
588
    {
589
        return 0;
590
    }
591

    
592
    if ( parse_file_attribute(attr, img_ids, error_str) != 0 )
593
    {
594
        return -1;
595
    }
596

    
597
    if ( img_ids.size() != 1 )
598
    {
599
        error_str = "Only one FILE variable can be used in: " + attr;
600
        return -1;
601
    }
602

    
603
    img_id = img_ids.back();
604

    
605
    img = ipool->get(img_id, true);
606

    
607
    if ( img == 0 )
608
    {
609
        error_str = "Image no longer exists in attribute: " + attr;
610
        return -1;
611
    }
612

    
613
    state = img->get_state();
614

    
615
    ds_id = img->get_ds_id();
616
    type  = img->get_type();
617

    
618
    os->remove(base_name);
619

    
620
    os->replace(base_name_id,     img->get_oid());
621
    os->replace(base_name_source, img->get_source());
622
    os->replace(base_name_ds_id,  img->get_ds_id());
623

    
624
    img->unlock();
625

    
626
    type_str = Image::type_to_str(type);
627

    
628
    if ( type != base_type )
629
    {
630
        ostringstream oss;
631

    
632
        oss << base_name << " needs an image of type "
633
            << Image::type_to_str(base_type) << " and not "
634
            << type_str;
635

    
636
        error_str = oss.str();
637
        return -1;
638
    }
639

    
640
    if ( state != Image::READY )
641
    {
642
        ostringstream oss;
643

    
644
        oss << type_str << " Image '" << img_id << " 'not in READY state.";
645

    
646
        error_str = oss.str();
647
        return -1;
648
    }
649

    
650
    ds = ds_pool->get(ds_id, true);
651

    
652
    if ( ds == 0 )
653
    {
654
        error_str = "Associated datastore for image does not exist";
655
        return -1;
656
    }
657

    
658
    os->replace(base_name_tm, ds->get_tm_mad());
659

    
660
    if ( ds->get_cluster_id() != ClusterPool::NONE_CLUSTER_ID )
661
    {
662
        os->replace(base_name_cluster, ds->get_cluster_id());
663
    }
664

    
665
    ds->unlock();
666

    
667
    return 0;
668
}
669

    
670
/* -------------------------------------------------------------------------- */
671

    
672
int VirtualMachine::parse_os(string& error_str)
673
{
674
    int num;
675
    int rc;
676

    
677
    vector<Attribute *> os_attr;
678
    VectorAttribute *   os;
679

    
680
    vector<Attribute *>::iterator it;
681

    
682
    num = user_obj_template->remove("OS", os_attr);
683

    
684
    for (it=os_attr.begin(); it != os_attr.end(); it++)
685
    {
686
        obj_template->set(*it);
687
    }
688

    
689
    if ( num == 0 )
690
    {
691
        return 0;
692
    }
693
    else if ( num > 1 )
694
    {
695
        error_str = "Only one OS attribute can be defined.";
696
        return -1;
697
    }
698

    
699
    os = dynamic_cast<VectorAttribute *>(os_attr[0]);
700

    
701
    if ( os == 0 )
702
    {
703
        error_str = "Internal error parsing OS attribute.";
704
        return -1;
705
    }
706

    
707
    rc = set_os_file(os, "KERNEL", Image::KERNEL, error_str);
708

    
709
    if ( rc != 0 )
710
    {
711
        return -1;
712
    }
713

    
714
    rc = set_os_file(os, "INITRD", Image::RAMDISK, error_str);
715

    
716
    if ( rc != 0 )
717
    {
718
        return -1;
719
    }
720

    
721
    return 0;
722
}
723

    
724
/* -------------------------------------------------------------------------- */
725
/* -------------------------------------------------------------------------- */
726

    
727
int VirtualMachine::parse_defaults(string& error_str)
728
{
729
    int num;
730

    
731
    vector<Attribute *> attr;
732
    VectorAttribute*    vatt = 0;
733

    
734
    num = user_obj_template->remove("NIC_DEFAULT", attr);
735

    
736
    if ( num == 0 )
737
    {
738
        return 0;
739
    }
740

    
741
    if ( num > 1 )
742
    {
743
        error_str = "Only one NIC_DEFAULT attribute can be defined.";
744
        goto error_cleanup;
745
    }
746

    
747
    vatt = dynamic_cast<VectorAttribute *>(attr[0]);
748

    
749
    if ( vatt == 0 )
750
    {
751
        error_str = "Wrong format for NIC_DEFAULT attribute.";
752
        goto error_cleanup;
753
    }
754

    
755
    for (int i=0; i < NUM_NO_NIC_DEFAULTS; i++)
756
    {
757
        if(vatt->vector_value(NO_NIC_DEFAULTS[i]) != "")
758
        {
759
            ostringstream oss;
760
            oss << "Attribute " << NO_NIC_DEFAULTS[i]
761
                << " is not allowed inside NIC_DEFAULT.";
762

    
763
            error_str = oss.str();
764

    
765
            return -1;
766
        }
767
    }
768

    
769
    obj_template->set(vatt);
770

    
771
    return 0;
772

    
773
error_cleanup:
774

    
775
    for (int i = 0; i < num ; i++)
776
    {
777
        delete attr[i];
778
    }
779

    
780
    return -1;
781
}
782

    
783

    
784
/* -------------------------------------------------------------------------- */
785
/* -------------------------------------------------------------------------- */
786

    
787
static void parse_context_network(const char* vars[][2], int num_vars,
788
        VectorAttribute * context, VectorAttribute * nic)
789
{
790
    string nic_id = nic->vector_value("NIC_ID");
791

    
792
    for (int i=0; i < num_vars; i++)
793
    {
794
        ostringstream cvar;
795
        string cval;
796

    
797
        cvar << "ETH" << nic_id << "_" << vars[i][0];
798

    
799
        cval = context->vector_value(cvar.str().c_str());
800

    
801
        if (!cval.empty())
802
        {
803
            continue;
804
        }
805

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

    
808
        if (cval.empty()) //Will check the AR and VNET
809
        {
810
            ostringstream cval_ss;
811

    
812
            cval_ss << "$NETWORK["<< vars[i][1] <<", NIC_ID=\""<< nic_id <<"\"]";
813
            cval = cval_ss.str();
814
        }
815

    
816
        context->replace(cvar.str(), cval);
817
    }
818
}
819

    
820
/* -------------------------------------------------------------------------- */
821

    
822
int VirtualMachine::parse_context(string& error_str)
823
{
824
    int rc, num;
825

    
826
    vector<Attribute *> array_context;
827
    VectorAttribute *   context;
828
    VectorAttribute *   context_parsed;
829

    
830
    string * str;
831
    string   parsed;
832
    string   files_ds;
833
    string   files_ds_parsed;
834

    
835
    ostringstream oss_parsed;
836

    
837
    vector<int>  img_ids;
838

    
839
    num = obj_template->remove("CONTEXT", array_context);
840

    
841
    if ( num == 0 )
842
    {
843
        return 0;
844
    }
845
    else if ( num > 1 )
846
    {
847
        error_str = "Only one CONTEXT attribute can be defined.";
848
        goto error_cleanup;
849
    }
850

    
851
    context = dynamic_cast<VectorAttribute *>(array_context[0]);
852

    
853
    if ( context == 0 )
854
    {
855
        error_str = "Wrong format for CONTEXT attribute.";
856
        goto error_cleanup;
857
    }
858

    
859
    //Backup datastore files to parse them later
860

    
861
    files_ds = context->vector_value("FILES_DS");
862

    
863
    context->remove("FILES_DS");
864

    
865
    // ----------- Inject Network context in marshalled string  ----------------
866

    
867
    bool net_context;
868
    context->vector_value("NETWORK", net_context);
869

    
870
    if (net_context)
871
    {
872
        vector<Attribute  * > v_attributes;
873
        VectorAttribute *     vatt;
874

    
875
        int num_vatts = obj_template->get("NIC", v_attributes);
876

    
877
        for(int i=0; i<num_vatts; i++)
878
        {
879
            vatt = dynamic_cast<VectorAttribute * >(v_attributes[i]);
880

    
881
            if ( vatt == 0 )
882
            {
883
                continue;
884
            }
885

    
886
            parse_context_network(NETWORK_CONTEXT, NUM_NETWORK_CONTEXT, 
887
                    context, vatt);
888

    
889
            if (!vatt->vector_value("IP6_GLOBAL").empty())
890
            {
891
                parse_context_network(NETWORK6_CONTEXT, NUM_NETWORK6_CONTEXT, 
892
                        context, vatt);
893
            }
894
        }
895
    }
896

    
897
    // -------------------------------------------------------------------------
898
    // Parse CONTEXT variables & free vector attributes
899
    // -------------------------------------------------------------------------
900

    
901
    str = context->marshall(" @^_^@ ");
902

    
903
    if (str == 0)
904
    {
905
        error_str = "Cannot marshall CONTEXT";
906
        goto error_cleanup;
907
    }
908

    
909
    rc = parse_template_attribute(*str, parsed, error_str);
910

    
911
    delete str;
912

    
913
    if (rc != 0)
914
    {
915
        goto error_cleanup;
916
    }
917

    
918
    for (int i = 0; i < num ; i++)
919
    {
920
        delete array_context[i];
921
    }
922

    
923
    // -------------------------------------------------------------------------
924
    // Parse FILE_DS variables
925
    // -------------------------------------------------------------------------
926

    
927
    if (!files_ds.empty())
928
    {
929
        if ( parse_file_attribute(files_ds, img_ids, error_str) != 0 )
930
        {
931
            return -1;
932
        }
933

    
934
        if ( img_ids.size() > 0 )
935
        {
936
            vector<int>::iterator it;
937

    
938
            Nebula& nd = Nebula::instance();
939

    
940
            ImagePool * ipool = nd.get_ipool();
941
            Image  *    img   = 0;
942

    
943
            Image::ImageType type;
944
            Image::ImageState state;
945

    
946
            for ( it=img_ids.begin() ; it < img_ids.end(); it++ )
947
            {
948
                img = ipool->get(*it, true);
949

    
950
                if ( img != 0 )
951
                {
952
                    oss_parsed << img->get_source() << ":'"
953
                               << img->get_name() << "' ";
954

    
955
                    type  = img->get_type();
956
                    state = img->get_state();
957

    
958
                    img->unlock();
959

    
960
                    if (type != Image::CONTEXT)
961
                    {
962
                        error_str = "Only images of type CONTEXT can be used in"
963
                                    " FILE_DS attribute.";
964
                        return -1;
965
                    }
966

    
967
                    if ( state != Image::READY )
968
                    {
969
                        ostringstream oss;
970

    
971
                        oss << Image::type_to_str(type)
972
                            << " Image '" << *it << "' not in READY state.";
973

    
974
                        error_str = oss.str();
975

    
976
                        return -1;
977
                    }
978

    
979
                }
980
            }
981
        }
982
    }
983

    
984
    files_ds_parsed = oss_parsed.str();
985

    
986
    context_parsed = new VectorAttribute("CONTEXT");
987
    context_parsed->unmarshall(parsed," @^_^@ ");
988

    
989
    if ( !files_ds_parsed.empty() )
990
    {
991
        context_parsed->replace("FILES_DS", files_ds_parsed);
992
    }
993

    
994
    obj_template->set(context_parsed);
995

    
996
    // -------------------------------------------------------------------------
997
    // OneGate URL
998
    // -------------------------------------------------------------------------
999

    
1000
    bool token;
1001
    context_parsed->vector_value("TOKEN", token);
1002

    
1003
    if (token)
1004
    {
1005
        string endpoint;
1006

    
1007
        Nebula::instance().get_configuration_attribute(
1008
                    "ONEGATE_ENDPOINT", endpoint);
1009

    
1010
        if ( endpoint.empty() )
1011
        {
1012
            error_str = "CONTEXT/TOKEN set, but OneGate endpoint was not "
1013
                "defined in oned.conf or CONTEXT.";
1014
            return -1;
1015
        }
1016

    
1017
        context_parsed->replace("ONEGATE_ENDPOINT", endpoint);
1018
        context_parsed->replace("VMID", oid);
1019
    }
1020

    
1021
    return rc;
1022

    
1023
error_cleanup:
1024
    for (int i = 0; i < num ; i++)
1025
    {
1026
        delete array_context[i];
1027
    }
1028

    
1029
    return -1;
1030
}
1031

    
1032
/* -------------------------------------------------------------------------- */
1033
/* -------------------------------------------------------------------------- */
1034

    
1035
int VirtualMachine::parse_graphics(string& error_str)
1036
{
1037
    vector<Attribute *> array_graphics;
1038
    VectorAttribute *   graphics;
1039

    
1040
    vector<Attribute *>::iterator it;
1041

    
1042
    int num = user_obj_template->remove("GRAPHICS", array_graphics);
1043

    
1044
    for (it=array_graphics.begin(); it != array_graphics.end(); it++)
1045
    {
1046
        obj_template->set(*it);
1047
    }
1048

    
1049
    if ( num == 0 )
1050
    {
1051
        return 0;
1052
    }
1053

    
1054
    graphics = dynamic_cast<VectorAttribute * >(array_graphics[0]);
1055

    
1056
    if ( graphics == 0 )
1057
    {
1058
        return 0;
1059
    }
1060

    
1061
    string port = graphics->vector_value("PORT");
1062
    int    port_i;
1063

    
1064
    int rc = graphics->vector_value("PORT", port_i);
1065

    
1066
    if ( port.empty() )
1067
    {
1068
        Nebula&       nd = Nebula::instance();
1069

    
1070
        ostringstream oss;
1071
        istringstream iss;
1072

    
1073
        int           base_port;
1074
        string        base_port_s;
1075

    
1076
        int limit = 65535;
1077

    
1078
        nd.get_configuration_attribute("VNC_BASE_PORT",base_port_s);
1079
        iss.str(base_port_s);
1080
        iss >> base_port;
1081

    
1082
        oss << ( base_port + ( oid % (limit - base_port) ));
1083
        graphics->replace("PORT", oss.str());
1084
    }
1085
    else if ( rc == -1 || port_i < 0 )
1086
    {
1087
        error_str = "Wrong PORT number in GRAPHICS attribute";
1088
        return -1;
1089
    }
1090

    
1091
    string random_passwd = graphics->vector_value("RANDOM_PASSWD");
1092

    
1093
    if ( !random_passwd.empty() )
1094
    {
1095
        graphics->replace("PASSWD", one_util::random_password());
1096
    }
1097

    
1098
    return 0;
1099
}
1100

    
1101
/* -------------------------------------------------------------------------- */
1102
/* -------------------------------------------------------------------------- */
1103

    
1104
int VirtualMachine::parse_requirements(string& error_str)
1105
{
1106
    int rc, num;
1107

    
1108
    vector<Attribute *> array_reqs;
1109
    SingleAttribute *   reqs;
1110

    
1111
    string              parsed;
1112

    
1113
    num = user_obj_template->remove("SCHED_REQUIREMENTS", array_reqs);
1114

    
1115
    if ( num == 0 ) // Compatibility with old REQUIREMENTS attribute
1116
    {
1117
        num = user_obj_template->remove("REQUIREMENTS", array_reqs);
1118
    }
1119
    else
1120
    {
1121
        user_obj_template->erase("REQUIREMENTS");
1122
    }
1123

    
1124
    if ( num == 0 )
1125
    {
1126
        return 0;
1127
    }
1128
    else if ( num > 1 )
1129
    {
1130
        error_str = "Only one SCHED_REQUIREMENTS attribute can be defined.";
1131
        goto error_cleanup;
1132
    }
1133

    
1134
    reqs = dynamic_cast<SingleAttribute *>(array_reqs[0]);
1135

    
1136
    if ( reqs == 0 )
1137
    {
1138
        error_str = "Wrong format for SCHED_REQUIREMENTS attribute.";
1139
        goto error_cleanup;
1140
    }
1141

    
1142
    rc = parse_template_attribute(reqs->value(), parsed, error_str);
1143

    
1144
    if ( rc == 0 )
1145
    {
1146
        SingleAttribute * reqs_parsed;
1147

    
1148
        reqs_parsed = new SingleAttribute("SCHED_REQUIREMENTS",parsed);
1149
        user_obj_template->set(reqs_parsed);
1150
    }
1151

    
1152
    /* --- Delete old requirements attribute --- */
1153

    
1154
    delete array_reqs[0];
1155

    
1156
    return rc;
1157

    
1158
error_cleanup:
1159
    for (int i = 0; i < num ; i++)
1160
    {
1161
        delete array_reqs[i];
1162
    }
1163

    
1164
    return -1;
1165
}
1166

    
1167
/* ------------------------------------------------------------------------ */
1168
/* ------------------------------------------------------------------------ */
1169

    
1170
void VirtualMachine::parse_well_known_attributes()
1171
{
1172
    /*
1173
     * List of meaningful attributes, used in other places and expected in
1174
     * obj_template:
1175
     *
1176
     * DISK
1177
     * NIC
1178
     * VCPU
1179
     * MEMORY
1180
     * CPU
1181
     * CONTEXT
1182
     * OS
1183
     * GRAPHICS
1184
     *
1185
     * INPUT
1186
     * FEATURES
1187
     * RAW
1188
     */
1189

    
1190
    vector<Attribute *>             v_attr;
1191
    vector<Attribute *>::iterator   it;
1192

    
1193
    string names[] = {"INPUT", "FEATURES", "RAW"};
1194

    
1195
    for (int i=0; i<3; i++)
1196
    {
1197
        v_attr.clear();
1198

    
1199
        user_obj_template->remove(names[i], v_attr);
1200

    
1201
        for (it=v_attr.begin(); it != v_attr.end(); it++)
1202
        {
1203
            obj_template->set(*it);
1204
        }
1205
    }
1206
}
1207

    
1208
/* ------------------------------------------------------------------------ */
1209
/* ------------------------------------------------------------------------ */
1210

    
1211
static int check_and_set_cluster_id(const char *      id_name,
1212
                                    VectorAttribute * vatt,
1213
                                    string&           cluster_id)
1214
{
1215
    string vatt_cluster_id;
1216

    
1217
    vatt_cluster_id = vatt->vector_value(id_name);
1218

    
1219
    if ( !vatt_cluster_id.empty() )
1220
    {
1221
        if ( cluster_id.empty() )
1222
        {
1223
            cluster_id = vatt_cluster_id;
1224
        }
1225
        else if ( cluster_id != vatt_cluster_id )
1226
        {
1227
            return -1;
1228
        }
1229
    }
1230

    
1231
    return 0;
1232
}
1233

    
1234
/* ------------------------------------------------------------------------ */
1235

    
1236
int VirtualMachine::automatic_requirements(string& error_str)
1237
{
1238
    int                   num_vatts;
1239
    vector<Attribute  * > v_attributes;
1240
    VectorAttribute *     vatt;
1241

    
1242
    ostringstream   oss;
1243
    string          requirements;
1244
    string          cluster_id = "";
1245

    
1246
    vector<string> public_cloud_hypervisors;
1247

    
1248
    int num_public = get_public_cloud_hypervisors(public_cloud_hypervisors);
1249

    
1250
    int incomp_id;
1251
    int rc;
1252

    
1253
    // Get cluster id from all DISK vector attributes (IMAGE Datastore)
1254

    
1255
    num_vatts = obj_template->get("DISK",v_attributes);
1256

    
1257
    for(int i=0; i<num_vatts; i++)
1258
    {
1259
        vatt = dynamic_cast<VectorAttribute * >(v_attributes[i]);
1260

    
1261
        if ( vatt == 0 )
1262
        {
1263
            continue;
1264
        }
1265

    
1266
        rc = check_and_set_cluster_id("CLUSTER_ID", vatt, cluster_id);
1267

    
1268
        if ( rc != 0 )
1269
        {
1270
            incomp_id = i;
1271
            goto error_disk;
1272
        }
1273
    }
1274

    
1275
    // Get cluster id from the KERNEL and INITRD (FILE Datastores)
1276

    
1277
    v_attributes.clear();
1278
    num_vatts = obj_template->get("OS",v_attributes);
1279

    
1280
    if ( num_vatts > 0 )
1281
    {
1282
        vatt = dynamic_cast<VectorAttribute * >(v_attributes[0]);
1283

    
1284
        if ( vatt != 0 )
1285
        {
1286
            rc = check_and_set_cluster_id("KERNEL_CLUSTER_ID", vatt, cluster_id);
1287

    
1288
            if ( rc != 0 )
1289
            {
1290
                goto error_kernel;
1291
            }
1292

    
1293
            rc = check_and_set_cluster_id("INITRD_CLUSTER_ID", vatt, cluster_id);
1294

    
1295
            if ( rc != 0 )
1296
            {
1297
                goto error_initrd;
1298
            }
1299
        }
1300
    }
1301

    
1302
    // Get cluster id from all NIC vector attributes
1303

    
1304
    v_attributes.clear();
1305
    num_vatts = obj_template->get("NIC",v_attributes);
1306

    
1307
    for(int i=0; i<num_vatts; i++)
1308
    {
1309
        vatt = dynamic_cast<VectorAttribute * >(v_attributes[i]);
1310

    
1311
        if ( vatt == 0 )
1312
        {
1313
            continue;
1314
        }
1315

    
1316
        rc = check_and_set_cluster_id("CLUSTER_ID", vatt, cluster_id);
1317

    
1318
        if ( rc != 0 )
1319
        {
1320
            incomp_id = i;
1321
            goto error_nic;
1322
        }
1323
    }
1324

    
1325
    if ( !cluster_id.empty() )
1326
    {
1327
        oss << "CLUSTER_ID = " << cluster_id << " & !(PUBLIC_CLOUD = YES)";
1328
    }
1329
    else
1330
    {
1331
        oss << "!(PUBLIC_CLOUD = YES)";
1332
    }
1333

    
1334
    if (num_public != 0)
1335
    {
1336
        oss << " | (PUBLIC_CLOUD = YES & (";
1337

    
1338
        oss << "HYPERVISOR = " << public_cloud_hypervisors[0];
1339

    
1340
        for (int i = 1; i < num_public; i++)
1341
        {
1342
            oss << " | HYPERVISOR = " << public_cloud_hypervisors[i];
1343
        }
1344

    
1345
        oss << "))";
1346
    }
1347

    
1348
    obj_template->add("AUTOMATIC_REQUIREMENTS", oss.str());
1349

    
1350
    return 0;
1351

    
1352
error_disk:
1353
    oss << "Incompatible clusters in DISK. Datastore for DISK "<< incomp_id
1354
        << " is not the same as the one used by other VM elements (cluster "
1355
        << cluster_id << ")";
1356
    goto error_common;
1357

    
1358
error_kernel:
1359
    oss << "Incompatible cluster in KERNEL datastore, it should be in cluster "
1360
        << cluster_id << ".";
1361
    goto error_common;
1362

    
1363
error_initrd:
1364
    oss << "Incompatible cluster in INITRD datastore, it should be in cluster "
1365
        << cluster_id << ".";
1366
    goto error_common;
1367

    
1368
error_nic:
1369
    oss << "Incompatible clusters in NIC. Network for NIC "<< incomp_id
1370
        << " is not the same as the one used by other VM elements (cluster "
1371
        << cluster_id << ")";
1372
    goto error_common;
1373

    
1374
error_common:
1375
    error_str = oss.str();
1376

    
1377
    return -1;
1378
}
1379

    
1380
/* ------------------------------------------------------------------------ */
1381
/* ------------------------------------------------------------------------ */
1382

    
1383
int VirtualMachine::insert_replace(SqlDB *db, bool replace, string& error_str)
1384
{
1385
    ostringstream   oss;
1386
    int             rc;
1387

    
1388
    string xml_body;
1389
    char * sql_name;
1390
    char * sql_xml;
1391

    
1392
    sql_name =  db->escape_str(name.c_str());
1393

    
1394
    if ( sql_name == 0 )
1395
    {
1396
        goto error_generic;
1397
    }
1398

    
1399
    sql_xml = db->escape_str(to_xml(xml_body).c_str());
1400

    
1401
    if ( sql_xml == 0 )
1402
    {
1403
        goto error_body;
1404
    }
1405

    
1406
    if ( validate_xml(sql_xml) != 0 )
1407
    {
1408
        goto error_xml;
1409
    }
1410

    
1411
    if(replace)
1412
    {
1413
        oss << "REPLACE";
1414
    }
1415
    else
1416
    {
1417
        oss << "INSERT";
1418
    }
1419

    
1420
    oss << " INTO " << table << " ("<< db_names <<") VALUES ("
1421
        <<          oid             << ","
1422
        << "'" <<   sql_name        << "',"
1423
        << "'" <<   sql_xml         << "',"
1424
        <<          uid             << ","
1425
        <<          gid             << ","
1426
        <<          last_poll       << ","
1427
        <<          state           << ","
1428
        <<          lcm_state       << ","
1429
        <<          owner_u         << ","
1430
        <<          group_u         << ","
1431
        <<          other_u         << ")";
1432

    
1433
    db->free_str(sql_name);
1434
    db->free_str(sql_xml);
1435

    
1436
    rc = db->exec(oss);
1437

    
1438
    return rc;
1439

    
1440
error_xml:
1441
    db->free_str(sql_name);
1442
    db->free_str(sql_xml);
1443

    
1444
    error_str = "Error transforming the VM to XML.";
1445

    
1446
    goto error_common;
1447

    
1448
error_body:
1449
    db->free_str(sql_name);
1450
    goto error_generic;
1451

    
1452
error_generic:
1453
    error_str = "Error inserting VM in DB.";
1454
error_common:
1455
    return -1;
1456
}
1457

    
1458
/* -------------------------------------------------------------------------- */
1459
/* -------------------------------------------------------------------------- */
1460

    
1461
int VirtualMachine::update_monitoring(SqlDB * db)
1462
{
1463
    ostringstream   oss;
1464
    int             rc;
1465

    
1466
    string xml_body;
1467
    string error_str;
1468
    char * sql_xml;
1469

    
1470
    sql_xml = db->escape_str(to_xml(xml_body).c_str());
1471

    
1472
    if ( sql_xml == 0 )
1473
    {
1474
        goto error_body;
1475
    }
1476

    
1477
    if ( validate_xml(sql_xml) != 0 )
1478
    {
1479
        goto error_xml;
1480
    }
1481

    
1482
    oss << "REPLACE INTO " << monit_table << " ("<< monit_db_names <<") VALUES ("
1483
        <<          oid             << ","
1484
        <<          last_poll       << ","
1485
        << "'" <<   sql_xml         << "')";
1486

    
1487
    db->free_str(sql_xml);
1488

    
1489
    rc = db->exec(oss);
1490

    
1491
    return rc;
1492

    
1493
error_xml:
1494
    db->free_str(sql_xml);
1495

    
1496
    error_str = "could not transform the VM to XML.";
1497

    
1498
    goto error_common;
1499

    
1500
error_body:
1501
    error_str = "could not insert the VM in the DB.";
1502

    
1503
error_common:
1504
    oss.str("");
1505
    oss << "Error updating VM monitoring information, " << error_str;
1506

    
1507
    NebulaLog::log("ONE",Log::ERROR, oss);
1508

    
1509
    return -1;
1510
}
1511

    
1512
/* -------------------------------------------------------------------------- */
1513
/* -------------------------------------------------------------------------- */
1514

    
1515
void VirtualMachine::add_history(
1516
    int   hid,
1517
    int   cid,
1518
    const string& hostname,
1519
    const string& vmm_mad,
1520
    const string& vnm_mad,
1521
    const string& tm_mad,
1522
    const string& ds_location,
1523
    int           ds_id)
1524
{
1525
    ostringstream os;
1526
    int           seq;
1527
    string        vm_xml;
1528

    
1529
    if (history == 0)
1530
    {
1531
        seq = 0;
1532
    }
1533
    else
1534
    {
1535
        seq = history->seq + 1;
1536

    
1537
        previous_history = history;
1538
    }
1539

    
1540
    to_xml_extended(vm_xml, 0);
1541

    
1542
    history = new History(oid,
1543
                          seq,
1544
                          hid,
1545
                          hostname,
1546
                          cid,
1547
                          vmm_mad,
1548
                          vnm_mad,
1549
                          tm_mad,
1550
                          ds_location,
1551
                          ds_id,
1552
                          vm_xml);
1553

    
1554
    history_records.push_back(history);
1555
};
1556

    
1557
/* -------------------------------------------------------------------------- */
1558
/* -------------------------------------------------------------------------- */
1559

    
1560
void VirtualMachine::cp_history()
1561
{
1562
    History * htmp;
1563
    string    vm_xml;
1564

    
1565
    if (history == 0)
1566
    {
1567
        return;
1568
    }
1569

    
1570
    to_xml_extended(vm_xml, 0);
1571

    
1572
    htmp = new History(oid,
1573
                       history->seq + 1,
1574
                       history->hid,
1575
                       history->hostname,
1576
                       history->cid,
1577
                       history->vmm_mad_name,
1578
                       history->vnm_mad_name,
1579
                       history->tm_mad_name,
1580
                       history->ds_location,
1581
                       history->ds_id,
1582
                       vm_xml);
1583

    
1584
    previous_history = history;
1585
    history          = htmp;
1586

    
1587
    history_records.push_back(history);
1588
}
1589

    
1590
/* -------------------------------------------------------------------------- */
1591
/* -------------------------------------------------------------------------- */
1592

    
1593
void VirtualMachine::cp_previous_history()
1594
{
1595
    History * htmp;
1596
    string    vm_xml;
1597

    
1598
    if ( previous_history == 0 || history == 0)
1599
    {
1600
        return;
1601
    }
1602

    
1603
    to_xml_extended(vm_xml, 0);
1604

    
1605
    htmp = new History(oid,
1606
                       history->seq + 1,
1607
                       previous_history->hid,
1608
                       previous_history->hostname,
1609
                       previous_history->cid,
1610
                       previous_history->vmm_mad_name,
1611
                       previous_history->vnm_mad_name,
1612
                       previous_history->tm_mad_name,
1613
                       previous_history->ds_location,
1614
                       previous_history->ds_id,
1615
                       vm_xml);
1616

    
1617
    previous_history = history;
1618
    history          = htmp;
1619

    
1620
    history_records.push_back(history);
1621
}
1622

    
1623
/* -------------------------------------------------------------------------- */
1624
/* -------------------------------------------------------------------------- */
1625

    
1626
void VirtualMachine::get_requirements (int& cpu, int& memory, int& disk)
1627
{
1628
    istringstream   iss;
1629
    float           fcpu;
1630

    
1631
    if ((get_template_attribute("MEMORY",memory) == false) ||
1632
        (get_template_attribute("CPU",fcpu) == false))
1633
    {
1634
        cpu    = 0;
1635
        memory = 0;
1636
        disk   = 0;
1637

    
1638
        return;
1639
    }
1640

    
1641
    cpu    = (int) (fcpu * 100);//now in 100%
1642
    memory = memory * 1024;     //now in Kilobytes
1643
    disk   = 0;
1644

    
1645
    return;
1646
}
1647

    
1648
/* -------------------------------------------------------------------------- */
1649
/* -------------------------------------------------------------------------- */
1650

    
1651
int VirtualMachine::check_resize (
1652
        float cpu, int memory, int vcpu, string& error_str)
1653
{
1654
    if (cpu < 0)
1655
    {
1656
        error_str = "CPU must be a positive float or integer value.";
1657
        return -1;
1658
    }
1659

    
1660
    if (memory < 0)
1661
    {
1662
        error_str = "MEMORY must be a positive integer value.";
1663
        return -1;
1664
    }
1665

    
1666
    if (vcpu < 0)
1667
    {
1668
        error_str = "VCPU must be a positive integer value.";
1669
        return -1;
1670
    }
1671

    
1672
    return 0;
1673
}
1674

    
1675
/* -------------------------------------------------------------------------- */
1676
/* -------------------------------------------------------------------------- */
1677

    
1678
int VirtualMachine::resize(float cpu, int memory, int vcpu, string& error_str)
1679
{
1680
    ostringstream oss;
1681

    
1682
    int rc = check_resize(cpu, memory, vcpu, error_str);
1683

    
1684
    if (rc != 0)
1685
    {
1686
        return rc;
1687
    }
1688

    
1689
    if (cpu > 0)
1690
    {
1691
        oss << cpu;
1692
        replace_template_attribute("CPU", oss.str());
1693
        oss.str("");
1694
    }
1695

    
1696
    if (memory > 0)
1697
    {
1698
        oss << memory;
1699
        replace_template_attribute("MEMORY", oss.str());
1700
        oss.str("");
1701
    }
1702

    
1703
    if (vcpu > 0)
1704
    {
1705
        oss << vcpu;
1706
        replace_template_attribute("VCPU", oss.str());
1707
    }
1708

    
1709
    return 0;
1710
}
1711

    
1712
/* -------------------------------------------------------------------------- */
1713
/* -------------------------------------------------------------------------- */
1714

    
1715
static void assign_disk_targets(queue<pair <string, VectorAttribute *> >& _queue,
1716
                                set<string>& used_targets)
1717
{
1718
    int    index = 0;
1719
    string target;
1720

    
1721
    pair <string, VectorAttribute *> disk_pair;
1722

    
1723
    while (_queue.size() > 0 )
1724
    {
1725
        disk_pair = _queue.front();
1726
        index     = 0;
1727

    
1728
        do
1729
        {
1730
            target = disk_pair.first + static_cast<char>(('a'+ index));
1731
            index++;
1732
        }
1733
        while ( used_targets.count(target) > 0 && index < 26 );
1734

    
1735
        disk_pair.second->replace("TARGET", target);
1736
        used_targets.insert(target);
1737

    
1738
        _queue.pop();
1739
    }
1740
}
1741

    
1742
/* -------------------------------------------------------------------------- */
1743

    
1744
int VirtualMachine::get_disk_images(string& error_str)
1745
{
1746
    int                  num_disks, num_context, rc;
1747
    vector<Attribute  *> disks;
1748
    vector<Attribute  *> context_disks;
1749
    ImagePool *          ipool;
1750
    VectorAttribute *    disk;
1751
    vector<int>          acquired_images;
1752

    
1753
    int     image_id;
1754
    string  dev_prefix;
1755
    string  target;
1756

    
1757
    queue<pair <string, VectorAttribute *> > os_disk;
1758
    queue<pair <string, VectorAttribute *> > cdrom_disks;
1759
    queue<pair <string, VectorAttribute *> > datablock_disks;
1760

    
1761
    set<string> used_targets;
1762

    
1763
    ostringstream    oss;
1764
    Image::ImageType img_type;
1765

    
1766
    Nebula& nd = Nebula::instance();
1767
    ipool      = nd.get_ipool();
1768

    
1769
    vector<Attribute*>::iterator it;
1770

    
1771
    num_context = user_obj_template->remove("CONTEXT", context_disks);
1772
    num_disks   = user_obj_template->remove("DISK", disks);
1773

    
1774
    for (it=context_disks.begin(); it != context_disks.end(); it++)
1775
    {
1776
        obj_template->set(*it);
1777
    }
1778

    
1779
    for (it=disks.begin(); it != disks.end(); it++)
1780
    {
1781
        obj_template->set(*it);
1782
    }
1783

    
1784
    if ( num_disks > 20 )
1785
    {
1786
        goto error_max_disks;
1787
    }
1788

    
1789
    // -------------------------------------------------------------------------
1790
    // Set DISK attributes & Targets
1791
    // -------------------------------------------------------------------------
1792
    for(int i=0; i<num_disks; i++)
1793
    {
1794
        disk = dynamic_cast<VectorAttribute * >(disks[i]);
1795

    
1796
        if ( disk == 0 )
1797
        {
1798
            continue;
1799
        }
1800

    
1801
        rc = ipool->disk_attribute(oid,
1802
                                   disk,
1803
                                   i,
1804
                                   img_type,
1805
                                   dev_prefix,
1806
                                   uid,
1807
                                   image_id,
1808
                                   error_str);
1809
        if (rc == 0 )
1810
        {
1811
            acquired_images.push_back(image_id);
1812

    
1813
            target = disk->vector_value("TARGET");
1814

    
1815
            if ( !target.empty() )
1816
            {
1817
                if (  used_targets.insert(target).second == false )
1818
                {
1819
                    goto error_duplicated_target;
1820
                }
1821
            }
1822
            else
1823
            {
1824
                switch(img_type)
1825
                {
1826
                    case Image::OS:
1827
                        // The first OS disk gets the first device (a),
1828
                        // other OS's will be managed as DATABLOCK's
1829
                        if ( os_disk.empty() )
1830
                        {
1831
                            os_disk.push( make_pair(dev_prefix, disk) );
1832
                        }
1833
                        else
1834
                        {
1835
                            datablock_disks.push( make_pair(dev_prefix, disk) );
1836
                        }
1837
                        break;
1838

    
1839
                    case Image::CDROM:
1840
                        cdrom_disks.push( make_pair(dev_prefix, disk) );
1841
                        break;
1842

    
1843
                    case Image::DATABLOCK:
1844
                        datablock_disks.push( make_pair(dev_prefix, disk) );
1845
                        break;
1846

    
1847
                    default:
1848
                        break;
1849
                }
1850
            }
1851
        }
1852
        else
1853
        {
1854
            oss << "DISK " << i << ": " << error_str;
1855
            error_str = oss.str();
1856

    
1857
            goto error_common;
1858
        }
1859
    }
1860

    
1861
    // -------------------------------------------------------------------------
1862
    // The context is the last of the cdroms
1863
    // -------------------------------------------------------------------------
1864
    if ( num_context > 0 )
1865
    {
1866
        disk = dynamic_cast<VectorAttribute * >(context_disks[0]);
1867

    
1868
        if ( disk != 0 )
1869
        {
1870
            target = disk->vector_value("TARGET");
1871

    
1872
            if ( !target.empty() )
1873
            {
1874
                if (  used_targets.insert(target).second == false )
1875
                {
1876
                    goto error_duplicated_target;
1877
                }
1878
            }
1879
            else
1880
            {
1881
                dev_prefix = disk->vector_value("DEV_PREFIX");
1882

    
1883
                if ( dev_prefix.empty() )
1884
                {
1885
                    dev_prefix = ipool->default_cdrom_dev_prefix();
1886
                }
1887

    
1888
                cdrom_disks.push(make_pair(dev_prefix, disk));
1889
            }
1890

    
1891
            // Disk IDs are 0..num-1, context disk is is num
1892
            disk->replace("DISK_ID", num_disks);
1893
        }
1894
    }
1895

    
1896
    assign_disk_targets(os_disk, used_targets);
1897
    assign_disk_targets(cdrom_disks, used_targets);
1898
    assign_disk_targets(datablock_disks, used_targets);
1899

    
1900
    return 0;
1901

    
1902
error_max_disks:
1903
    error_str = "Exceeded the maximum number of disks (20)";
1904
    return -1;
1905

    
1906
error_duplicated_target:
1907
    oss << "Two disks have defined the same target " << target;
1908
    error_str = oss.str();
1909

    
1910
error_common:
1911
    ImageManager *  imagem  = nd.get_imagem();
1912

    
1913
    vector<int>::iterator img_it;
1914

    
1915
    for ( img_it=acquired_images.begin() ; img_it < acquired_images.end(); img_it++ )
1916
    {
1917
        imagem->release_image(oid, *img_it, false);
1918
    }
1919

    
1920
    return -1;
1921
}
1922

    
1923
/* -------------------------------------------------------------------------- */
1924
/* -------------------------------------------------------------------------- */
1925

    
1926
void VirtualMachine::get_disk_info(int&         max_disk_id,
1927
                                   set<string>& used_targets)
1928
{
1929
    vector<Attribute  *> disks;
1930
    VectorAttribute *    disk;
1931

    
1932
    string target;
1933

    
1934
    int disk_id;
1935
    int num_disks;
1936

    
1937
    max_disk_id = -1;
1938

    
1939
    num_disks = obj_template->get("DISK", disks);
1940

    
1941
    for(int i=0; i<num_disks; i++)
1942
    {
1943
        disk = dynamic_cast<VectorAttribute * >(disks[i]);
1944

    
1945
        if ( disk == 0 )
1946
        {
1947
            continue;
1948
        }
1949

    
1950
        target = disk->vector_value("TARGET");
1951

    
1952
        if ( !target.empty() )
1953
        {
1954
            used_targets.insert(target);
1955
        }
1956

    
1957
        disk->vector_value("DISK_ID", disk_id);
1958

    
1959
        if ( disk_id > max_disk_id )
1960
        {
1961
            max_disk_id = disk_id;
1962
        }
1963
    }
1964

    
1965
    disks.clear();
1966

    
1967
    if ( obj_template->get("CONTEXT", disks) > 0 )
1968
    {
1969
        disk = dynamic_cast<VectorAttribute * >(disks[0]);
1970

    
1971
        if ( disk != 0 )
1972
        {
1973
            target = disk->vector_value("TARGET");
1974

    
1975
            if ( !target.empty() )
1976
            {
1977
                used_targets.insert(target);
1978
            }
1979

    
1980
            disk->vector_value("DISK_ID", disk_id);
1981

    
1982
            if ( disk_id > max_disk_id )
1983
            {
1984
                max_disk_id = disk_id;
1985
            }
1986
        }
1987
    }
1988
}
1989

    
1990
/* -------------------------------------------------------------------------- */
1991
/* -------------------------------------------------------------------------- */
1992

    
1993
VectorAttribute * VirtualMachine::set_up_attach_disk(
1994
                int                      vm_id,
1995
                VirtualMachineTemplate * tmpl,
1996
                set<string>&             used_targets,
1997
                int                      max_disk_id,
1998
                int                      uid,
1999
                int&                     image_id,
2000
                string&                  error_str)
2001
{
2002
    vector<Attribute  *> disks;
2003
    VectorAttribute *    new_disk;
2004

    
2005
    string target;
2006

    
2007
    Nebula&       nd     = Nebula::instance();
2008
    ImagePool *   ipool  = nd.get_ipool();
2009
    ImageManager* imagem = nd.get_imagem();
2010

    
2011
    string           dev_prefix;
2012
    Image::ImageType img_type;
2013

    
2014
    image_id = -1;
2015

    
2016
    // -------------------------------------------------------------------------
2017
    // Get the DISK attribute from the template
2018
    // -------------------------------------------------------------------------
2019

    
2020
    if ( tmpl->get("DISK", disks) != 1 )
2021
    {
2022
        error_str = "The template must contain one DISK attribute";
2023
        return 0;
2024
    }
2025

    
2026
    new_disk = dynamic_cast<VectorAttribute * >(disks[0]);
2027

    
2028
    if ( new_disk == 0 )
2029
    {
2030
        error_str = "Internal error parsing DISK attribute";
2031
        return 0;
2032
    }
2033

    
2034
    new_disk = new_disk->clone();
2035

    
2036
    // -------------------------------------------------------------------------
2037
    // Acquire the new disk image
2038
    // -------------------------------------------------------------------------
2039

    
2040
    int rc = ipool->disk_attribute(vm_id,
2041
                                   new_disk,
2042
                                   max_disk_id + 1,
2043
                                   img_type,
2044
                                   dev_prefix,
2045
                                   uid,
2046
                                   image_id,
2047
                                   error_str);
2048
    if ( rc != 0 )
2049
    {
2050
        delete new_disk;
2051
        return 0;
2052
    }
2053

    
2054
    target = new_disk->vector_value("TARGET");
2055

    
2056
    if ( !target.empty() )
2057
    {
2058
        if (  used_targets.insert(target).second == false )
2059
        {
2060
            ostringstream oss;
2061

    
2062
            oss << "Target " << target << " is already in use.";
2063
            error_str = oss.str();
2064

    
2065
            imagem->release_image(vm_id, image_id, false);
2066

    
2067
            delete new_disk;
2068
            return 0;
2069
        }
2070
    }
2071
    else
2072
    {
2073
        queue<pair <string, VectorAttribute *> > disks_queue;
2074

    
2075
        disks_queue.push(make_pair(dev_prefix, new_disk));
2076

    
2077
        assign_disk_targets(disks_queue, used_targets);
2078
    }
2079

    
2080
    return new_disk;
2081
}
2082

    
2083
/* -------------------------------------------------------------------------- */
2084
/* -------------------------------------------------------------------------- */
2085

    
2086
int VirtualMachine::set_attach_disk(int disk_id)
2087
{
2088
    VectorAttribute * disk;
2089

    
2090
    disk = get_disk(disk_id);
2091

    
2092
    if ( disk != 0 )
2093
    {
2094
        disk->replace("ATTACH", "YES");
2095
        return 0;
2096
    }
2097

    
2098
    return -1;
2099
}
2100

    
2101
/* -------------------------------------------------------------------------- */
2102
/* -------------------------------------------------------------------------- */
2103

    
2104
VectorAttribute* VirtualMachine::get_attach_disk()
2105
{
2106
    int                  num_disks;
2107
    vector<Attribute  *> disks;
2108
    VectorAttribute *    disk;
2109

    
2110
    num_disks = obj_template->get("DISK", disks);
2111

    
2112
    for(int i=0; i<num_disks; i++)
2113
    {
2114
        disk = dynamic_cast<VectorAttribute * >(disks[i]);
2115

    
2116
        if ( disk == 0 )
2117
        {
2118
            continue;
2119
        }
2120

    
2121
        if ( disk->vector_value("ATTACH") == "YES" )
2122
        {
2123
            return disk;
2124
        }
2125
    }
2126

    
2127
    return 0;
2128
}
2129

    
2130
/* -------------------------------------------------------------------------- */
2131
/* -------------------------------------------------------------------------- */
2132

    
2133
void VirtualMachine::clear_attach_disk()
2134
{
2135
    int                  num_disks;
2136
    vector<Attribute  *> disks;
2137
    VectorAttribute *    disk;
2138

    
2139
    num_disks = obj_template->get("DISK", disks);
2140

    
2141
    for(int i=0; i<num_disks; i++)
2142
    {
2143
        disk = dynamic_cast<VectorAttribute * >(disks[i]);
2144

    
2145
        if ( disk == 0 )
2146
        {
2147
            continue;
2148
        }
2149

    
2150
        if ( disk->vector_value("ATTACH") == "YES" )
2151
        {
2152
            disk->remove("ATTACH");
2153
            return;
2154
        }
2155
    }
2156
}
2157

    
2158
/* -------------------------------------------------------------------------- */
2159
/* -------------------------------------------------------------------------- */
2160

    
2161
VectorAttribute * VirtualMachine::delete_attach_disk()
2162
{
2163
    vector<Attribute  *> disks;
2164
    VectorAttribute *    disk;
2165

    
2166
    int num_disks = obj_template->get("DISK", disks);
2167

    
2168
    for(int i=0; i<num_disks; i++)
2169
    {
2170
        disk = dynamic_cast<VectorAttribute * >(disks[i]);
2171

    
2172
        if ( disk == 0 )
2173
        {
2174
            continue;
2175
        }
2176

    
2177
        if ( disk->vector_value("ATTACH") == "YES" )
2178
        {
2179
            return static_cast<VectorAttribute * >(obj_template->remove(disk));
2180
        }
2181
    }
2182

    
2183
    return 0;
2184
}
2185

    
2186
/* -------------------------------------------------------------------------- */
2187
/* -------------------------------------------------------------------------- */
2188

    
2189
bool VirtualMachine::isVolatile(const VectorAttribute * disk)
2190
{
2191
    string type = disk->vector_value("TYPE");
2192

    
2193
    one_util::toupper(type);
2194

    
2195
    return ( type == "SWAP" || type == "FS");
2196
}
2197

    
2198
/* -------------------------------------------------------------------------- */
2199
/* -------------------------------------------------------------------------- */
2200

    
2201
bool VirtualMachine::isVolatile(const Template * tmpl)
2202
{
2203
    vector<const Attribute*> disks;
2204
    int num_disks = tmpl->get("DISK", disks);
2205

    
2206
    for (int i = 0 ; i < num_disks ; i++)
2207
    {
2208
        const VectorAttribute * disk = dynamic_cast<const VectorAttribute*>(disks[i]);
2209

    
2210
        if (disk == 0)
2211
        {
2212
            continue;
2213
        }
2214

    
2215
        if (VirtualMachine::isVolatile(disk))
2216
        {
2217
            return true;
2218
        }
2219
    }
2220

    
2221
    return false;
2222
}
2223

    
2224
/* -------------------------------------------------------------------------- */
2225
/* -------------------------------------------------------------------------- */
2226

    
2227
bool VirtualMachine::isImported() const
2228
{
2229
    bool is_imported = false;
2230

    
2231
    get_template_attribute("IMPORTED", is_imported);
2232

    
2233
    return is_imported;
2234
}
2235

    
2236
/* -------------------------------------------------------------------------- */
2237
/* -------------------------------------------------------------------------- */
2238

    
2239
long long VirtualMachine::get_volatile_disk_size(Template * tmpl)
2240
{
2241
    long long size = 0;
2242

    
2243
    vector<const Attribute*> disks;
2244
    int num_disks = tmpl->get("DISK", disks);
2245

    
2246
    if (num_disks == 0)
2247
    {
2248
        return size;
2249
    }
2250

    
2251
    for (int i = 0 ; i < num_disks ; i++)
2252
    {
2253
        long long disk_size;
2254
        const VectorAttribute * disk = dynamic_cast<const VectorAttribute*>(disks[i]);
2255

    
2256
        if (disk == 0)
2257
        {
2258
            continue;
2259
        }
2260

    
2261
        if (!VirtualMachine::isVolatile(disk))
2262
        {
2263
            continue;
2264
        }
2265

    
2266
        if (disk->vector_value("SIZE", disk_size) == 0)
2267
        {
2268
            size += disk_size;
2269
        }
2270
    }
2271

    
2272
    return size;
2273
}
2274

    
2275
/* -------------------------------------------------------------------------- */
2276
/* -------------------------------------------------------------------------- */
2277

    
2278
VectorAttribute * VirtualMachine::get_attach_nic_info(
2279
                            VirtualMachineTemplate * tmpl,
2280
                            int&                     max_nic_id,
2281
                            string&                  error_str)
2282
{
2283
    vector<Attribute  *> nics;
2284
    VectorAttribute *    nic;
2285

    
2286
    int nic_id;
2287
    int num_nics;
2288

    
2289
    // -------------------------------------------------------------------------
2290
    // Get the highest NIC_ID
2291
    // -------------------------------------------------------------------------
2292

    
2293
    max_nic_id = -1;
2294

    
2295
    num_nics = obj_template->get("NIC", nics);
2296

    
2297
    for(int i=0; i<num_nics; i++)
2298
    {
2299
        nic = dynamic_cast<VectorAttribute * >(nics[i]);
2300

    
2301
        if ( nic == 0 )
2302
        {
2303
            continue;
2304
        }
2305

    
2306
        nic->vector_value("NIC_ID", nic_id);
2307

    
2308
        if ( nic_id > max_nic_id )
2309
        {
2310
            max_nic_id = nic_id;
2311
        }
2312
    }
2313

    
2314
    // -------------------------------------------------------------------------
2315
    // Get the new NIC attribute from the template
2316
    // -------------------------------------------------------------------------
2317

    
2318
    nics.clear();
2319

    
2320
    if ( tmpl->get("NIC", nics) != 1 )
2321
    {
2322
        error_str = "The template must contain one NIC attribute";
2323
        return 0;
2324
    }
2325

    
2326
    nic = dynamic_cast<VectorAttribute * >(nics[0]);
2327

    
2328
    if ( nic == 0 )
2329
    {
2330
        error_str = "Internal error parsing NIC attribute";
2331
        return 0;
2332
    }
2333

    
2334
    nic = nic->clone();
2335

    
2336
    merge_nic_defaults(nic);
2337

    
2338
    return nic;
2339
}
2340

    
2341
/* -------------------------------------------------------------------------- */
2342
/* -------------------------------------------------------------------------- */
2343

    
2344
int VirtualMachine::set_up_attach_nic(
2345
                        int                      vm_id,
2346
                        set<int>&                vm_sgs,
2347
                        VectorAttribute *        new_nic,
2348
                        vector<VectorAttribute*> &rules,
2349
                        int                      max_nic_id,
2350
                        int                      uid,
2351
                        string&                  error_str)
2352
{
2353
    Nebula&             nd     = Nebula::instance();
2354
    VirtualNetworkPool* vnpool = nd.get_vnpool();
2355

    
2356
    set<int> nic_sgs;
2357

    
2358
    int rc = vnpool->nic_attribute(new_nic, max_nic_id+1, uid, vm_id, error_str);
2359

    
2360
    if ( rc == -1 ) //-2 is not using a pre-defined network
2361
    {
2362
        return -1;
2363
    }
2364

    
2365
    get_security_groups(new_nic, nic_sgs);
2366

    
2367
    for (set<int>::iterator it = vm_sgs.begin(); it != vm_sgs.end(); it++)
2368
    {
2369
        nic_sgs.erase(*it);
2370
    }
2371

    
2372
    get_security_group_rules(vm_id, nic_sgs, rules);
2373

    
2374
    return 0;
2375
}
2376

    
2377
/* -------------------------------------------------------------------------- */
2378
/* -------------------------------------------------------------------------- */
2379

    
2380
void VirtualMachine::clear_attach_nic()
2381
{
2382
    int                  num_nics;
2383
    vector<Attribute  *> nics;
2384
    VectorAttribute *    nic;
2385

    
2386
    num_nics = obj_template->get("NIC", nics);
2387

    
2388
    for(int i=0; i<num_nics; i++)
2389
    {
2390
        nic = dynamic_cast<VectorAttribute * >(nics[i]);
2391

    
2392
        if ( nic == 0 )
2393
        {
2394
            continue;
2395
        }
2396

    
2397
        if ( nic->vector_value("ATTACH") == "YES" )
2398
        {
2399
            nic->remove("ATTACH");
2400
            return;
2401
        }
2402
    }
2403
}
2404

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

    
2408
VectorAttribute * VirtualMachine::delete_attach_nic()
2409
{
2410
    vector<Attribute  *> nics;
2411
    VectorAttribute *    nic;
2412

    
2413
    int num_nics = obj_template->get("NIC", nics);
2414

    
2415
    for(int i=0; i<num_nics; i++)
2416
    {
2417
        nic = dynamic_cast<VectorAttribute * >(nics[i]);
2418

    
2419
        if ( nic == 0 )
2420
        {
2421
            continue;
2422
        }
2423

    
2424
        if ( nic->vector_value("ATTACH") == "YES" )
2425
        {
2426
            return static_cast<VectorAttribute * >(obj_template->remove(nic));
2427
        }
2428
    }
2429

    
2430
    return 0;
2431
}
2432

    
2433
/* -------------------------------------------------------------------------- */
2434
/* -------------------------------------------------------------------------- */
2435

    
2436
void VirtualMachine::set_attach_nic(
2437
        VectorAttribute *       new_nic,
2438
        vector<VectorAttribute*> &rules)
2439
{
2440
    vector<VectorAttribute*>::iterator it;
2441

    
2442
    new_nic->replace("ATTACH", "YES");
2443

    
2444
    obj_template->set(new_nic);
2445

    
2446
    for(it = rules.begin(); it != rules.end(); it++ )
2447
    {
2448
        obj_template->set(*it);
2449
    }
2450
}
2451

    
2452
/* -------------------------------------------------------------------------- */
2453
/* -------------------------------------------------------------------------- */
2454

    
2455
int VirtualMachine::set_attach_nic(int nic_id)
2456
{
2457
    int num_nics;
2458
    int n_id;
2459

    
2460
    vector<Attribute  *> nics;
2461
    VectorAttribute *    nic;
2462

    
2463
    num_nics = obj_template->get("NIC", nics);
2464

    
2465
    for(int i=0; i<num_nics; i++)
2466
    {
2467
        nic = dynamic_cast<VectorAttribute * >(nics[i]);
2468

    
2469
        if ( nic == 0 )
2470
        {
2471
            continue;
2472
        }
2473

    
2474
        nic->vector_value("NIC_ID", n_id);
2475

    
2476
        if ( n_id == nic_id )
2477
        {
2478
            nic->replace("ATTACH", "YES");
2479
            return 0;
2480
        }
2481
    }
2482

    
2483
    return -1;
2484
}
2485

    
2486
/* -------------------------------------------------------------------------- */
2487
/* -------------------------------------------------------------------------- */
2488

    
2489
void VirtualMachine::release_disk_images()
2490
{
2491
    int     iid;
2492
    int     save_as_id;
2493
    int     num_disks;
2494

    
2495
    bool img_error;
2496

    
2497
    vector<Attribute const  * > disks;
2498
    ImageManager *              imagem;
2499

    
2500
    string  disk_base_path = "";
2501

    
2502
    Nebula& nd = Nebula::instance();
2503
    imagem     = nd.get_imagem();
2504

    
2505
    num_disks  = get_template_attribute("DISK",disks);
2506

    
2507
    for(int i=0; i<num_disks; i++)
2508
    {
2509
        VectorAttribute const *  disk =
2510
            dynamic_cast<VectorAttribute const * >(disks[i]);
2511

    
2512
        if ( disk == 0 )
2513
        {
2514
            continue;
2515
        }
2516

    
2517
        img_error = state != ACTIVE || lcm_state != EPILOG;
2518

    
2519
        if ( disk->vector_value("IMAGE_ID", iid) == 0 )
2520
        {
2521
            imagem->release_image(oid, iid, img_error);
2522
        }
2523

    
2524
        if ( disk->vector_value("SAVE_AS", save_as_id) == 0 )
2525
        {
2526
            imagem->release_image(oid, save_as_id, img_error);
2527
        }
2528
    }
2529
}
2530

    
2531
/* -------------------------------------------------------------------------- */
2532
/* -------------------------------------------------------------------------- */
2533

    
2534
int VirtualMachine::new_snapshot(string& name, int& snap_id)
2535
{
2536
    int num_snaps;
2537
    int id;
2538
    int max_id = -1;
2539

    
2540
    vector<Attribute  *> snaps;
2541
    VectorAttribute *    snap;
2542

    
2543
    num_snaps = obj_template->get("SNAPSHOT", snaps);
2544

    
2545
    for(int i=0; i<num_snaps; i++)
2546
    {
2547
        snap = dynamic_cast<VectorAttribute * >(snaps[i]);
2548

    
2549
        if ( snap == 0 )
2550
        {
2551
            continue;
2552
        }
2553

    
2554
        snap->vector_value("SNAPSHOT_ID", id);
2555

    
2556
        if (id > max_id)
2557
        {
2558
            max_id = id;
2559
        }
2560
    }
2561

    
2562
    snap_id = max_id + 1;
2563

    
2564
    if (name.empty())
2565
    {
2566
        ostringstream oss;
2567

    
2568
        oss << "snapshot-" << snap_id;
2569

    
2570
        name = oss.str();
2571
    }
2572

    
2573
    snap = new VectorAttribute("SNAPSHOT");
2574
    snap->replace("SNAPSHOT_ID", snap_id);
2575
    snap->replace("NAME", name);
2576
    snap->replace("TIME", (int)time(0));
2577
    snap->replace("HYPERVISOR_ID", "");
2578

    
2579
    snap->replace("ACTIVE", "YES");
2580

    
2581
    obj_template->set(snap);
2582

    
2583
    return 0;
2584
}
2585

    
2586
/* -------------------------------------------------------------------------- */
2587
/* -------------------------------------------------------------------------- */
2588

    
2589
int VirtualMachine::set_active_snapshot(int snap_id)
2590
{
2591
    int num_snaps;
2592
    int s_id;
2593

    
2594
    vector<Attribute  *> snaps;
2595
    VectorAttribute *    snap;
2596

    
2597
    num_snaps = obj_template->get("SNAPSHOT", snaps);
2598

    
2599
    for(int i=0; i<num_snaps; i++)
2600
    {
2601
        snap = dynamic_cast<VectorAttribute * >(snaps[i]);
2602

    
2603
        if ( snap == 0 )
2604
        {
2605
            continue;
2606
        }
2607

    
2608
        snap->vector_value("SNAPSHOT_ID", s_id);
2609

    
2610
        if ( s_id == snap_id )
2611
        {
2612
            snap->replace("ACTIVE", "YES");
2613
            return 0;
2614
        }
2615
    }
2616

    
2617
    return -1;
2618
}
2619

    
2620
/* -------------------------------------------------------------------------- */
2621
/* -------------------------------------------------------------------------- */
2622

    
2623
void VirtualMachine::update_snapshot_id(string& hypervisor_id)
2624
{
2625
    int                  num_snaps;
2626
    vector<Attribute  *> snaps;
2627
    VectorAttribute *    snap;
2628

    
2629
    num_snaps = obj_template->get("SNAPSHOT", snaps);
2630

    
2631
    for(int i=0; i<num_snaps; i++)
2632
    {
2633
        snap = dynamic_cast<VectorAttribute * >(snaps[i]);
2634

    
2635
        if ( snap == 0 )
2636
        {
2637
            continue;
2638
        }
2639

    
2640
        if ( snap->vector_value("ACTIVE") == "YES" )
2641
        {
2642
            snap->replace("HYPERVISOR_ID", hypervisor_id);
2643
            break;
2644
        }
2645
    }
2646
}
2647

    
2648
/* -------------------------------------------------------------------------- */
2649
/* -------------------------------------------------------------------------- */
2650

    
2651
void VirtualMachine::clear_active_snapshot()
2652
{
2653
    int                  num_snaps;
2654
    vector<Attribute  *> snaps;
2655
    VectorAttribute *    snap;
2656

    
2657
    num_snaps = obj_template->get("SNAPSHOT", snaps);
2658

    
2659
    for(int i=0; i<num_snaps; i++)
2660
    {
2661
        snap = dynamic_cast<VectorAttribute * >(snaps[i]);
2662

    
2663
        if ( snap == 0 )
2664
        {
2665
            continue;
2666
        }
2667

    
2668
        if ( snap->vector_value("ACTIVE") == "YES" )
2669
        {
2670
            snap->remove("ACTIVE");
2671
            return;
2672
        }
2673
    }
2674
}
2675

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

    
2679
void VirtualMachine::delete_active_snapshot()
2680
{
2681
    vector<Attribute  *> snaps;
2682
    VectorAttribute *    snap;
2683

    
2684
    int num_snaps = obj_template->get("SNAPSHOT", snaps);
2685

    
2686
    for(int i=0; i<num_snaps; i++)
2687
    {
2688
        snap = dynamic_cast<VectorAttribute * >(snaps[i]);
2689

    
2690
        if ( snap == 0 )
2691
        {
2692
            continue;
2693
        }
2694

    
2695
        if ( snap->vector_value("ACTIVE") == "YES" )
2696
        {
2697
            delete obj_template->remove(snap);
2698

    
2699
            return;
2700
        }
2701
    }
2702
}
2703

    
2704
/* -------------------------------------------------------------------------- */
2705
/* -------------------------------------------------------------------------- */
2706

    
2707
void VirtualMachine::delete_snapshots()
2708
{
2709
    obj_template->erase("SNAPSHOT");
2710
}
2711

    
2712
/* -------------------------------------------------------------------------- */
2713
/* -------------------------------------------------------------------------- */
2714

    
2715
int VirtualMachine::get_network_leases(string& estr)
2716
{
2717
    int                   num_nics, rc;
2718
    vector<Attribute  * > nics;
2719
    VirtualNetworkPool *  vnpool;
2720
    VectorAttribute *     nic;
2721

    
2722
    Nebula& nd = Nebula::instance();
2723
    vnpool     = nd.get_vnpool();
2724

    
2725
    vector<VectorAttribute*>            sg_rules;
2726
    vector<VectorAttribute*>::iterator  it;
2727

    
2728
    set<int> vm_sgs;
2729

    
2730
    num_nics   = user_obj_template->remove("NIC",nics);
2731

    
2732
    for (vector<Attribute*>::iterator it=nics.begin(); it != nics.end(); it++)
2733
    {
2734
        obj_template->set(*it);
2735
    }
2736

    
2737
    for(int i=0; i<num_nics; i++)
2738
    {
2739
        nic = dynamic_cast<VectorAttribute * >(nics[i]);
2740

    
2741
        if ( nic == 0 )
2742
        {
2743
            continue;
2744
        }
2745

    
2746
        merge_nic_defaults(nic);
2747

    
2748
        rc = vnpool->nic_attribute(nic, i, uid, oid, estr);
2749

    
2750
        if (rc == -1)
2751
        {
2752
            return -1;
2753
        }
2754
    }
2755

    
2756
    get_security_groups(vm_sgs);
2757

    
2758
    get_security_group_rules(get_oid(), vm_sgs, sg_rules);
2759

    
2760
    for(it = sg_rules.begin(); it != sg_rules.end(); it++ )
2761
    {
2762
        obj_template->set(*it);
2763
    }
2764

    
2765
    return 0;
2766
}
2767

    
2768
/* -------------------------------------------------------------------------- */
2769
/* -------------------------------------------------------------------------- */
2770

    
2771
void VirtualMachine::merge_nic_defaults(VectorAttribute* nic)
2772
{
2773
    vector<Attribute  *> nics_def;
2774
    VectorAttribute *    nic_def = 0;
2775

    
2776
    int num;
2777

    
2778
    num = obj_template->get("NIC_DEFAULT", nics_def);
2779

    
2780
    if (num == 0)
2781
    {
2782
        return;
2783
    }
2784
    else
2785
    {
2786
        nic_def = dynamic_cast<VectorAttribute * >(nics_def[0]);
2787

    
2788
        if ( nic_def == 0 )
2789
        {
2790
            return;
2791
        }
2792
    }
2793

    
2794
    nic->merge(nic_def, false);
2795
}
2796

    
2797
/* -------------------------------------------------------------------------- */
2798
/* -------------------------------------------------------------------------- */
2799

    
2800
void VirtualMachine::release_network_leases()
2801
{
2802
    string                        vnid;
2803
    string                        ip;
2804
    int                           num_nics;
2805
    vector<Attribute const  * >   nics;
2806

    
2807
    num_nics = get_template_attribute("NIC",nics);
2808

    
2809
    for(int i=0; i<num_nics; i++)
2810
    {
2811
        VectorAttribute const *  nic =
2812
            dynamic_cast<VectorAttribute const * >(nics[i]);
2813

    
2814
        release_network_leases(nic, oid);
2815
    }
2816
}
2817

    
2818
/* -------------------------------------------------------------------------- */
2819
/* -------------------------------------------------------------------------- */
2820

    
2821
int VirtualMachine::release_network_leases(VectorAttribute const * nic, int vmid)
2822
{
2823
    VirtualNetworkPool* vnpool = Nebula::instance().get_vnpool();
2824
    VirtualNetwork*     vn;
2825

    
2826
    int     vnid;
2827
    int     ar_id;
2828
    string  mac;
2829
    string  error_msg;
2830

    
2831
    if ( nic == 0 )
2832
    {
2833
        return -1;
2834
    }
2835

    
2836
    release_security_groups(vmid, nic);
2837

    
2838
    if (nic->vector_value("NETWORK_ID", vnid) != 0)
2839
    {
2840
        return -1;
2841
    }
2842

    
2843
    mac = nic->vector_value("MAC");
2844

    
2845
    if (mac.empty())
2846
    {
2847
        return -1;
2848
    }
2849

    
2850
    vn = vnpool->get(vnid, true);
2851

    
2852
    if ( vn == 0 )
2853
    {
2854
        return -1;
2855
    }
2856

    
2857
    if (nic->vector_value("AR_ID", ar_id) == 0)
2858
    {
2859
        vn->free_addr(ar_id, vmid, mac);
2860
    }
2861
    else
2862
    {
2863
        vn->free_addr(vmid, mac);
2864
    }
2865

    
2866
    vnpool->update(vn);
2867

    
2868
    vn->unlock();
2869

    
2870
    return 0;
2871
}
2872

    
2873
/* -------------------------------------------------------------------------- */
2874
/* -------------------------------------------------------------------------- */
2875

    
2876
void VirtualMachine::get_security_groups(set<int>& sgs) const
2877
{
2878

    
2879
    string                        vnid;
2880
    string                        ip;
2881
    int                           num_nics;
2882
    vector<Attribute const  * >   nics;
2883

    
2884
    num_nics = get_template_attribute("NIC", nics);
2885

    
2886
    for(int i=0; i<num_nics; i++)
2887
    {
2888
        get_security_groups(dynamic_cast<VectorAttribute const *>(nics[i]),sgs);
2889
    }
2890
}
2891
/* -------------------------------------------------------------------------- */
2892
/* -------------------------------------------------------------------------- */
2893

    
2894
void VirtualMachine::get_security_group_rules(int id, set<int>& secgroups,
2895
        vector<VectorAttribute*> &rules)
2896
{
2897
    set<int>::iterator sg_it;
2898

    
2899
    SecurityGroup*     sgroup;
2900
    SecurityGroupPool* sgroup_pool = Nebula::instance().get_secgrouppool();
2901

    
2902
    vector<VectorAttribute*>::iterator rule_it;
2903
    vector<VectorAttribute*> sgroup_rules;
2904

    
2905
    int                 vnet_id;
2906
    VirtualNetwork*     vnet;
2907
    VirtualNetworkPool* vnet_pool = Nebula::instance().get_vnpool();
2908

    
2909
    for (sg_it = secgroups.begin(); sg_it != secgroups.end(); sg_it++, sgroup_rules.clear())
2910
    {
2911
        sgroup = sgroup_pool->get(*sg_it, true);
2912

    
2913
        if (sgroup == 0)
2914
        {
2915
            continue;
2916
        }
2917

    
2918
        sgroup->add_vm(id);
2919

    
2920
        sgroup_pool->update(sgroup);
2921

    
2922
        sgroup->get_rules(sgroup_rules);
2923

    
2924
        sgroup->unlock();
2925

    
2926
        for (rule_it = sgroup_rules.begin(); rule_it != sgroup_rules.end(); rule_it++)
2927
        {
2928
            if ( (*rule_it)->vector_value("NETWORK_ID", vnet_id) != -1 )
2929
            {
2930
                vector<VectorAttribute*> vnet_rules;
2931

    
2932
                VectorAttribute * rule = *rule_it;
2933

    
2934
                vnet = vnet_pool->get(vnet_id, true);
2935

    
2936
                if (vnet == 0)
2937
                {
2938
                    continue;
2939
                }
2940

    
2941
                vnet->process_security_rule(rule, vnet_rules);
2942

    
2943
                delete rule;
2944

    
2945
                rules.insert(rules.end(), vnet_rules.begin(), vnet_rules.end());
2946

    
2947
                vnet->unlock();
2948
            }
2949
            else
2950
            {
2951
                rules.push_back(*rule_it);
2952
            }
2953
        }
2954
    }
2955
}
2956

    
2957
/* -------------------------------------------------------------------------- */
2958
/* -------------------------------------------------------------------------- */
2959

    
2960
void VirtualMachine::release_security_groups(int id, VectorAttribute const * nic)
2961
{
2962
    set<int>::iterator it;
2963
    set<int> secgroups;
2964

    
2965
    SecurityGroup*      sgroup;
2966
    SecurityGroupPool*  sgroup_pool = Nebula::instance().get_secgrouppool();
2967

    
2968
    get_security_groups(nic, secgroups);
2969

    
2970
    for (it = secgroups.begin(); it != secgroups.end(); it++)
2971
    {
2972
        sgroup = sgroup_pool->get(*it, true);
2973

    
2974
        if (sgroup == 0)
2975
        {
2976
            continue;
2977
        }
2978

    
2979
        sgroup->del_vm(id);
2980

    
2981
        sgroup_pool->update(sgroup);
2982

    
2983
        sgroup->unlock();
2984
    }
2985
}
2986

    
2987
/* -------------------------------------------------------------------------- */
2988
/* -------------------------------------------------------------------------- */
2989

    
2990
int VirtualMachine::generate_context(string &files, int &disk_id, string& token_password)
2991
{
2992
    ofstream file;
2993
    string   files_ds;
2994

    
2995
    vector<const Attribute*> attrs;
2996
    const VectorAttribute *  context;
2997

    
2998
    map<string, string>::const_iterator it;
2999

    
3000
    files = "";
3001
    bool token;
3002

    
3003
    if ( history == 0 )
3004
        return -1;
3005

    
3006
    if ( get_template_attribute("CONTEXT",attrs) != 1 )
3007
    {
3008
        log("VM", Log::INFO, "Virtual Machine has no context");
3009
        return 0;
3010
    }
3011

    
3012
    file.open(history->context_file.c_str(),ios::out);
3013

    
3014
    if (file.fail() == true)
3015
    {
3016
        ostringstream oss;
3017

    
3018
        oss << "Could not open context file: " << history->context_file;
3019
        log("VM", Log::ERROR, oss);
3020
        return -1;
3021
    }
3022

    
3023
    context = dynamic_cast<const VectorAttribute *>(attrs[0]);
3024

    
3025
    if (context == 0)
3026
    {
3027
        file.close();
3028
        return -1;
3029
    }
3030

    
3031
    files = context->vector_value("FILES");
3032

    
3033
    files_ds = context->vector_value("FILES_DS");
3034

    
3035
    if (!files_ds.empty())
3036
    {
3037
        files += " ";
3038
        files += files_ds;
3039
    }
3040

    
3041
    for (size_t i=0;i<files.length();i++)
3042
    {
3043
        if (files[i] == '\n')
3044
        {
3045
            files[i] = ' ';
3046
        }
3047
    }
3048

    
3049
    context->vector_value("TOKEN", token);
3050

    
3051
    if (token)
3052
    {
3053
        ofstream      token_file;
3054
        ostringstream oss;
3055

    
3056
        string* encrypted;
3057
        string  tk_error;
3058

    
3059
        if (token_password.empty())
3060
        {
3061
            tk_error = "CONTEXT/TOKEN set, but TOKEN_PASSWORD is not defined"
3062
                " in the user template.";
3063

    
3064
            file.close();
3065

    
3066
            log("VM", Log::ERROR, tk_error.c_str());
3067
            set_template_error_message(tk_error);
3068

    
3069
            return -1;
3070
        }
3071

    
3072
        // The token_password is taken from the owner user's template.
3073
        // We store this original owner in case a chown operation is performed.
3074
        add_template_attribute("CREATED_BY", uid);
3075

    
3076
        token_file.open(history->token_file.c_str(), ios::out);
3077

    
3078
        if (token_file.fail())
3079
        {
3080
            tk_error = "Cannot create token file";
3081

    
3082
            file.close();
3083

    
3084
            log("VM", Log::ERROR, tk_error.c_str());
3085
            set_template_error_message(tk_error);
3086

    
3087
            return -1;
3088
        }
3089

    
3090
        oss << oid << ':' << stime;
3091

    
3092
        encrypted = one_util::aes256cbc_encrypt(oss.str(), token_password);
3093

    
3094
        token_file << *encrypted << endl;
3095

    
3096
        token_file.close();
3097

    
3098
        delete encrypted;
3099

    
3100
        files += (" " + history->token_file);
3101
    }
3102

    
3103
    const map<string, string> values = context->value();
3104

    
3105
    file << "# Context variables generated by OpenNebula\n";
3106

    
3107
    for (it=values.begin(); it != values.end(); it++ )
3108
    {
3109
        //Replace every ' in value by '\''
3110
        string escape_str(it->second);
3111
        size_t pos = 0;
3112

    
3113
        while ((pos = escape_str.find('\'', pos)) != string::npos)
3114
        {
3115
            escape_str.replace(pos,1,"'\\''");
3116
            pos = pos + 4;
3117
        }
3118

    
3119
        file << it->first <<"='" << escape_str << "'" << endl;
3120
    }
3121

    
3122
    file.close();
3123

    
3124
    context->vector_value("DISK_ID", disk_id);
3125

    
3126
    return 1;
3127
}
3128

    
3129
/* -------------------------------------------------------------------------- */
3130

    
3131
int VirtualMachine::get_image_from_disk(int disk_id, bool hot, string& err_str)
3132
{
3133
    int iid = -1;
3134
    int rc;
3135

    
3136
    VectorAttribute *     disk;
3137

    
3138
    ostringstream oss;
3139

    
3140
    disk = get_disk(disk_id);
3141

    
3142
    if ( disk == 0 )
3143
    {
3144
        goto error_not_found;
3145
    }
3146

    
3147
    if(!((disk->vector_value("SAVE_AS")).empty()))
3148
    {
3149
        goto error_saved;
3150
    }
3151

    
3152
    if(!(disk->vector_value("PERSISTENT").empty()) && !hot)
3153
    {
3154
        goto error_persistent;
3155
    }
3156

    
3157
    rc = disk->vector_value("IMAGE_ID", iid);
3158

    
3159
    if ( rc != 0 )
3160
    {
3161
        goto error_image_id;
3162
    }
3163

    
3164
    return iid;
3165

    
3166
error_persistent:
3167
    oss << "Source image for DISK " << disk_id << " is persistent.";
3168
    goto error_common;
3169

    
3170
error_saved:
3171
    oss << "The DISK " << disk_id << " is already going to be saved.";
3172
    goto error_common;
3173

    
3174
error_image_id:
3175
    oss << "The DISK " << disk_id << " does not have a valid IMAGE_ID.";
3176
    goto error_common;
3177

    
3178
error_not_found:
3179
    oss << "The DISK " << disk_id << " does not exist for VM " << oid << ".";
3180

    
3181
error_common:
3182
    err_str = oss.str();
3183

    
3184
    return -1;
3185
}
3186

    
3187
/* -------------------------------------------------------------------------- */
3188
/* -------------------------------------------------------------------------- */
3189

    
3190
int VirtualMachine::set_saveas_state(int disk_id, bool hot)
3191
{
3192
    VectorAttribute* disk;
3193

    
3194
    switch (state)
3195
    {
3196
        case ACTIVE:
3197
            switch (lcm_state)
3198
            {
3199
                case RUNNING:
3200
                    lcm_state = HOTPLUG_SAVEAS;
3201
                break;
3202

    
3203
                default:
3204
                    return -1;
3205
            }
3206
        break;
3207

    
3208
        case POWEROFF:
3209
            state     = ACTIVE;
3210
            lcm_state = HOTPLUG_SAVEAS_POWEROFF;
3211
        break;
3212

    
3213
        case SUSPENDED:
3214
            state     = ACTIVE;
3215
            lcm_state = HOTPLUG_SAVEAS_SUSPENDED;
3216
        break;
3217

    
3218
        default:
3219
            return -1;
3220
    }
3221

    
3222
    disk = get_disk(disk_id);
3223

    
3224
    if ( disk != 0 )
3225
    {
3226
        if (hot)
3227
        {
3228
            disk->replace("HOTPLUG_SAVE_AS_ACTIVE", "YES");
3229
        }
3230
        else
3231
        {
3232
            disk->replace("SAVE_AS_ACTIVE", "YES");
3233
        }
3234
    }
3235

    
3236
    return 0;
3237
}
3238

    
3239
/* -------------------------------------------------------------------------- */
3240
/* -------------------------------------------------------------------------- */
3241

    
3242
int VirtualMachine::clear_saveas_state(int disk_id, bool hot)
3243
{
3244
    VectorAttribute * disk;
3245

    
3246
    disk = get_disk(disk_id);
3247

    
3248
    if (disk != 0)
3249
    {
3250
        if (hot)
3251
        {
3252
            disk->remove("HOTPLUG_SAVE_AS_ACTIVE");
3253
            disk->remove("HOTPLUG_SAVE_AS");
3254
            disk->remove("HOTPLUG_SAVE_AS_SOURCE");
3255
        }
3256
        else
3257
        {
3258
            disk->remove("SAVE_AS_ACTIVE");
3259
        }
3260
    }
3261

    
3262
    switch (lcm_state)
3263
    {
3264
        case HOTPLUG_SAVEAS:
3265
            lcm_state = RUNNING;
3266
        break;
3267

    
3268
        case HOTPLUG_SAVEAS_POWEROFF:
3269
            state     = POWEROFF;
3270
            lcm_state = LCM_INIT;
3271
        break;
3272

    
3273
        case HOTPLUG_SAVEAS_SUSPENDED:
3274
            state     = SUSPENDED;
3275
            lcm_state = LCM_INIT;
3276
        break;
3277

    
3278
        default:
3279
            return -1;
3280
    }
3281

    
3282
    return 0;
3283
}
3284

    
3285
/* -------------------------------------------------------------------------- */
3286
/* -------------------------------------------------------------------------- */
3287

    
3288
VectorAttribute* VirtualMachine::get_disk(int disk_id)
3289
{
3290
    int num_disks;
3291
    int tdisk_id;
3292

    
3293
    vector<Attribute  *> disks;
3294
    VectorAttribute *    disk;
3295

    
3296
    num_disks = obj_template->get("DISK", disks);
3297

    
3298
    for(int i=0; i<num_disks; i++)
3299
    {
3300
        disk = dynamic_cast<VectorAttribute * >(disks[i]);
3301

    
3302
        if ( disk == 0 )
3303
        {
3304
            continue;
3305
        }
3306

    
3307
        disk->vector_value("DISK_ID", tdisk_id);
3308

    
3309
        if ( tdisk_id == disk_id )
3310
        {
3311
            return disk;
3312
        }
3313
    }
3314

    
3315
    return 0;
3316
}
3317

    
3318
/* -------------------------------------------------------------------------- */
3319
/* -------------------------------------------------------------------------- */
3320

    
3321
int VirtualMachine::save_disk(int           disk_id,
3322
                              const string& source,
3323
                              int           img_id)
3324
{
3325
    VectorAttribute * disk;
3326

    
3327
    if (lcm_state != HOTPLUG_SAVEAS && lcm_state != HOTPLUG_SAVEAS_SUSPENDED
3328
        && lcm_state != HOTPLUG_SAVEAS_POWEROFF )
3329
    {
3330
        return -1;
3331
    }
3332

    
3333
    disk = get_disk(disk_id);
3334

    
3335
    if ( disk != 0 )
3336
    {
3337
        disk->replace("SAVE_AS_SOURCE", source);
3338

    
3339
        disk->replace("SAVE_AS", img_id);
3340

    
3341
        disk->replace("SAVE", "YES");
3342
    }
3343

    
3344
    return 0;
3345
}
3346

    
3347
/* -------------------------------------------------------------------------- */
3348
/* -------------------------------------------------------------------------- */
3349

    
3350
int VirtualMachine::clear_save_disk(int disk_id)
3351
{
3352
    VectorAttribute * disk;
3353

    
3354
    disk = get_disk(disk_id);
3355

    
3356
    if ( disk != 0 )
3357
    {
3358
        disk->remove("SAVE_AS_SOURCE");
3359
        disk->remove("SAVE_AS");
3360
        disk->replace("SAVE", "NO");
3361

    
3362
        return 0;
3363
    }
3364

    
3365
    return -1;
3366
}
3367

    
3368
/* -------------------------------------------------------------------------- */
3369
/* -------------------------------------------------------------------------- */
3370

    
3371
int VirtualMachine::get_save_disk_image(int disk_id)
3372
{
3373
    VectorAttribute * disk;
3374
    bool    save;
3375
    int     img_id = -1;
3376

    
3377
    disk = get_disk(disk_id);
3378

    
3379
    if ( disk != 0 )
3380
    {
3381
        disk->vector_value("SAVE", save);
3382

    
3383
        if (save)
3384
        {
3385
            disk->vector_value("SAVE_AS", img_id);
3386
        }
3387
    }
3388

    
3389
    return img_id;
3390
}
3391

    
3392
/* -------------------------------------------------------------------------- */
3393
/* -------------------------------------------------------------------------- */
3394

    
3395
int VirtualMachine::save_disk_hot(int           disk_id,
3396
                                  const string& source,
3397
                                  int           img_id)
3398
{
3399
    VectorAttribute * disk;
3400

    
3401
    if (lcm_state != HOTPLUG_SAVEAS && lcm_state != HOTPLUG_SAVEAS_SUSPENDED
3402
        && lcm_state != HOTPLUG_SAVEAS_POWEROFF )
3403
    {
3404
        return -1;
3405
    }
3406

    
3407
    disk = get_disk(disk_id);
3408

    
3409
    if ( disk != 0 )
3410
    {
3411
        disk->replace("HOTPLUG_SAVE_AS", img_id);
3412
        disk->replace("HOTPLUG_SAVE_AS_SOURCE", source);
3413
    }
3414

    
3415
    return 0;
3416
}
3417

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

    
3421
int VirtualMachine::get_saveas_disk_hot(int& disk_id, string& source, int& image_id)
3422
{
3423
    vector<Attribute  *> disks;
3424
    VectorAttribute *    disk;
3425

    
3426
    int rc;
3427
    int num_disks;
3428

    
3429
    num_disks = obj_template->get("DISK", disks);
3430

    
3431
    for(int i=0; i<num_disks; i++)
3432
    {
3433
        disk = dynamic_cast<VectorAttribute * >(disks[i]);
3434

    
3435
        if ( disk == 0 )
3436
        {
3437
            continue;
3438
        }
3439

    
3440
        if ( disk->vector_value("HOTPLUG_SAVE_AS_ACTIVE") == "YES" )
3441
        {
3442
            source = disk->vector_value("HOTPLUG_SAVE_AS_SOURCE");
3443

    
3444
            rc =  disk->vector_value("HOTPLUG_SAVE_AS", image_id);
3445
            rc += disk->vector_value("DISK_ID",  disk_id);
3446

    
3447
            if ( rc != 0 || source.empty() )
3448
            {
3449
                return -1;
3450
            }
3451

    
3452
            return 0;
3453
        }
3454
    }
3455

    
3456
    return -1;
3457
}
3458

    
3459
/* -------------------------------------------------------------------------- */
3460
/* -------------------------------------------------------------------------- */
3461

    
3462
int VirtualMachine::cancel_saveas_disk(int& image_id)
3463
{
3464
    vector<Attribute  *> disks;
3465
    VectorAttribute *    disk;
3466

    
3467
    int num_disks;
3468

    
3469
    num_disks = obj_template->get("DISK", disks);
3470

    
3471
    bool active, hot_active;
3472

    
3473
    image_id = -1;
3474

    
3475
    for(int i=0; i<num_disks; i++)
3476
    {
3477
        disk = dynamic_cast<VectorAttribute * >(disks[i]);
3478

    
3479
        if ( disk == 0 )
3480
        {
3481
            continue;
3482
        }
3483

    
3484
        disk->vector_value("SAVE_AS_ACTIVE", active);
3485
        disk->vector_value("HOTPLUG_SAVE_AS_ACTIVE", hot_active);
3486

    
3487
        if (active)
3488
        {
3489
            disk->vector_value("SAVE_AS", image_id);
3490

    
3491
            disk->remove("SAVE_AS_ACTIVE");
3492
            disk->remove("SAVE_AS_SOURCE");
3493
            disk->remove("SAVE_AS");
3494

    
3495
            disk->replace("SAVE", "NO");
3496

    
3497
            return 0;
3498
        }
3499

    
3500
        if (hot_active)
3501
        {
3502
            disk->vector_value("HOTPLUG_SAVE_AS", image_id);
3503

    
3504
            disk->remove("HOTPLUG_SAVE_AS_ACTIVE");
3505
            disk->remove("HOTPLUG_SAVE_AS");
3506
            disk->remove("HOTPLUG_SAVE_AS_SOURCE");
3507

    
3508
            return 0;
3509
        }
3510
    }
3511

    
3512
    return -1;
3513
}
3514

    
3515
/* -------------------------------------------------------------------------- */
3516
/* -------------------------------------------------------------------------- */
3517

    
3518
void VirtualMachine::set_auth_request(int uid,
3519
                                      AuthRequest& ar,
3520
                                      VirtualMachineTemplate *tmpl)
3521
{
3522
    int                   num;
3523
    vector<Attribute  * > vectors;
3524
    VectorAttribute *     vector;
3525

    
3526
    Nebula& nd = Nebula::instance();
3527

    
3528
    ImagePool *          ipool  = nd.get_ipool();
3529
    VirtualNetworkPool * vnpool = nd.get_vnpool();
3530
    SecurityGroupPool *  sgpool = nd.get_secgrouppool();
3531

    
3532
    set<int>        sgroups;
3533
    SecurityGroup * sgroup;
3534

    
3535
    num = tmpl->get("DISK",vectors);
3536

    
3537
    for(int i=0; i<num; i++)
3538
    {
3539

    
3540
        vector = dynamic_cast<VectorAttribute * >(vectors[i]);
3541

    
3542
        if ( vector == 0 )
3543
        {
3544
            continue;
3545
        }
3546

    
3547
        ipool->authorize_disk(vector,uid,&ar);
3548
    }
3549

    
3550
    vectors.clear();
3551

    
3552
    num = tmpl->get("NIC",vectors);
3553

    
3554
    for(int i=0; i<num; i++, sgroups.clear())
3555
    {
3556
        vector = dynamic_cast<VectorAttribute * >(vectors[i]);
3557

    
3558
        if ( vector == 0 )
3559
        {
3560
            continue;
3561
        }
3562

    
3563
        vnpool->authorize_nic(vector,uid,&ar);
3564

    
3565
        get_security_groups(vector, sgroups);
3566

    
3567
        for(set<int>::iterator it = sgroups.begin(); it != sgroups.end(); it++)
3568
        {
3569
            sgroup = sgpool->get(*it, true);
3570

    
3571
            if(sgroup != 0)
3572
            {
3573
                PoolObjectAuth perm;
3574
                sgroup->get_permissions(perm);
3575

    
3576
                sgroup->unlock();
3577

    
3578
                ar.add_auth(AuthRequest::USE, perm);
3579
            }
3580
        }
3581
    }
3582
}
3583

    
3584
/* -------------------------------------------------------------------------- */
3585
/* -------------------------------------------------------------------------- */
3586

    
3587
pthread_mutex_t VirtualMachine::lex_mutex = PTHREAD_MUTEX_INITIALIZER;
3588

    
3589
extern "C"
3590
{
3591
    typedef struct yy_buffer_state * YY_BUFFER_STATE;
3592

    
3593
    int vm_var_parse (VirtualMachine * vm,
3594
                      ostringstream *  parsed,
3595
                      char **          errmsg);
3596

    
3597
    int vm_file_var_parse (VirtualMachine * vm,
3598
                           vector<int> *    img_ids,
3599
                           char **          errmsg);
3600

    
3601
    int vm_var_lex_destroy();
3602

    
3603
    YY_BUFFER_STATE vm_var__scan_string(const char * str);
3604

    
3605
    void vm_var__delete_buffer(YY_BUFFER_STATE);
3606
}
3607

    
3608
/* -------------------------------------------------------------------------- */
3609

    
3610
int VirtualMachine::parse_template_attribute(const string& attribute,
3611
                                             string&       parsed,
3612
                                             string&       error_str)
3613
{
3614
    YY_BUFFER_STATE  str_buffer = 0;
3615
    const char *     str;
3616
    int              rc;
3617
    ostringstream    oss_parsed;
3618
    char *           error_msg = 0;
3619

    
3620
    pthread_mutex_lock(&lex_mutex);
3621

    
3622
    str        = attribute.c_str();
3623
    str_buffer = vm_var__scan_string(str);
3624

    
3625
    if (str_buffer == 0)
3626
    {
3627
        goto error_yy;
3628
    }
3629

    
3630
    rc = vm_var_parse(this, &oss_parsed, &error_msg);
3631

    
3632
    vm_var__delete_buffer(str_buffer);
3633

    
3634
    vm_var_lex_destroy();
3635

    
3636
    pthread_mutex_unlock(&lex_mutex);
3637

    
3638
    if ( rc != 0 && error_msg != 0 )
3639
    {
3640
        ostringstream oss;
3641

    
3642
        oss << "Error parsing: " << attribute << ". " << error_msg;
3643
        log("VM", Log::ERROR, oss);
3644

    
3645
        error_str = oss.str();
3646

    
3647
        free(error_msg);
3648
    }
3649

    
3650
    parsed = oss_parsed.str();
3651

    
3652
    return rc;
3653

    
3654
error_yy:
3655
    log("VM",Log::ERROR,"Error setting scan buffer");
3656
    pthread_mutex_unlock(&lex_mutex);
3657
    return -1;
3658
}
3659

    
3660
/* -------------------------------------------------------------------------- */
3661

    
3662
int VirtualMachine::parse_file_attribute(string       attribute,
3663
                                         vector<int>& img_ids,
3664
                                         string&      error)
3665
{
3666
    YY_BUFFER_STATE  str_buffer = 0;
3667
    const char *     str;
3668
    int              rc;
3669
    ostringstream    oss_parsed;
3670
    char *           error_msg = 0;
3671

    
3672
    size_t non_blank_pos;
3673

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

    
3678
    if ( non_blank_pos != string::npos )
3679
    {
3680
        attribute.erase(0, non_blank_pos);
3681
    }
3682

    
3683
    pthread_mutex_lock(&lex_mutex);
3684

    
3685
    str        = attribute.c_str();
3686
    str_buffer = vm_var__scan_string(str);
3687

    
3688
    if (str_buffer == 0)
3689
    {
3690
        goto error_yy;
3691
    }
3692

    
3693
    rc = vm_file_var_parse(this, &img_ids, &error_msg);
3694

    
3695
    vm_var__delete_buffer(str_buffer);
3696

    
3697
    vm_var_lex_destroy();
3698

    
3699
    pthread_mutex_unlock(&lex_mutex);
3700

    
3701
    if ( rc != 0  )
3702
    {
3703
        ostringstream oss;
3704

    
3705
        if ( error_msg != 0 )
3706
        {
3707
            oss << "Error parsing: " << attribute << ". " << error_msg;
3708
            free(error_msg);
3709
        }
3710
        else
3711
        {
3712
            oss << "Unknown error parsing: " << attribute << ".";
3713
        }
3714

    
3715
        error = oss.str();
3716
    }
3717

    
3718
    return rc;
3719

    
3720
error_yy:
3721
    log("VM",Log::ERROR,"Error setting scan buffer");
3722
    pthread_mutex_unlock(&lex_mutex);
3723
    return -1;
3724
}
3725
/* -------------------------------------------------------------------------- */
3726
/* -------------------------------------------------------------------------- */
3727

    
3728
string& VirtualMachine::to_xml_extended(string& xml, int n_history) const
3729
{
3730
    string template_xml;
3731
    string user_template_xml;
3732
    string history_xml;
3733
    string perm_xml;
3734
    ostringstream        oss;
3735

    
3736
    oss << "<VM>"
3737
        << "<ID>"        << oid       << "</ID>"
3738
        << "<UID>"       << uid       << "</UID>"
3739
        << "<GID>"       << gid       << "</GID>"
3740
        << "<UNAME>"     << uname     << "</UNAME>"
3741
        << "<GNAME>"     << gname     << "</GNAME>"
3742
        << "<NAME>"      << name      << "</NAME>"
3743
        << perms_to_xml(perm_xml)
3744
        << "<LAST_POLL>" << last_poll << "</LAST_POLL>"
3745
        << "<STATE>"     << state     << "</STATE>"
3746
        << "<LCM_STATE>" << lcm_state << "</LCM_STATE>"
3747
        << "<PREV_STATE>"     << prev_state     << "</PREV_STATE>"
3748
        << "<PREV_LCM_STATE>" << prev_lcm_state << "</PREV_LCM_STATE>"
3749
        << "<RESCHED>"   << resched   << "</RESCHED>"
3750
        << "<STIME>"     << stime     << "</STIME>"
3751
        << "<ETIME>"     << etime     << "</ETIME>"
3752
        << "<DEPLOY_ID>" << deploy_id << "</DEPLOY_ID>"
3753
        << "<MEMORY>"    << memory    << "</MEMORY>"
3754
        << "<CPU>"       << cpu       << "</CPU>"
3755
        << "<NET_TX>"    << net_tx    << "</NET_TX>"
3756
        << "<NET_RX>"    << net_rx    << "</NET_RX>"
3757
        << obj_template->to_xml(template_xml)
3758
        << user_obj_template->to_xml(user_template_xml);
3759

    
3760
    if ( hasHistory() && n_history > 0 )
3761
    {
3762
        oss << "<HISTORY_RECORDS>";
3763

    
3764
        if ( n_history == 2 )
3765
        {
3766
            for (unsigned int i=0; i < history_records.size(); i++)
3767
            {
3768
                oss << history_records[i]->to_xml(history_xml);
3769
            }
3770
        }
3771
        else
3772
        {
3773
            oss << history->to_xml(history_xml);
3774
        }
3775

    
3776
        oss << "</HISTORY_RECORDS>";
3777
    }
3778
    else
3779
    {
3780
        oss << "<HISTORY_RECORDS/>";
3781
    }
3782

    
3783
    oss << "</VM>";
3784

    
3785
    xml = oss.str();
3786

    
3787
    return xml;
3788
}
3789

    
3790
/* -------------------------------------------------------------------------- */
3791
/* -------------------------------------------------------------------------- */
3792

    
3793
int VirtualMachine::from_xml(const string &xml_str)
3794
{
3795
    vector<xmlNodePtr> content;
3796

    
3797
    int istate;
3798
    int ilcmstate;
3799
    int rc = 0;
3800

    
3801
    // Initialize the internal XML object
3802
    update_from_str(xml_str);
3803

    
3804
    // Get class base attributes
3805
    rc += xpath(oid,       "/VM/ID",    -1);
3806

    
3807
    rc += xpath(uid,       "/VM/UID",   -1);
3808
    rc += xpath(gid,       "/VM/GID",   -1);
3809

    
3810
    rc += xpath(uname,     "/VM/UNAME", "not_found");
3811
    rc += xpath(gname,     "/VM/GNAME", "not_found");
3812
    rc += xpath(name,      "/VM/NAME",  "not_found");
3813

    
3814
    rc += xpath(last_poll, "/VM/LAST_POLL", 0);
3815
    rc += xpath(resched,   "/VM/RESCHED",   0);
3816

    
3817
    rc += xpath(stime,     "/VM/STIME",    0);
3818
    rc += xpath(etime,     "/VM/ETIME",    0);
3819
    rc += xpath(deploy_id, "/VM/DEPLOY_ID","");
3820

    
3821
    rc += xpath(memory,    "/VM/MEMORY",   0);
3822
    rc += xpath(cpu,       "/VM/CPU",      0);
3823
    rc += xpath(net_tx,    "/VM/NET_TX",   0);
3824
    rc += xpath(net_rx,    "/VM/NET_RX",   0);
3825

    
3826
    // Permissions
3827
    rc += perms_from_xml();
3828

    
3829
    //VM states
3830
    rc += xpath(istate,    "/VM/STATE",     0);
3831
    rc += xpath(ilcmstate, "/VM/LCM_STATE", 0);
3832

    
3833
    state     = static_cast<VmState>(istate);
3834
    lcm_state = static_cast<LcmState>(ilcmstate);
3835

    
3836
    xpath(istate,    "/VM/PREV_STATE",     istate);
3837
    xpath(ilcmstate, "/VM/PREV_LCM_STATE", ilcmstate);
3838

    
3839
    prev_state     = static_cast<VmState>(istate);
3840
    prev_lcm_state = static_cast<LcmState>(ilcmstate);
3841

    
3842
    // Virtual Machine template
3843
    ObjectXML::get_nodes("/VM/TEMPLATE", content);
3844

    
3845
    if (content.empty())
3846
    {
3847
        return -1;
3848
    }
3849
    rc += obj_template->from_xml_node(content[0]);
3850

    
3851
    ObjectXML::free_nodes(content);
3852
    content.clear();
3853

    
3854
    // Virtual Machine user template
3855

    
3856
    ObjectXML::get_nodes("/VM/USER_TEMPLATE", content);
3857

    
3858
    if (content.empty())
3859
    {
3860
        return -1;
3861
    }
3862

    
3863
    rc += user_obj_template->from_xml_node(content[0]);
3864

    
3865
    ObjectXML::free_nodes(content);
3866
    content.clear();
3867

    
3868
    // Last history entry
3869

    
3870
    ObjectXML::get_nodes("/VM/HISTORY_RECORDS/HISTORY", content);
3871

    
3872
    if (!content.empty())
3873
    {
3874
        history = new History(oid);
3875
        rc += history->from_xml_node(content[0]);
3876

    
3877
        history_records.resize(history->seq + 1);
3878
        history_records[history->seq] = history;
3879

    
3880
        ObjectXML::free_nodes(content);
3881
    }
3882

    
3883
    if (rc != 0)
3884
    {
3885
        return -1;
3886
    }
3887

    
3888
    return 0;
3889
}
3890

    
3891
/* -------------------------------------------------------------------------- */
3892
/* -------------------------------------------------------------------------- */
3893

    
3894
string VirtualMachine::get_system_dir() const
3895
{
3896
    ostringstream oss;
3897

    
3898
    oss << history->ds_location << "/" << history->ds_id << "/"<< oid;
3899

    
3900
    return oss.str();
3901
};
3902

    
3903
/* -------------------------------------------------------------------------- */
3904
/* -------------------------------------------------------------------------- */
3905

    
3906
void VirtualMachine::update_info(
3907
    const int _memory,
3908
    const int _cpu,
3909
    const long long _net_tx,
3910
    const long long _net_rx,
3911
    const map<string, string> &custom)
3912
{
3913
    map<string, string>::const_iterator it;
3914

    
3915
    last_poll = time(0);
3916

    
3917
    if (_memory != -1)
3918
    {
3919
        memory = _memory;
3920
    }
3921

    
3922
    if (_cpu != -1)
3923
    {
3924
        cpu    = _cpu;
3925
    }
3926

    
3927
    if (_net_tx != -1)
3928
    {
3929
        net_tx = _net_tx;
3930
    }
3931

    
3932
    if (_net_rx != -1)
3933
    {
3934
        net_rx = _net_rx;
3935
    }
3936

    
3937
    for (it = custom.begin(); it != custom.end(); it++)
3938
    {
3939
        replace_template_attribute(it->first, it->second);
3940
    }
3941

    
3942
    set_vm_info();
3943

    
3944
    clear_template_monitor_error();
3945
};
3946

    
3947
/* -------------------------------------------------------------------------- */
3948
/* -------------------------------------------------------------------------- */
3949

    
3950
int VirtualMachine::replace_template(
3951
        const string&   tmpl_str,
3952
        bool            keep_restricted,
3953
        string&         error)
3954
{
3955
    VirtualMachineTemplate * new_tmpl =
3956
            new VirtualMachineTemplate(false,'=',"USER_TEMPLATE");
3957

    
3958
    if ( new_tmpl == 0 )
3959
    {
3960
        error = "Cannot allocate a new template";
3961
        return -1;
3962
    }
3963

    
3964
    if ( new_tmpl->parse_str_or_xml(tmpl_str, error) != 0 )
3965
    {
3966
        delete new_tmpl;
3967
        return -1;
3968
    }
3969

    
3970
    if (keep_restricted)
3971
    {
3972
        new_tmpl->remove_restricted();
3973

    
3974
        if (user_obj_template != 0)
3975
        {
3976
            user_obj_template->remove_all_except_restricted();
3977

    
3978
            string aux_error;
3979
            new_tmpl->merge(user_obj_template, aux_error);
3980
        }
3981
    }
3982

    
3983
    delete user_obj_template;
3984

    
3985
    user_obj_template = new_tmpl;
3986

    
3987
    return 0;
3988
}
3989

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

    
3993
int VirtualMachine::append_template(
3994
        const string&   tmpl_str,
3995
        bool            keep_restricted,
3996
        string&         error)
3997
{
3998
    VirtualMachineTemplate * new_tmpl =
3999
            new VirtualMachineTemplate(false,'=',"USER_TEMPLATE");
4000

    
4001
    if ( new_tmpl == 0 )
4002
    {
4003
        error = "Cannot allocate a new template";
4004
        return -1;
4005
    }
4006

    
4007
    if ( new_tmpl->parse_str_or_xml(tmpl_str, error) != 0 )
4008
    {
4009
        delete new_tmpl;
4010
        return -1;
4011
    }
4012

    
4013
    if (keep_restricted)
4014
    {
4015
        new_tmpl->remove_restricted();
4016
    }
4017

    
4018
    if (user_obj_template != 0)
4019
    {
4020
        user_obj_template->merge(new_tmpl, error);
4021
        delete new_tmpl;
4022
    }
4023
    else
4024
    {
4025
        user_obj_template = new_tmpl;
4026
    }
4027

    
4028
    return 0;
4029
}
4030

    
4031
/* -------------------------------------------------------------------------- */
4032
/* -------------------------------------------------------------------------- */
4033

    
4034
void VirtualMachine::set_template_error_message(const string& message)
4035
{
4036
    set_template_error_message("ERROR", message);
4037
}
4038

    
4039
/* -------------------------------------------------------------------------- */
4040

    
4041
void VirtualMachine::set_template_error_message(const string& name,
4042
                                               const string& message)
4043
{
4044
    SingleAttribute * attr;
4045
    ostringstream     error_value;
4046

    
4047
    error_value << one_util::log_time() << " : " << message;
4048

    
4049
    attr = new SingleAttribute(name, error_value.str());
4050

    
4051
    user_obj_template->erase(name);
4052
    user_obj_template->set(attr);
4053
}
4054

    
4055
/* -------------------------------------------------------------------------- */
4056
/* -------------------------------------------------------------------------- */
4057

    
4058
void VirtualMachine::clear_template_error_message()
4059
{
4060
    user_obj_template->erase("ERROR");
4061
}
4062

    
4063
/* -------------------------------------------------------------------------- */
4064
/* -------------------------------------------------------------------------- */
4065

    
4066
void VirtualMachine::set_template_monitor_error(const string& message)
4067
{
4068
    set_template_error_message("ERROR_MONITOR", message);
4069
}
4070

    
4071
/* -------------------------------------------------------------------------- */
4072

    
4073
void VirtualMachine::clear_template_monitor_error()
4074
{
4075
    user_obj_template->erase("ERROR_MONITOR");
4076
}
4077

    
4078
/* -------------------------------------------------------------------------- */
4079
/* -------------------------------------------------------------------------- */
4080

    
4081
int VirtualMachine::get_public_cloud_hypervisors(vector<string> &public_cloud_hypervisors) const
4082
{
4083
    vector<Attribute*>                  attrs;
4084
    vector<Attribute*>::const_iterator  it;
4085

    
4086
    VectorAttribute *   vatt;
4087

    
4088
    user_obj_template->get("PUBLIC_CLOUD", attrs);
4089

    
4090
    for (it = attrs.begin(); it != attrs.end(); it++)
4091
    {
4092
        vatt = dynamic_cast<VectorAttribute * >(*it);
4093

    
4094
        if ( vatt == 0 )
4095
        {
4096
            continue;
4097
        }
4098

    
4099
        string type = vatt->vector_value("TYPE");
4100

    
4101
        if (!type.empty())
4102
        {
4103
            public_cloud_hypervisors.push_back(type);
4104
        }
4105
    }
4106

    
4107
    // Compatibility with old templates
4108

    
4109
    attrs.clear();
4110
    user_obj_template->get("EC2", attrs);
4111

    
4112
    if (!attrs.empty())
4113
    {
4114
        public_cloud_hypervisors.push_back("ec2");
4115
    }
4116

    
4117
    return public_cloud_hypervisors.size();
4118
}