Statistics
| Branch: | Tag: | Revision:

one / src / vm / VirtualMachine.cc @ 5f28a7bf

History | View | Annotate | Download (78.2 KB)

1
/* -------------------------------------------------------------------------- */
2
/* Copyright 2002-2017, OpenNebula Project, OpenNebula Systems                */
3
/*                                                                            */
4
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
5
/* not use this file except in compliance with the License. You may obtain    */
6
/* a copy of the License at                                                   */
7
/*                                                                            */
8
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
9
/*                                                                            */
10
/* Unless required by applicable law or agreed to in writing, software        */
11
/* distributed under the License is distributed on an "AS IS" BASIS,          */
12
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
13
/* See the License for the specific language governing permissions and        */
14
/* limitations under the License.                                             */
15
/* -------------------------------------------------------------------------- */
16
#include <limits.h>
17
#include <string.h>
18
#include <time.h>
19
#include <sys/stat.h>
20
#include <sys/types.h>
21
#include <regex.h>
22
#include <unistd.h>
23

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

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

    
35
#include "Nebula.h"
36

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

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

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

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

    
79
    obj_template = new VirtualMachineTemplate;
80

    
81
    set_umask(umask);
82
}
83

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

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

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

    
99
int VirtualMachine::vm_state_from_str(string& st, VmState& state)
100
{
101
    one_util::toupper(st);
102

    
103
    if ( st == "INIT" ) {
104
        state = INIT;
105
    } else if ( st == "PENDING" ) {
106
                state = PENDING;
107
    } else if ( st == "HOLD" ) {
108
                state = HOLD;
109
    } else if ( st == "ACTIVE" ) {
110
                state = ACTIVE;
111
    } else if ( st == "STOPPED" ) {
112
                state = STOPPED;
113
    } else if ( st == "SUSPENDED" ) {
114
                state = SUSPENDED;
115
    } else if ( st == "DONE" ) {
116
                state = DONE;
117
    } else if ( st == "POWEROFF" ) {
118
                state = POWEROFF;
119
    } else if ( st == "UNDEPLOYED" ) {
120
                state = UNDEPLOYED;
121
    } else if ( st == "CLONING" ) {
122
                state = CLONING;
123
    } else if ( st == "CLONING_FAILURE" ) {
124
                state = CLONING_FAILURE;
125
    } else {
126
        return -1;
127
    }
128

    
129
    return 0;
130
}
131

    
132
/* -------------------------------------------------------------------------- */
133

    
134
string& VirtualMachine::vm_state_to_str(string& st, VmState state)
135
{
136
    switch (state)
137
    {
138
        case INIT:
139
                        st = "INIT"; break;
140
        case PENDING:
141
                        st = "PENDING"; break;
142
        case HOLD:
143
                        st = "HOLD"; break;
144
        case ACTIVE:
145
                        st = "ACTIVE"; break;
146
        case STOPPED:
147
                        st = "STOPPED"; break;
148
        case SUSPENDED:
149
                        st = "SUSPENDED"; break;
150
        case DONE:
151
                        st = "DONE"; break;
152
        case POWEROFF:
153
                        st = "POWEROFF"; break;
154
        case UNDEPLOYED:
155
                        st = "UNDEPLOYED"; break;
156
        case CLONING:
157
                        st = "CLONING"; break;
158
        case CLONING_FAILURE:
159
                        st = "CLONING_FAILURE"; break;
160
    }
161

    
162
    return st;
163
}
164

    
165
/* -------------------------------------------------------------------------- */
166
/* -------------------------------------------------------------------------- */
167

    
168
int VirtualMachine::lcm_state_from_str(string& st, LcmState& state)
169
{
170
    one_util::toupper(st);
171

    
172
    if ( st == "LCM_INIT" ){
173
        state = LCM_INIT;
174
    } else if ( st == "PROLOG") {
175
        state = PROLOG;
176
    } else if ( st == "BOOT") {
177
        state = BOOT;
178
    } else if ( st == "RUNNING") {
179
        state = RUNNING;
180
    } else if ( st == "MIGRATE") {
181
        state = MIGRATE;
182
    } else if ( st == "SAVE_STOP") {
183
                state = SAVE_STOP;
184
    } else if ( st == "SAVE_SUSPEND") {
185
                state = SAVE_SUSPEND;
186
    } else if ( st == "SAVE_MIGRATE") {
187
                state = SAVE_MIGRATE;
188
    } else if ( st == "PROLOG_MIGRATE") {
189
                state = PROLOG_MIGRATE;
190
    } else if ( st == "PROLOG_RESUME") {
191
                state = PROLOG_RESUME;
192
    } else if ( st == "EPILOG_STOP") {
193
                state = EPILOG_STOP;
194
    } else if ( st == "EPILOG") {
195
                state = EPILOG;
196
    } else if ( st == "SHUTDOWN") {
197
                state = SHUTDOWN;
198
    } else if ( st == "CLEANUP_RESUBMIT") {
199
                state = CLEANUP_RESUBMIT;
200
    } else if ( st == "UNKNOWN") {
201
                state = UNKNOWN;
202
    } else if ( st == "HOTPLUG") {
203
                state = HOTPLUG;
204
    } else if ( st == "SHUTDOWN_POWEROFF") {
205
                state = SHUTDOWN_POWEROFF;
206
    } else if ( st == "BOOT_UNKNOWN") {
207
                state = BOOT_UNKNOWN;
208
    } else if ( st == "BOOT_POWEROFF") {
209
                state = BOOT_POWEROFF;
210
    } else if ( st == "BOOT_SUSPENDED") {
211
                state = BOOT_SUSPENDED;
212
    } else if ( st == "BOOT_STOPPED") {
213
                state = BOOT_STOPPED;
214
    } else if ( st == "CLEANUP_DELETE") {
215
                state = CLEANUP_DELETE;
216
    } else if ( st == "HOTPLUG_SNAPSHOT") {
217
                state = HOTPLUG_SNAPSHOT;
218
    } else if ( st == "HOTPLUG_NIC") {
219
                state = HOTPLUG_NIC;
220
    } else if ( st == "HOTPLUG_SAVEAS") {
221
                state = HOTPLUG_SAVEAS;
222
    } else if ( st == "HOTPLUG_SAVEAS_POWEROFF") {
223
                state = HOTPLUG_SAVEAS_POWEROFF;
224
    } else if ( st == "HOTPLUG_SAVEAS_SUSPENDED") {
225
                state = HOTPLUG_SAVEAS_SUSPENDED;
226
    } else if ( st == "SHUTDOWN_UNDEPLOY") {
227
                state = SHUTDOWN_UNDEPLOY;
228
    } else if ( st == "EPILOG_UNDEPLOY") {
229
                state = EPILOG_UNDEPLOY;
230
    } else if ( st == "PROLOG_UNDEPLOY") {
231
                state = PROLOG_UNDEPLOY;
232
    } else if ( st == "BOOT_UNDEPLOY") {
233
                state = BOOT_UNDEPLOY;
234
    } else if ( st == "HOTPLUG_PROLOG_POWEROFF") {
235
                state = HOTPLUG_PROLOG_POWEROFF;
236
    } else if ( st == "HOTPLUG_EPILOG_POWEROFF") {
237
                state = HOTPLUG_EPILOG_POWEROFF;
238
    } else if ( st == "BOOT_MIGRATE") {
239
                state = BOOT_MIGRATE;
240
    } else if ( st == "BOOT_FAILURE") {
241
                state = BOOT_FAILURE;
242
    } else if ( st == "BOOT_MIGRATE_FAILURE") {
243
                state = BOOT_MIGRATE_FAILURE;
244
    } else if ( st == "PROLOG_MIGRATE_FAILURE") {
245
                state = PROLOG_MIGRATE_FAILURE;
246
    } else if ( st == "PROLOG_FAILURE") {
247
                state = PROLOG_FAILURE;
248
    } else if ( st == "EPILOG_FAILURE") {
249
                state = EPILOG_FAILURE;
250
    } else if ( st == "EPILOG_STOP_FAILURE") {
251
                state = EPILOG_STOP_FAILURE;
252
    } else if ( st == "EPILOG_UNDEPLOY_FAILURE") {
253
                state = EPILOG_UNDEPLOY_FAILURE;
254
    } else if ( st == "PROLOG_MIGRATE_POWEROFF") {
255
                state = PROLOG_MIGRATE_POWEROFF;
256
    } else if ( st == "PROLOG_MIGRATE_POWEROFF_FAILURE") {
257
                state = PROLOG_MIGRATE_POWEROFF_FAILURE;
258
    } else if ( st == "PROLOG_MIGRATE_SUSPEND") {
259
                state = PROLOG_MIGRATE_SUSPEND;
260
    } else if ( st == "PROLOG_MIGRATE_SUSPEND_FAILURE") {
261
                state = PROLOG_MIGRATE_SUSPEND_FAILURE;
262
    } else if ( st == "BOOT_STOPPED_FAILURE") {
263
                state = BOOT_STOPPED_FAILURE;
264
    } else if ( st == "BOOT_UNDEPLOY_FAILURE") {
265
                state = BOOT_UNDEPLOY_FAILURE;
266
    } else if ( st == "PROLOG_RESUME_FAILURE") {
267
                state = PROLOG_RESUME_FAILURE;
268
    } else if ( st == "PROLOG_UNDEPLOY_FAILURE") {
269
                state = PROLOG_UNDEPLOY_FAILURE;
270
    } else if ( st == "DISK_SNAPSHOT_POWEROFF") {
271
                state = DISK_SNAPSHOT_POWEROFF;
272
    } else if ( st == "DISK_SNAPSHOT_REVERT_POWEROFF") {
273
                state = DISK_SNAPSHOT_REVERT_POWEROFF;
274
    } else if ( st == "DISK_SNAPSHOT_DELETE_POWEROFF") {
275
                state = DISK_SNAPSHOT_DELETE_POWEROFF;
276
    } else if ( st == "DISK_SNAPSHOT_SUSPENDED") {
277
                state = DISK_SNAPSHOT_SUSPENDED;
278
    } else if ( st == "DISK_SNAPSHOT_REVERT_SUSPENDED") {
279
                state = DISK_SNAPSHOT_REVERT_SUSPENDED;
280
    } else if ( st == "DISK_SNAPSHOT_DELETE_SUSPENDED") {
281
                state = DISK_SNAPSHOT_DELETE_SUSPENDED;
282
    } else if ( st == "DISK_SNAPSHOT") {
283
                state = DISK_SNAPSHOT;
284
    } else if ( st == "DISK_SNAPSHOT_DELETE") {
285
                state = DISK_SNAPSHOT_DELETE;
286
    } else if ( st == "PROLOG_MIGRATE_UNKNOWN") {
287
                state = PROLOG_MIGRATE_UNKNOWN;
288
    } else if ( st == "PROLOG_MIGRATE_UNKNOWN_FAILURE") {
289
                state = PROLOG_MIGRATE_UNKNOWN_FAILURE;
290
    } else if ( st == "DISK_RESIZE") {
291
                state = DISK_RESIZE;
292
    } else if ( st == "DISK_RESIZE_POWEROFF") {
293
                state = DISK_RESIZE_POWEROFF;
294
    } else if ( st == "DISK_RESIZE_UNDEPLOYED") {
295
                state = DISK_RESIZE_UNDEPLOYED;
296
    } else {
297
        return -1;
298
    }
299

    
300
    return 0;
301
}
302

    
303
/* -------------------------------------------------------------------------- */
304

    
305
string& VirtualMachine::lcm_state_to_str(string& st, LcmState state)
306
{
307
    switch (state)
308
    {
309
        case LCM_INIT:
310
            st = "LCM_INIT"; break;
311
        case PROLOG:
312
            st = "PROLOG"; break;
313
        case BOOT:
314
            st = "BOOT"; break;
315
        case RUNNING:
316
            st = "RUNNING"; break;
317
        case MIGRATE:
318
                        st = "MIGRATE"; break;
319
        case SAVE_STOP:
320
                        st = "SAVE_STOP"; break;
321
        case SAVE_SUSPEND:
322
                        st = "SAVE_SUSPEND"; break;
323
        case SAVE_MIGRATE:
324
                        st = "SAVE_MIGRATE"; break;
325
        case PROLOG_MIGRATE:
326
                        st = "PROLOG_MIGRATE"; break;
327
        case PROLOG_RESUME:
328
                        st = "PROLOG_RESUME"; break;
329
        case EPILOG_STOP:
330
                        st = "EPILOG_STOP"; break;
331
        case EPILOG:
332
                        st = "EPILOG"; break;
333
        case SHUTDOWN:
334
                        st = "SHUTDOWN"; break;
335
        case CLEANUP_RESUBMIT:
336
                        st = "CLEANUP_RESUBMIT"; break;
337
        case UNKNOWN:
338
                        st = "UNKNOWN"; break;
339
        case HOTPLUG:
340
                        st = "HOTPLUG"; break;
341
        case SHUTDOWN_POWEROFF:
342
                        st = "SHUTDOWN_POWEROFF"; break;
343
        case BOOT_UNKNOWN:
344
                        st = "BOOT_UNKNOWN"; break;
345
        case BOOT_POWEROFF:
346
                        st = "BOOT_POWEROFF"; break;
347
        case BOOT_SUSPENDED:
348
                        st = "BOOT_SUSPENDED"; break;
349
        case BOOT_STOPPED:
350
                        st = "BOOT_STOPPED"; break;
351
        case CLEANUP_DELETE:
352
                        st = "CLEANUP_DELETE"; break;
353
        case HOTPLUG_SNAPSHOT:
354
                        st = "HOTPLUG_SNAPSHOT"; break;
355
        case HOTPLUG_NIC:
356
                        st = "HOTPLUG_NIC"; break;
357
        case HOTPLUG_SAVEAS:
358
                        st = "HOTPLUG_SAVEAS"; break;
359
        case HOTPLUG_SAVEAS_POWEROFF:
360
                        st = "HOTPLUG_SAVEAS_POWEROFF"; break;
361
        case HOTPLUG_SAVEAS_SUSPENDED:
362
                        st = "HOTPLUG_SAVEAS_SUSPENDED"; break;
363
        case SHUTDOWN_UNDEPLOY:
364
                        st = "SHUTDOWN_UNDEPLOY"; break;
365
        case EPILOG_UNDEPLOY:
366
                        st = "EPILOG_UNDEPLOY"; break;
367
        case PROLOG_UNDEPLOY:
368
                        st = "PROLOG_UNDEPLOY"; break;
369
        case BOOT_UNDEPLOY:
370
                        st = "BOOT_UNDEPLOY"; break;
371
        case HOTPLUG_PROLOG_POWEROFF:
372
                        st = "HOTPLUG_PROLOG_POWEROFF"; break;
373
        case HOTPLUG_EPILOG_POWEROFF:
374
                        st = "HOTPLUG_EPILOG_POWEROFF"; break;
375
        case BOOT_MIGRATE:
376
                        st = "BOOT_MIGRATE"; break;
377
        case BOOT_FAILURE:
378
                        st = "BOOT_FAILURE"; break;
379
        case BOOT_MIGRATE_FAILURE:
380
                        st = "BOOT_MIGRATE_FAILURE"; break;
381
        case PROLOG_MIGRATE_FAILURE:
382
                        st = "PROLOG_MIGRATE_FAILURE"; break;
383
        case PROLOG_FAILURE:
384
                        st = "PROLOG_FAILURE"; break;
385
        case EPILOG_FAILURE:
386
                        st = "EPILOG_FAILURE"; break;
387
        case EPILOG_STOP_FAILURE:
388
                        st = "EPILOG_STOP_FAILURE"; break;
389
        case EPILOG_UNDEPLOY_FAILURE:
390
                        st = "EPILOG_UNDEPLOY_FAILURE"; break;
391
        case PROLOG_MIGRATE_POWEROFF:
392
                        st = "PROLOG_MIGRATE_POWEROFF"; break;
393
        case PROLOG_MIGRATE_POWEROFF_FAILURE:
394
                        st = "PROLOG_MIGRATE_POWEROFF_FAILURE"; break;
395
        case PROLOG_MIGRATE_SUSPEND:
396
                        st = "PROLOG_MIGRATE_SUSPEND"; break;
397
        case PROLOG_MIGRATE_SUSPEND_FAILURE:
398
                        st = "PROLOG_MIGRATE_SUSPEND_FAILURE"; break;
399
        case BOOT_STOPPED_FAILURE:
400
                        st = "BOOT_STOPPED_FAILURE"; break;
401
        case BOOT_UNDEPLOY_FAILURE:
402
                        st = "BOOT_UNDEPLOY_FAILURE"; break;
403
        case PROLOG_RESUME_FAILURE:
404
                        st = "PROLOG_RESUME_FAILURE"; break;
405
        case PROLOG_UNDEPLOY_FAILURE:
406
                        st = "PROLOG_UNDEPLOY_FAILURE"; break;
407
        case DISK_SNAPSHOT_POWEROFF:
408
                        st = "DISK_SNAPSHOT_POWEROFF"; break;
409
        case DISK_SNAPSHOT_REVERT_POWEROFF:
410
                        st = "DISK_SNAPSHOT_REVERT_POWEROFF"; break;
411
        case DISK_SNAPSHOT_DELETE_POWEROFF:
412
                        st = "DISK_SNAPSHOT_DELETE_POWEROFF"; break;
413
        case DISK_SNAPSHOT_SUSPENDED:
414
                        st = "DISK_SNAPSHOT_SUSPENDED"; break;
415
        case DISK_SNAPSHOT_REVERT_SUSPENDED:
416
                        st = "DISK_SNAPSHOT_REVERT_SUSPENDED"; break;
417
        case DISK_SNAPSHOT_DELETE_SUSPENDED:
418
                        st = "DISK_SNAPSHOT_DELETE_SUSPENDED"; break;
419
        case DISK_SNAPSHOT:
420
                        st = "DISK_SNAPSHOT"; break;
421
        case DISK_SNAPSHOT_DELETE:
422
                        st = "DISK_SNAPSHOT_DELETE"; break;
423
        case PROLOG_MIGRATE_UNKNOWN:
424
                        st = "PROLOG_MIGRATE_UNKNOWN"; break;
425
        case PROLOG_MIGRATE_UNKNOWN_FAILURE:
426
                        st = "PROLOG_MIGRATE_UNKNOWN_FAILURE"; break;
427
        case DISK_RESIZE:
428
                        st = "DISK_RESIZE"; break;
429
        case DISK_RESIZE_POWEROFF:
430
                        st = "DISK_RESIZE_POWEROFF"; break;
431
        case DISK_RESIZE_UNDEPLOYED:
432
                        st = "DISK_RESIZE_UNDEPLOYED"; break;
433
    }
434

    
435
    return st;
436
}
437

    
438
/* -------------------------------------------------------------------------- */
439

    
440
string VirtualMachine::state_str()
441
{
442
    string st;
443

    
444
    if (state == ACTIVE)
445
    {
446
        return lcm_state_to_str(st, lcm_state);
447
    }
448

    
449
    return vm_state_to_str(st, state);
450
}
451

    
452
/* ************************************************************************** */
453
/* Virtual Machine :: Database Access Functions                               */
454
/* ************************************************************************** */
455

    
456
const char * VirtualMachine::table = "vm_pool";
457

    
458
const char * VirtualMachine::db_names =
459
    "oid, name, body, uid, gid, last_poll, state, lcm_state, "
460
    "owner_u, group_u, other_u";
461

    
462
const char * VirtualMachine::db_bootstrap = "CREATE TABLE IF NOT EXISTS "
463
    "vm_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, "
464
    "gid INTEGER, last_poll INTEGER, state INTEGER, lcm_state INTEGER, "
465
    "owner_u INTEGER, group_u INTEGER, other_u INTEGER)";
466

    
467

    
468
const char * VirtualMachine::monit_table = "vm_monitoring";
469

    
470
const char * VirtualMachine::monit_db_names = "vmid, last_poll, body";
471

    
472
const char * VirtualMachine::monit_db_bootstrap = "CREATE TABLE IF NOT EXISTS "
473
    "vm_monitoring (vmid INTEGER, last_poll INTEGER, body MEDIUMTEXT, "
474
    "PRIMARY KEY(vmid, last_poll))";
475

    
476

    
477
const char * VirtualMachine::showback_table = "vm_showback";
478

    
479
const char * VirtualMachine::showback_db_names = "vmid, year, month, body";
480

    
481
const char * VirtualMachine::showback_db_bootstrap =
482
    "CREATE TABLE IF NOT EXISTS vm_showback "
483
    "(vmid INTEGER, year INTEGER, month INTEGER, body MEDIUMTEXT, "
484
    "PRIMARY KEY(vmid, year, month))";
485

    
486
/* -------------------------------------------------------------------------- */
487
/* -------------------------------------------------------------------------- */
488

    
489
int VirtualMachine::select(SqlDB * db)
490
{
491
    ostringstream   oss;
492
    ostringstream   ose;
493

    
494
    string system_dir;
495
    int    rc;
496
    int    last_seq;
497

    
498
    Nebula& nd = Nebula::instance();
499

    
500
    // Rebuild the VirtualMachine object
501
    rc = PoolObjectSQL::select(db);
502

    
503
    if( rc != 0 )
504
    {
505
        return rc;
506
    }
507

    
508
    //Get History Records. 
509
    if( hasHistory() )
510
    {
511
        last_seq = history->seq;
512

    
513
        delete history_records[last_seq];
514

    
515
        for (int i = last_seq; i >= 0; i--)
516
        {
517
            History * hp;
518

    
519
            hp = new History(oid, i);
520
            rc = hp->select(db);
521

    
522
            if ( rc != 0)
523
            {
524
                goto error_previous_history;
525
            }
526

    
527
            history_records[i] = hp;
528

    
529
            if ( i == last_seq )
530
            {
531
                history = hp;
532
            }
533
            else if ( i == last_seq - 1 )
534
            {
535
                previous_history = hp;
536
            }
537
        }
538
    }
539

    
540
    if ( state == DONE ) //Do not recreate dirs. They may be deleted
541
    {
542
        _log = 0;
543

    
544
        return 0;
545
    }
546

    
547
    //--------------------------------------------------------------------------
548
    //Create support directories for this VM
549
    //--------------------------------------------------------------------------
550
    oss.str("");
551
    oss << nd.get_vms_location() << oid;
552

    
553
    mkdir(oss.str().c_str(), 0700);
554
    chmod(oss.str().c_str(), 0700);
555

    
556
    //--------------------------------------------------------------------------
557
    //Create Log support for this VM
558
    //--------------------------------------------------------------------------
559
    try
560
    {
561
        Log::MessageType   clevel;
562
        NebulaLog::LogType log_system;
563

    
564
        log_system  = nd.get_log_system();
565
        clevel      = nd.get_debug_level();
566

    
567
        switch(log_system)
568
        {
569
            case NebulaLog::FILE_TS:
570
            case NebulaLog::FILE:
571
                _log = new FileLog(nd.get_vm_log_filename(oid), clevel);
572
                break;
573

    
574
            case NebulaLog::SYSLOG:
575
                _log = new SysLog(clevel, oid, obj_type);
576
                break;
577

    
578
            case NebulaLog::STD:
579
                _log = new StdLog(clevel, oid, obj_type);
580
                break;
581

    
582
            default:
583
                throw runtime_error("Unknown log system.");
584
                break;
585
        }
586
    }
587
    catch(exception &e)
588
    {
589
        ose << "Error creating log: " << e.what();
590
        NebulaLog::log("ONE",Log::ERROR, ose);
591

    
592
        _log = 0;
593
    }
594

    
595
    return 0;
596

    
597
error_previous_history:
598
    ose << "Cannot get previous history record (seq:" << history->seq
599
        << ") for VM id: " << oid;
600

    
601
    log("ONE", Log::ERROR, ose);
602
    return -1;
603
}
604

    
605
/* -------------------------------------------------------------------------- */
606
/* -------------------------------------------------------------------------- */
607

    
608
static int set_boot_order(Template * tmpl, string& error_str)
609
{
610
    vector<VectorAttribute *> disk;
611
    vector<VectorAttribute *> nic;
612

    
613
    ostringstream oss;
614

    
615
    int ndisk = tmpl->get("DISK", disk);
616
    int nnic  = tmpl->get("NIC", nic);
617

    
618
    for (int i=0; i<ndisk; ++i)
619
    {
620
        disk[i]->remove("ORDER");
621
    }
622

    
623
    for (int i=0; i<nnic; ++i)
624
    {
625
        nic[i]->remove("ORDER");
626
    }
627

    
628
    VectorAttribute * os = tmpl->get("OS");
629

    
630
    if ( os == 0 )
631
    {
632
        return 0;
633
    }
634

    
635
    string order = os->vector_value("BOOT");
636

    
637
    if ( order.empty() )
638
    {
639
        return 0;
640
    }
641

    
642
    vector<string> bdevs = one_util::split(order, ',');
643

    
644
    int index = 1;
645

    
646
    for (vector<string>::iterator i = bdevs.begin(); i != bdevs.end(); ++i)
647
    {
648
        vector<VectorAttribute *> * dev;
649
        int    max;
650
        int    disk_id;
651
        size_t pos;
652

    
653
        const char * id_name;
654

    
655
        one_util::toupper(*i);
656

    
657
        int rc = one_util::regex_match("^(DISK|NIC)[[:digit:]]+$", (*i).c_str());
658

    
659
        if (rc != 0)
660
        {
661
            goto error_parsing;
662
        }
663

    
664
        if ((*i).compare(0,4,"DISK") == 0)
665
        {
666
            pos = 4;
667

    
668
            max = ndisk;
669
            dev = &disk;
670

    
671
            id_name = "DISK_ID";
672
        }
673
        else if ((*i).compare(0,3,"NIC") == 0)
674
        {
675
            pos = 3;
676

    
677
            max = nnic;
678
            dev = &nic;
679

    
680
            id_name = "NIC_ID";
681
        }
682
        else
683
        {
684
            goto error_parsing;
685
        }
686

    
687
        istringstream iss((*i).substr(pos, string::npos));
688

    
689
        iss >> disk_id;
690

    
691
        if (iss.fail())
692
        {
693
            goto error_parsing;
694
        }
695

    
696
        bool found = false;
697

    
698
        for (int j=0; j<max; ++j)
699
        {
700
            int j_disk_id;
701

    
702
            if ( (*dev)[j]->vector_value(id_name, j_disk_id) == 0 &&
703
                   j_disk_id == disk_id )
704
            {
705
                (*dev)[j]->replace("ORDER", index++);
706
                found = true;
707
            }
708
        }
709

    
710
        if (!found)
711
        {
712
            oss << "Wrong OS/BOOT value. Device with "
713
                << id_name << " " << disk_id << " not found";
714

    
715
            goto error_common;
716
        }
717
    }
718

    
719
    return 0;
720

    
721
error_parsing:
722
    oss << "Wrong OS/BOOT value: \"" << order
723
        << "\" should be a comma-separated list of disk# or nic#";
724

    
725
error_common:
726
    error_str = oss.str();
727
    return -1;
728
}
729

    
730
/* -------------------------------------------------------------------------- */
731
/* -------------------------------------------------------------------------- */
732

    
733
int VirtualMachine::insert(SqlDB * db, string& error_str)
734
{
735
    int    rc;
736
    string name;
737
    string prefix;
738

    
739
    string value;
740
    int    ivalue;
741
    float  fvalue;
742
    set<int> cluster_ids;
743
    vector<Template *> quotas;
744

    
745
    ostringstream oss;
746

    
747
    // ------------------------------------------------------------------------
748
    // Set a name if the VM has not got one and VM_ID
749
    // ------------------------------------------------------------------------
750
    user_obj_template->erase("VMID");
751
    obj_template->add("VMID", oid);
752

    
753
    user_obj_template->get("TEMPLATE_ID", value);
754
    user_obj_template->erase("TEMPLATE_ID");
755

    
756
    if (!value.empty())
757
    {
758
        obj_template->add("TEMPLATE_ID", value);
759
    }
760

    
761
    user_obj_template->get("NAME",name);
762
    user_obj_template->erase("NAME");
763

    
764
    user_obj_template->get("TEMPLATE_NAME", prefix);
765
    user_obj_template->erase("TEMPLATE_NAME");
766

    
767
    if (prefix.empty())
768
    {
769
        prefix = "one";
770
    }
771

    
772
    if (name.empty() == true)
773
    {
774
        oss.str("");
775
        oss << prefix << "-" << oid;
776
        name = oss.str();
777
    }
778

    
779
    if ( !PoolObjectSQL::name_is_valid(name, error_str) )
780
    {
781
        goto error_name;
782
    }
783

    
784
    this->name = name;
785

    
786
    // ------------------------------------------------------------------------
787
    // Parse the Public Cloud specs for this VM
788
    // ------------------------------------------------------------------------
789

    
790
    if (parse_public_clouds(error_str) != 0)
791
    {
792
        goto error_public;
793
    }
794

    
795
    // ------------------------------------------------------------------------
796
    // Check for EMULATOR attribute
797
    // ------------------------------------------------------------------------
798

    
799
    user_obj_template->get("EMULATOR", value);
800

    
801
    if (!value.empty())
802
    {
803
        user_obj_template->erase("EMULATOR");
804
        obj_template->add("EMULATOR", value);
805
    }
806

    
807
    // ------------------------------------------------------------------------
808
    // Check for CPU, VCPU and MEMORY attributes
809
    // ------------------------------------------------------------------------
810

    
811
    if ( user_obj_template->get("MEMORY", ivalue) == false || (ivalue * 1024) <= 0 )
812
    {
813
        goto error_memory;
814
    }
815

    
816
    user_obj_template->erase("MEMORY");
817
    obj_template->add("MEMORY", ivalue);
818

    
819
    if ( user_obj_template->get("CPU", fvalue) == false || fvalue <= 0 )
820
    {
821
        goto error_cpu;
822
    }
823

    
824
    user_obj_template->erase("CPU");
825
    obj_template->add("CPU", fvalue);
826

    
827
    // VCPU is optional, first check if the attribute exists, then check it is
828
    // an integer
829
    user_obj_template->get("VCPU", value);
830

    
831
    if ( value.empty() == false )
832
    {
833
        if ( user_obj_template->get("VCPU", ivalue) == false || ivalue <= 0 )
834
        {
835
            goto error_vcpu;
836
        }
837

    
838
        user_obj_template->erase("VCPU");
839
        obj_template->add("VCPU", ivalue);
840
    }
841

    
842
    // ------------------------------------------------------------------------
843
    // Check the cost attributes
844
    // ------------------------------------------------------------------------
845

    
846
    if ( user_obj_template->get("CPU_COST", fvalue) == true )
847
    {
848
        if ( fvalue < 0 )
849
        {
850
            goto error_cpu_cost;
851
        }
852

    
853
        user_obj_template->erase("CPU_COST");
854
        obj_template->add("CPU_COST", fvalue);
855
    }
856

    
857
    if ( user_obj_template->get("MEMORY_COST", fvalue) == true )
858
    {
859
        if ( fvalue < 0 )
860
        {
861
            goto error_memory_cost;
862
        }
863

    
864
        user_obj_template->erase("MEMORY_COST");
865
        obj_template->add("MEMORY_COST", fvalue);
866
    }
867

    
868
    if ( user_obj_template->get("DISK_COST", fvalue) == true )
869
    {
870
        if ( fvalue < 0 )
871
        {
872
            goto error_disk_cost;
873
        }
874

    
875
        user_obj_template->erase("DISK_COST");
876
        obj_template->add("DISK_COST", fvalue);
877
    }
878

    
879
    // ------------------------------------------------------------------------
880
    // Check the OS attribute
881
    // ------------------------------------------------------------------------
882

    
883
    rc = parse_os(error_str);
884

    
885
    if ( rc != 0 )
886
    {
887
        goto error_os;
888
    }
889

    
890
    // ------------------------------------------------------------------------
891
    // PCI Devices (Needs to be parsed before network)
892
    // ------------------------------------------------------------------------
893

    
894
    rc = parse_pci(error_str);
895

    
896
    if ( rc != 0 )
897
    {
898
        goto error_pci;
899
    }
900

    
901
    // ------------------------------------------------------------------------
902
    // Parse the defaults to merge
903
    // ------------------------------------------------------------------------
904

    
905
    rc = parse_defaults(error_str);
906

    
907
    if ( rc != 0 )
908
    {
909
        goto error_defaults;
910
    }
911

    
912
    // ------------------------------------------------------------------------
913
    // Parse the virtual router attributes
914
    // ------------------------------------------------------------------------
915

    
916
    rc = parse_vrouter(error_str);
917

    
918
    if ( rc != 0 )
919
    {
920
        goto error_vrouter;
921
    }
922

    
923
    // ------------------------------------------------------------------------
924
    // Get network leases
925
    // ------------------------------------------------------------------------
926

    
927
    rc = get_network_leases(error_str);
928

    
929
    if ( rc != 0 )
930
    {
931
        goto error_leases_rollback;
932
    }
933

    
934
    // ------------------------------------------------------------------------
935
    // Get disk images
936
    // ------------------------------------------------------------------------
937

    
938
    rc = get_disk_images(error_str);
939

    
940
    if ( rc != 0 )
941
    {
942
        // The get_disk_images method has an internal rollback for
943
        // the acquired images, release_disk_images() would release all disks
944
        goto error_leases_rollback;
945
    }
946

    
947
    bool on_hold;
948

    
949
    if (user_obj_template->get("SUBMIT_ON_HOLD", on_hold) == true)
950
    {
951
        user_obj_template->erase("SUBMIT_ON_HOLD");
952

    
953
        obj_template->replace("SUBMIT_ON_HOLD", on_hold);
954
    }
955

    
956
    if ( has_cloning_disks())
957
    {
958
        state = VirtualMachine::CLONING;
959
    }
960

    
961
    // -------------------------------------------------------------------------
962
    // Set boot order
963
    // -------------------------------------------------------------------------
964

    
965
    rc = set_boot_order(obj_template, error_str);
966

    
967
    if ( rc != 0 )
968
    {
969
        goto error_boot_order;
970
    }
971

    
972
    // -------------------------------------------------------------------------
973
    // Parse the context & requirements
974
    // -------------------------------------------------------------------------
975

    
976
    rc = parse_context(error_str);
977

    
978
    if ( rc != 0 )
979
    {
980
        goto error_context;
981
    }
982

    
983
    rc = parse_requirements(error_str);
984

    
985
    if ( rc != 0 )
986
    {
987
        goto error_requirements;
988
    }
989

    
990
    rc = automatic_requirements(cluster_ids, error_str);
991

    
992
    if ( rc != 0 )
993
    {
994
        goto error_requirements;
995
    }
996

    
997
    if ( parse_graphics(error_str) != 0 )
998
    {
999
        goto error_graphics;
1000
    }
1001

    
1002
    // -------------------------------------------------------------------------
1003
    // Get and set DEPLOY_ID for imported VMs
1004
    // -------------------------------------------------------------------------
1005

    
1006
    user_obj_template->get("IMPORT_VM_ID", value);
1007
    user_obj_template->erase("IMPORT_VM_ID");
1008

    
1009
    if (!value.empty())
1010
    {
1011
        const char * one_vms = "^one-[[:digit:]]+$";
1012

    
1013
        if (one_util::regex_match(one_vms, value.c_str()) == 0)
1014
        {
1015
            goto error_one_vms;
1016
        }
1017
        else
1018
        {
1019
            deploy_id = value;
1020
            obj_template->add("IMPORTED", "YES");
1021
        }
1022
    }
1023

    
1024
    // ------------------------------------------------------------------------
1025
    // Associate to VM Group
1026
    // ------------------------------------------------------------------------
1027
    if ( get_vmgroup(error_str) == -1 )
1028
    {
1029
        goto error_rollback;
1030
    }
1031

    
1032
    // ------------------------------------------------------------------------
1033

    
1034
    parse_well_known_attributes();
1035

    
1036
    // ------------------------------------------------------------------------
1037
    // Insert the VM
1038
    // ------------------------------------------------------------------------
1039

    
1040
    rc = insert_replace(db, false, error_str);
1041

    
1042
    if ( rc != 0 )
1043
    {
1044
        goto error_update;
1045
    }
1046

    
1047
    return 0;
1048

    
1049
error_update:
1050
    goto error_rollback;
1051

    
1052
error_boot_order:
1053
    goto error_rollback;
1054

    
1055
error_context:
1056
    goto error_rollback;
1057

    
1058
error_requirements:
1059
    goto error_rollback;
1060

    
1061
error_graphics:
1062
    goto error_rollback;
1063

    
1064
error_rollback:
1065
    release_disk_images(quotas);
1066

    
1067
error_leases_rollback:
1068
    release_network_leases();
1069
    goto error_common;
1070

    
1071
error_cpu:
1072
    error_str = "CPU attribute must be a positive float or integer value.";
1073
    goto error_common;
1074

    
1075
error_vcpu:
1076
    error_str = "VCPU attribute must be a positive integer value.";
1077
    goto error_common;
1078

    
1079
error_memory:
1080
    error_str = "MEMORY attribute must be a positive integer value.";
1081
    goto error_common;
1082

    
1083
error_cpu_cost:
1084
    error_str = "CPU_COST attribute must be a positive float or integer value.";
1085
    goto error_common;
1086

    
1087
error_memory_cost:
1088
    error_str = "MEMORY_COST attribute must be a positive float or integer value.";
1089
    goto error_common;
1090

    
1091
error_disk_cost:
1092
    error_str = "DISK_COST attribute must be a positive float or integer value.";
1093
    goto error_common;
1094

    
1095
error_one_vms:
1096
    error_str = "Trying to import an OpenNebula VM: 'one-*'.";
1097
    goto error_common;
1098

    
1099
error_os:
1100
error_pci:
1101
error_defaults:
1102
error_vrouter:
1103
error_public:
1104
error_name:
1105
error_common:
1106
    NebulaLog::log("ONE",Log::ERROR, error_str);
1107

    
1108
    return -1;
1109
}
1110

    
1111
/* ------------------------------------------------------------------------ */
1112
/* ------------------------------------------------------------------------ */
1113

    
1114
/**
1115
 * @return -1 for incompatible cluster IDs, -2 for missing cluster IDs
1116
 */
1117
static int check_and_set_cluster_id(
1118
        const char *           id_name,
1119
        const VectorAttribute* vatt,
1120
        set<int>               &cluster_ids)
1121
{
1122
    set<int> vatt_cluster_ids;
1123
    string   val;
1124

    
1125
    // If the attr does not exist, the vatt is using a manual path/resource.
1126
    // This is different to a resource with 0 clusters
1127
    if (vatt->vector_value(id_name, val) != 0)
1128
    {
1129
        return 0;
1130
    }
1131

    
1132
    one_util::split_unique(val, ',', vatt_cluster_ids);
1133

    
1134
    if ( vatt_cluster_ids.empty() )
1135
    {
1136
        return -2;
1137
    }
1138

    
1139
    if ( cluster_ids.empty() )
1140
    {
1141
        cluster_ids = vatt_cluster_ids;
1142

    
1143
        return 0;
1144
    }
1145

    
1146
    set<int> intersection = one_util::set_intersection(cluster_ids, vatt_cluster_ids);
1147

    
1148
    if (intersection.empty())
1149
    {
1150
        return -1;
1151
    }
1152

    
1153
    cluster_ids = intersection;
1154

    
1155
    return 0;
1156
}
1157

    
1158
/* ------------------------------------------------------------------------ */
1159

    
1160
void update_os_file(VectorAttribute *  os,
1161
                    const string&      base_name)
1162
{
1163
    ClusterPool *   clpool = Nebula::instance().get_clpool();
1164
    int             ds_id;
1165
    set<int>        cluster_ids;
1166

    
1167
    string base_name_ds_id   = base_name + "_DS_DSID";
1168
    string base_name_cluster = base_name + "_DS_CLUSTER_ID";
1169

    
1170
    if (os->vector_value(base_name_ds_id, ds_id) != 0)
1171
    {
1172
        return;
1173
    }
1174

    
1175
    clpool->query_datastore_clusters(ds_id, cluster_ids);
1176

    
1177
    os->replace(base_name_cluster, one_util::join(cluster_ids, ','));
1178
}
1179

    
1180
/* ------------------------------------------------------------------------ */
1181

    
1182
static void update_disk_cluster_id(VectorAttribute* disk)
1183
{
1184
    ClusterPool *   clpool = Nebula::instance().get_clpool();
1185
    int             ds_id;
1186
    set<int>        cluster_ids;
1187

    
1188
    if (disk->vector_value("DATASTORE_ID", ds_id) != 0)
1189
    {
1190
        return;
1191
    }
1192

    
1193
    clpool->query_datastore_clusters(ds_id, cluster_ids);
1194

    
1195
    disk->replace("CLUSTER_ID", one_util::join(cluster_ids, ','));
1196
}
1197

    
1198
/* ------------------------------------------------------------------------ */
1199

    
1200
static void update_nic_cluster_id(VectorAttribute* nic)
1201
{
1202
    ClusterPool *   clpool = Nebula::instance().get_clpool();
1203
    int             vn_id;
1204
    set<int>        cluster_ids;
1205

    
1206
    if (nic->vector_value("NETWORK_ID", vn_id) != 0)
1207
    {
1208
        return;
1209
    }
1210

    
1211
    clpool->query_vnet_clusters(vn_id, cluster_ids);
1212

    
1213
    nic->replace("CLUSTER_ID", one_util::join(cluster_ids, ','));
1214
}
1215

    
1216
/* ------------------------------------------------------------------------ */
1217

    
1218
/**
1219
 * Returns the list of Cluster IDs where the VM can be deployed, based
1220
 * on the Datastores and VirtualNetworks requested
1221
 *
1222
 * @param tmpl of the VirtualMachine
1223
 * @param cluster_ids set of Cluster IDs
1224
 * @param error_str Returns the error reason, if any
1225
 * @return 0 on success
1226
 */
1227
static int get_cluster_requirements(Template *tmpl, set<int>& cluster_ids,
1228
        string& error_str)
1229
{
1230
    ostringstream   oss;
1231
    int             num_vatts;
1232
    vector<VectorAttribute*> vatts;
1233

    
1234
    int incomp_id;
1235
    int rc;
1236

    
1237
    // Get cluster id from the KERNEL and INITRD (FILE Datastores)
1238
    VectorAttribute * osatt = tmpl->get("OS");
1239

    
1240
    if ( osatt != 0 )
1241
    {
1242
        update_os_file(osatt, "KERNEL");
1243

    
1244
        rc = check_and_set_cluster_id("KERNEL_DS_CLUSTER_ID", osatt, cluster_ids);
1245

    
1246
        if ( rc != 0 )
1247
        {
1248
            goto error_kernel;
1249
        }
1250

    
1251
        update_os_file(osatt, "INITRD");
1252

    
1253
        rc = check_and_set_cluster_id("INITRD_DS_CLUSTER_ID", osatt, cluster_ids);
1254

    
1255
        if ( rc != 0 )
1256
        {
1257
            goto error_initrd;
1258
        }
1259
    }
1260

    
1261
    // Get cluster id from all DISK vector attributes (IMAGE Datastore)
1262
    num_vatts = tmpl->get("DISK",vatts);
1263

    
1264
    for(int i=0; i<num_vatts; i++)
1265
    {
1266
        update_disk_cluster_id(vatts[i]);
1267

    
1268
        rc = check_and_set_cluster_id("CLUSTER_ID", vatts[i], cluster_ids);
1269

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

    
1277
    vatts.clear();
1278

    
1279
    // Get cluster id from all NIC vector attributes
1280
    num_vatts = tmpl->get("NIC", vatts);
1281

    
1282
    for(int i=0; i<num_vatts; i++)
1283
    {
1284
        update_nic_cluster_id(vatts[i]);
1285

    
1286
        rc = check_and_set_cluster_id("CLUSTER_ID", vatts[i], cluster_ids);
1287

    
1288
        if ( rc != 0 )
1289
        {
1290
            incomp_id = i;
1291
            goto error_nic;
1292
        }
1293
    }
1294

    
1295
    vatts.clear();
1296

    
1297
    // Get cluster id from all PCI attibutes, TYPE = NIC
1298
    num_vatts = tmpl->get("PCI", vatts);
1299

    
1300
    for(int i=0; i<num_vatts; i++)
1301
    {
1302
        if ( vatts[i]->vector_value("TYPE") != "NIC" )
1303
        {
1304
            continue;
1305
        }
1306

    
1307
        update_nic_cluster_id(vatts[i]);
1308

    
1309
        rc = check_and_set_cluster_id("CLUSTER_ID", vatts[i], cluster_ids);
1310

    
1311
        if ( rc != 0 )
1312
        {
1313
            incomp_id = i;
1314
            goto error_pci;
1315
        }
1316
    }
1317

    
1318
    return 0;
1319

    
1320
error_disk:
1321
    if (rc == -1)
1322
    {
1323
        oss << "Incompatible clusters in DISK. Datastore for DISK "<< incomp_id
1324
            << " is not in the same cluster as the one used by other VM elements "
1325
            << "(cluster " << one_util::join(cluster_ids, ',') << ")";
1326
    }
1327
    else
1328
    {
1329
        oss << "Missing clusters. Datastore for DISK "<< incomp_id
1330
            << " is not in any cluster";
1331
    }
1332

    
1333
    goto error_common;
1334

    
1335
error_kernel:
1336
    if (rc == -1)
1337
    {
1338
        oss<<"Incompatible cluster in KERNEL datastore, it should be in cluster "
1339
           << one_util::join(cluster_ids, ',') << ".";
1340
    }
1341
    else
1342
    {
1343
        oss << "Missing clusters. KERNEL datastore is not in any cluster.";
1344
    }
1345

    
1346
    goto error_common;
1347

    
1348
error_initrd:
1349
    if (rc == -1)
1350
    {
1351
        oss<<"Incompatible cluster in INITRD datastore, it should be in cluster "
1352
           << one_util::join(cluster_ids, ',') << ".";
1353
    }
1354
    else
1355
    {
1356
        oss << "Missing clusters. INITRD datastore is not in any cluster.";
1357
    }
1358

    
1359
    goto error_common;
1360

    
1361
error_nic:
1362
    if (rc == -1)
1363
    {
1364
        oss << "Incompatible clusters in NIC. Network for NIC "<< incomp_id
1365
            << " is not in the same cluster as the one used by other VM elements "
1366
            << "(cluster " << one_util::join(cluster_ids, ',') << ")";
1367
    }
1368
    else
1369
    {
1370
        oss << "Missing clusters. Network for NIC "<< incomp_id
1371
            << " is not in any cluster";
1372
    }
1373

    
1374
    goto error_common;
1375

    
1376
error_pci:
1377
    if (rc == -1)
1378
    {
1379
        oss << "Incompatible clusters in PCI (TYPE=NIC). Network for PCI "
1380
            << incomp_id
1381
            << " is not in the same cluster as the one used by other VM elements "
1382
            << "(cluster " << one_util::join(cluster_ids, ',') << ")";
1383
    }
1384
    else
1385
    {
1386
        oss << "Missing clusters. Network for PCI "<< incomp_id
1387
            << " is not in any cluster";
1388
    }
1389

    
1390
    goto error_common;
1391

    
1392
error_common:
1393
    error_str = oss.str();
1394

    
1395
    return -1;
1396
}
1397

    
1398
/* ------------------------------------------------------------------------ */
1399
/* ------------------------------------------------------------------------ */
1400

    
1401
int VirtualMachine::automatic_requirements(set<int>& cluster_ids,
1402
    string& error_str)
1403
{
1404
    ostringstream   oss;
1405
    set<string>     clouds;
1406

    
1407
    obj_template->erase("AUTOMATIC_REQUIREMENTS");
1408
    obj_template->erase("AUTOMATIC_DS_REQUIREMENTS");
1409

    
1410
    int rc = get_cluster_requirements(obj_template, cluster_ids, error_str);
1411

    
1412
    if (rc != 0)
1413
    {
1414
        return -1;
1415
    }
1416

    
1417
    if ( !cluster_ids.empty() )
1418
    {
1419
        set<int>::iterator i = cluster_ids.begin();
1420

    
1421
        oss << "(CLUSTER_ID = " << *i;
1422

    
1423
        for (++i; i != cluster_ids.end(); i++)
1424
        {
1425
            oss << " | CLUSTER_ID = " << *i;
1426
        }
1427

    
1428
        oss << ") & !(PUBLIC_CLOUD = YES)";
1429
    }
1430
    else
1431
    {
1432
        oss << "!(PUBLIC_CLOUD = YES)";
1433
    }
1434

    
1435
    int num_public = get_public_clouds(clouds);
1436

    
1437
    if (num_public != 0)
1438
    {
1439
        set<string>::iterator it = clouds.begin();
1440

    
1441
        oss << " | (PUBLIC_CLOUD = YES & (";
1442

    
1443
        oss << "HYPERVISOR = " << *it ;
1444

    
1445
        for (++it; it != clouds.end() ; ++it)
1446
        {
1447
            oss << " | HYPERVISOR = " << *it;
1448
        }
1449

    
1450
        oss << "))";
1451
    }
1452

    
1453
    obj_template->add("AUTOMATIC_REQUIREMENTS", oss.str());
1454

    
1455
    // Set automatic System DS requirements
1456

    
1457
    if ( !cluster_ids.empty() )
1458
    {
1459
        oss.str("");
1460

    
1461
        set<int>::iterator i = cluster_ids.begin();
1462

    
1463
        oss << "\"CLUSTERS/ID\" @> " << *i;
1464

    
1465
        for (++i; i != cluster_ids.end(); i++)
1466
        {
1467
            oss << " | \"CLUSTERS/ID\" @> " << *i;
1468
        }
1469

    
1470
        obj_template->add("AUTOMATIC_DS_REQUIREMENTS", oss.str());
1471
    }
1472

    
1473
    return 0;
1474
}
1475

    
1476
/* ------------------------------------------------------------------------ */
1477
/* ------------------------------------------------------------------------ */
1478

    
1479
int VirtualMachine::insert_replace(SqlDB *db, bool replace, string& error_str)
1480
{
1481
    ostringstream   oss;
1482
    int             rc;
1483

    
1484
    string xml_body;
1485
    char * sql_name;
1486
    char * sql_xml;
1487

    
1488
    sql_name =  db->escape_str(name.c_str());
1489

    
1490
    if ( sql_name == 0 )
1491
    {
1492
        goto error_generic;
1493
    }
1494

    
1495
    sql_xml = db->escape_str(to_xml(xml_body).c_str());
1496

    
1497
    if ( sql_xml == 0 )
1498
    {
1499
        goto error_body;
1500
    }
1501

    
1502
    if ( validate_xml(sql_xml) != 0 )
1503
    {
1504
        goto error_xml;
1505
    }
1506

    
1507
    if(replace)
1508
    {
1509
        oss << "REPLACE";
1510
    }
1511
    else
1512
    {
1513
        oss << "INSERT";
1514
    }
1515

    
1516
    oss << " INTO " << table << " ("<< db_names <<") VALUES ("
1517
        <<          oid             << ","
1518
        << "'" <<   sql_name        << "',"
1519
        << "'" <<   sql_xml         << "',"
1520
        <<          uid             << ","
1521
        <<          gid             << ","
1522
        <<          last_poll       << ","
1523
        <<          state           << ","
1524
        <<          lcm_state       << ","
1525
        <<          owner_u         << ","
1526
        <<          group_u         << ","
1527
        <<          other_u         << ")";
1528

    
1529
    db->free_str(sql_name);
1530
    db->free_str(sql_xml);
1531

    
1532
    rc = db->exec_wr(oss);
1533

    
1534
    return rc;
1535

    
1536
error_xml:
1537
    db->free_str(sql_name);
1538
    db->free_str(sql_xml);
1539

    
1540
    error_str = "Error transforming the VM to XML.";
1541

    
1542
    goto error_common;
1543

    
1544
error_body:
1545
    db->free_str(sql_name);
1546
    goto error_generic;
1547

    
1548
error_generic:
1549
    error_str = "Error inserting VM in DB.";
1550
error_common:
1551
    return -1;
1552
}
1553

    
1554
/* -------------------------------------------------------------------------- */
1555
/* -------------------------------------------------------------------------- */
1556

    
1557
int VirtualMachine::update_monitoring(SqlDB * db)
1558
{
1559
    ostringstream oss;
1560
    int           rc;
1561

    
1562
    string xml_body;
1563
    string error_str;
1564
    char * sql_xml;
1565

    
1566
    float       cpu = 0;
1567
    long long   memory = 0;
1568

    
1569
    obj_template->get("CPU", cpu);
1570
    obj_template->get("MEMORY", memory);
1571

    
1572
    oss << "<VM>"
1573
        << "<ID>" << oid << "</ID>"
1574
        << "<LAST_POLL>" << last_poll << "</LAST_POLL>"
1575
        << monitoring.to_xml(xml_body)
1576
        << "<TEMPLATE>"
1577
        <<   "<CPU>"    << cpu << "</CPU>"
1578
        <<   "<MEMORY>" << memory << "</MEMORY>"
1579
        << "</TEMPLATE>"
1580
        << "</VM>";
1581

    
1582
    sql_xml = db->escape_str(oss.str().c_str());
1583

    
1584
    if ( sql_xml == 0 )
1585
    {
1586
        goto error_body;
1587
    }
1588

    
1589
    if ( validate_xml(sql_xml) != 0 )
1590
    {
1591
        goto error_xml;
1592
    }
1593

    
1594
    oss.str("");
1595

    
1596
    oss << "REPLACE INTO " << monit_table << " ("<< monit_db_names <<") VALUES ("
1597
        <<          oid             << ","
1598
        <<          last_poll       << ","
1599
        << "'" <<   sql_xml         << "')";
1600

    
1601
    db->free_str(sql_xml);
1602

    
1603
    rc = db->exec_local_wr(oss);
1604

    
1605
    return rc;
1606

    
1607
error_xml:
1608
    db->free_str(sql_xml);
1609

    
1610
    error_str = "could not transform the VM to XML.";
1611

    
1612
    goto error_common;
1613

    
1614
error_body:
1615
    error_str = "could not insert the VM in the DB.";
1616

    
1617
error_common:
1618
    oss.str("");
1619
    oss << "Error updating VM monitoring information, " << error_str;
1620

    
1621
    NebulaLog::log("ONE",Log::ERROR, oss);
1622

    
1623
    return -1;
1624
}
1625

    
1626
/* -------------------------------------------------------------------------- */
1627
/* -------------------------------------------------------------------------- */
1628

    
1629
void VirtualMachine::add_history(
1630
    int   hid,
1631
    int   cid,
1632
    const string& hostname,
1633
    const string& vmm_mad,
1634
    const string& tm_mad,
1635
    int           ds_id)
1636
{
1637
    ostringstream os;
1638
    int           seq;
1639
    string        vm_xml;
1640

    
1641
    if (history == 0)
1642
    {
1643
        seq = 0;
1644
    }
1645
    else
1646
    {
1647
        seq = history->seq + 1;
1648

    
1649
        previous_history = history;
1650
    }
1651

    
1652
    to_xml_extended(vm_xml, 0);
1653

    
1654
    history = new History(oid, seq, hid, hostname, cid, vmm_mad, tm_mad, ds_id,
1655
            vm_xml);
1656

    
1657
    history_records.push_back(history);
1658
};
1659

    
1660
/* -------------------------------------------------------------------------- */
1661
/* -------------------------------------------------------------------------- */
1662

    
1663
void VirtualMachine::cp_history()
1664
{
1665
    History * htmp;
1666
    string    vm_xml;
1667

    
1668
    if (history == 0)
1669
    {
1670
        return;
1671
    }
1672

    
1673
    to_xml_extended(vm_xml, 0);
1674

    
1675
    htmp = new History(oid,
1676
                       history->seq + 1,
1677
                       history->hid,
1678
                       history->hostname,
1679
                       history->cid,
1680
                       history->vmm_mad_name,
1681
                       history->tm_mad_name,
1682
                       history->ds_id,
1683
                       vm_xml);
1684

    
1685
    previous_history = history;
1686
    history          = htmp;
1687

    
1688
    history_records.push_back(history);
1689
}
1690

    
1691
/* -------------------------------------------------------------------------- */
1692
/* -------------------------------------------------------------------------- */
1693

    
1694
void VirtualMachine::cp_previous_history()
1695
{
1696
    History * htmp;
1697
    string    vm_xml;
1698

    
1699
    if ( previous_history == 0 || history == 0)
1700
    {
1701
        return;
1702
    }
1703

    
1704
    to_xml_extended(vm_xml, 0);
1705

    
1706
    htmp = new History(oid,
1707
                       history->seq + 1,
1708
                       previous_history->hid,
1709
                       previous_history->hostname,
1710
                       previous_history->cid,
1711
                       previous_history->vmm_mad_name,
1712
                       previous_history->tm_mad_name,
1713
                       previous_history->ds_id,
1714
                       vm_xml);
1715

    
1716
    previous_history = history;
1717
    history          = htmp;
1718

    
1719
    history_records.push_back(history);
1720
}
1721

    
1722
/* -------------------------------------------------------------------------- */
1723
/* -------------------------------------------------------------------------- */
1724

    
1725
void VirtualMachine::get_requirements (int& cpu, int& memory, int& disk,
1726
        vector<VectorAttribute *>& pci_devs)
1727
{
1728
    istringstream   iss;
1729
    float           fcpu;
1730

    
1731
    pci_devs.clear();
1732

    
1733
    if ((get_template_attribute("MEMORY",memory) == false) ||
1734
        (get_template_attribute("CPU",fcpu) == false))
1735
    {
1736
        cpu    = 0;
1737
        memory = 0;
1738
        disk   = 0;
1739

    
1740
        return;
1741
    }
1742

    
1743
    cpu    = (int) (fcpu * 100);//now in 100%
1744
    memory = memory * 1024;     //now in Kilobytes
1745
    disk   = 0;
1746

    
1747
    obj_template->get("PCI", pci_devs);
1748

    
1749
    return;
1750
}
1751

    
1752
/* -------------------------------------------------------------------------- */
1753
/* -------------------------------------------------------------------------- */
1754

    
1755
int VirtualMachine::check_resize (
1756
        float cpu, int memory, int vcpu, string& error_str)
1757
{
1758
    if (cpu < 0)
1759
    {
1760
        error_str = "CPU must be a positive float or integer value.";
1761
        return -1;
1762
    }
1763

    
1764
    if (memory < 0)
1765
    {
1766
        error_str = "MEMORY must be a positive integer value.";
1767
        return -1;
1768
    }
1769

    
1770
    if (vcpu < 0)
1771
    {
1772
        error_str = "VCPU must be a positive integer value.";
1773
        return -1;
1774
    }
1775

    
1776
    return 0;
1777
}
1778

    
1779
/* -------------------------------------------------------------------------- */
1780
/* -------------------------------------------------------------------------- */
1781

    
1782
int VirtualMachine::resize(float cpu, int memory, int vcpu, string& error_str)
1783
{
1784
    ostringstream oss;
1785

    
1786
    int rc = check_resize(cpu, memory, vcpu, error_str);
1787

    
1788
    if (rc != 0)
1789
    {
1790
        return rc;
1791
    }
1792

    
1793
    if (cpu > 0)
1794
    {
1795
        oss << cpu;
1796
        replace_template_attribute("CPU", oss.str());
1797
        oss.str("");
1798
    }
1799

    
1800
    if (memory > 0)
1801
    {
1802
        oss << memory;
1803
        replace_template_attribute("MEMORY", oss.str());
1804
        oss.str("");
1805
    }
1806

    
1807
    if (vcpu > 0)
1808
    {
1809
        oss << vcpu;
1810
        replace_template_attribute("VCPU", oss.str());
1811
    }
1812

    
1813
    return 0;
1814
}
1815

    
1816
/* -------------------------------------------------------------------------- */
1817
/* -------------------------------------------------------------------------- */
1818

    
1819
bool VirtualMachine::is_imported() const
1820
{
1821
    bool imported = false;
1822

    
1823
    get_template_attribute("IMPORTED", imported);
1824

    
1825
    return imported;
1826
}
1827

    
1828
string VirtualMachine::get_import_state()
1829
{
1830
    string import_state;
1831

    
1832
    user_obj_template->get("IMPORT_STATE", import_state);
1833
    user_obj_template->erase("IMPORT_STATE");
1834

    
1835
    return import_state;
1836
}
1837

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

    
1841
bool VirtualMachine::is_imported_action_supported(History::VMAction action) const
1842
{
1843
    if (!hasHistory())
1844
    {
1845
        return false;
1846
    }
1847

    
1848
    VirtualMachineManager * vmm = Nebula::instance().get_vmm();
1849

    
1850
    return vmm->is_imported_action_supported(get_vmm_mad(), action);
1851
}
1852

    
1853
/* -------------------------------------------------------------------------- */
1854
/* -------------------------------------------------------------------------- */
1855

    
1856
void VirtualMachine::remove_security_group(int sgid)
1857
{
1858
    int num_sgs;
1859
    int ssgid;
1860

    
1861
    vector<VectorAttribute  *> sgs;
1862

    
1863
    num_sgs = obj_template->get("SECURITY_GROUP_RULE", sgs);
1864

    
1865
    for(int i=0; i<num_sgs; i++)
1866
    {
1867
        sgs[i]->vector_value("SECURITY_GROUP_ID", ssgid);
1868

    
1869
        if ( ssgid == sgid )
1870
        {
1871
            obj_template->remove(sgs[i]);
1872
            delete sgs[i];
1873
        }
1874
    }
1875
}
1876

    
1877
/* -------------------------------------------------------------------------- */
1878
/* -------------------------------------------------------------------------- */
1879

    
1880
int VirtualMachine::get_vrouter_id()
1881
{
1882
    int vrid;
1883

    
1884
    if (!obj_template->get("VROUTER_ID", vrid))
1885
    {
1886
        vrid = -1;
1887
    }
1888

    
1889
    return vrid;
1890
}
1891

    
1892
/* -------------------------------------------------------------------------- */
1893
/* -------------------------------------------------------------------------- */
1894

    
1895
bool VirtualMachine::is_vrouter()
1896
{
1897
    return get_vrouter_id() != -1;
1898
}
1899

    
1900
/* -------------------------------------------------------------------------- */
1901
/* -------------------------------------------------------------------------- */
1902

    
1903
void VirtualMachine::set_auth_request(int uid,
1904
                                      AuthRequest& ar,
1905
                                      VirtualMachineTemplate *tmpl)
1906
{
1907
    VirtualMachineDisks::disk_iterator disk;
1908
    VirtualMachineDisks tdisks(tmpl, false);
1909

    
1910
    for( disk = tdisks.begin(); disk != tdisks.end(); ++disk)
1911
    {
1912
        (*disk)->authorize(uid, &ar);
1913
    }
1914

    
1915
    VirtualMachineNics::nic_iterator nic;
1916
    VirtualMachineNics tnics(tmpl);
1917

    
1918
    for( nic = tnics.begin(); nic != tnics.end(); ++nic)
1919
    {
1920
        (*nic)->authorize(uid, &ar);
1921
    }
1922

    
1923
    const VectorAttribute * vmgroup = tmpl->get("VMGROUP");
1924

    
1925
    if ( vmgroup != 0 )
1926
    {
1927
        VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool();
1928

    
1929
        vmgrouppool->authorize(vmgroup, uid, &ar);
1930
    }
1931
}
1932

    
1933
/* -------------------------------------------------------------------------- */
1934
/* -------------------------------------------------------------------------- */
1935

    
1936
string& VirtualMachine::to_xml_extended(string& xml, int n_history) const
1937
{
1938
    string template_xml;
1939
    string user_template_xml;
1940
    string monitoring_xml;
1941
    string history_xml;
1942
    string perm_xml;
1943
    string snap_xml;
1944

    
1945
    ostringstream   oss;
1946

    
1947
    oss << "<VM>"
1948
        << "<ID>"        << oid       << "</ID>"
1949
        << "<UID>"       << uid       << "</UID>"
1950
        << "<GID>"       << gid       << "</GID>"
1951
        << "<UNAME>"     << uname     << "</UNAME>"
1952
        << "<GNAME>"     << gname     << "</GNAME>"
1953
        << "<NAME>"      << name      << "</NAME>"
1954
        << perms_to_xml(perm_xml)
1955
        << "<LAST_POLL>" << last_poll << "</LAST_POLL>"
1956
        << "<STATE>"     << state     << "</STATE>"
1957
        << "<LCM_STATE>" << lcm_state << "</LCM_STATE>"
1958
        << "<PREV_STATE>"     << prev_state     << "</PREV_STATE>"
1959
        << "<PREV_LCM_STATE>" << prev_lcm_state << "</PREV_LCM_STATE>"
1960
        << "<RESCHED>"   << resched   << "</RESCHED>"
1961
        << "<STIME>"     << stime     << "</STIME>"
1962
        << "<ETIME>"     << etime     << "</ETIME>"
1963
        << "<DEPLOY_ID>" << deploy_id << "</DEPLOY_ID>"
1964
        << monitoring.to_xml(monitoring_xml)
1965
        << obj_template->to_xml(template_xml)
1966
        << user_obj_template->to_xml(user_template_xml);
1967

    
1968
    if ( hasHistory() && n_history > 0 )
1969
    {
1970
        oss << "<HISTORY_RECORDS>";
1971

    
1972
        if ( n_history == 2 )
1973
        {
1974
            for (unsigned int i=0; i < history_records.size(); i++)
1975
            {
1976
                oss << history_records[i]->to_xml(history_xml);
1977
            }
1978
        }
1979
        else
1980
        {
1981
            oss << history->to_xml(history_xml);
1982
        }
1983

    
1984
        oss << "</HISTORY_RECORDS>";
1985
    }
1986
    else
1987
    {
1988
        oss << "<HISTORY_RECORDS/>";
1989
    }
1990

    
1991
    VirtualMachineDisks::disk_iterator disk;
1992

    
1993
    for ( disk = const_cast<VirtualMachineDisks *>(&disks)->begin() ;
1994
            disk != const_cast<VirtualMachineDisks *>(&disks)->end() ; ++disk)
1995
    {
1996
        const Snapshots * snapshots = (*disk)->get_snapshots();
1997

    
1998
        if ( snapshots != 0 )
1999
        {
2000
            oss << snapshots->to_xml(snap_xml);
2001
        }
2002
    }
2003

    
2004
    oss << "</VM>";
2005

    
2006
    xml = oss.str();
2007

    
2008
    return xml;
2009
}
2010

    
2011
/* -------------------------------------------------------------------------- */
2012
/* -------------------------------------------------------------------------- */
2013

    
2014
int VirtualMachine::from_xml(const string &xml_str)
2015
{
2016
    vector<xmlNodePtr> content;
2017

    
2018
    int istate;
2019
    int ilcmstate;
2020
    int rc = 0;
2021

    
2022
    // Initialize the internal XML object
2023
    update_from_str(xml_str);
2024

    
2025
    // Get class base attributes
2026
    rc += xpath(oid,       "/VM/ID",    -1);
2027

    
2028
    rc += xpath(uid,       "/VM/UID",   -1);
2029
    rc += xpath(gid,       "/VM/GID",   -1);
2030

    
2031
    rc += xpath(uname,     "/VM/UNAME", "not_found");
2032
    rc += xpath(gname,     "/VM/GNAME", "not_found");
2033
    rc += xpath(name,      "/VM/NAME",  "not_found");
2034

    
2035
    rc += xpath<time_t>(last_poll, "/VM/LAST_POLL", 0);
2036
    rc += xpath(resched, "/VM/RESCHED", 0);
2037

    
2038
    rc += xpath<time_t>(stime, "/VM/STIME", 0);
2039
    rc += xpath<time_t>(etime, "/VM/ETIME", 0);
2040
    rc += xpath(deploy_id, "/VM/DEPLOY_ID","");
2041

    
2042
    // Permissions
2043
    rc += perms_from_xml();
2044

    
2045
    //VM states
2046
    rc += xpath(istate,    "/VM/STATE",     0);
2047
    rc += xpath(ilcmstate, "/VM/LCM_STATE", 0);
2048

    
2049
    state     = static_cast<VmState>(istate);
2050
    lcm_state = static_cast<LcmState>(ilcmstate);
2051

    
2052
    xpath(istate,    "/VM/PREV_STATE",     istate);
2053
    xpath(ilcmstate, "/VM/PREV_LCM_STATE", ilcmstate);
2054

    
2055
    prev_state     = static_cast<VmState>(istate);
2056
    prev_lcm_state = static_cast<LcmState>(ilcmstate);
2057

    
2058
    // -------------------------------------------------------------------------
2059
    // Virtual Machine template and attributes
2060
    // -------------------------------------------------------------------------
2061
    ObjectXML::get_nodes("/VM/TEMPLATE", content);
2062

    
2063
    if (content.empty())
2064
    {
2065
        return -1;
2066
    }
2067
    rc += obj_template->from_xml_node(content[0]);
2068

    
2069
    vector<VectorAttribute *> vdisks, vnics, pcis;
2070
    vector<VectorAttribute *>::iterator it;
2071

    
2072
    obj_template->get("DISK", vdisks);
2073

    
2074
    disks.init(vdisks, true);
2075

    
2076
    obj_template->get("NIC", vnics);
2077

    
2078
    obj_template->get("PCI", pcis);
2079

    
2080
    for (it =pcis.begin(); it != pcis.end(); ++it)
2081
    {
2082
        if ( (*it)->vector_value("TYPE") == "NIC" )
2083
        {
2084
            vnics.push_back(*it);
2085
        }
2086
    }
2087

    
2088
    nics.init(vnics, true);
2089

    
2090
    ObjectXML::free_nodes(content);
2091
    content.clear();
2092

    
2093
    // -------------------------------------------------------------------------
2094
    // Virtual Machine Monitoring
2095
    // -------------------------------------------------------------------------
2096
    ObjectXML::get_nodes("/VM/MONITORING", content);
2097

    
2098
    if (content.empty())
2099
    {
2100
        return -1;
2101
    }
2102

    
2103
    rc += monitoring.from_xml_node(content[0]);
2104

    
2105
    ObjectXML::free_nodes(content);
2106
    content.clear();
2107

    
2108
    // -------------------------------------------------------------------------
2109
    // Virtual Machine user template
2110
    // -------------------------------------------------------------------------
2111
    ObjectXML::get_nodes("/VM/USER_TEMPLATE", content);
2112

    
2113
    if (content.empty())
2114
    {
2115
        return -1;
2116
    }
2117

    
2118
    rc += user_obj_template->from_xml_node(content[0]);
2119

    
2120
    ObjectXML::free_nodes(content);
2121
    content.clear();
2122

    
2123
    // -------------------------------------------------------------------------
2124
    // Last history entry
2125
    // -------------------------------------------------------------------------
2126
    int last_seq;
2127

    
2128
    if ( xpath(last_seq,"/VM/HISTORY_RECORDS/HISTORY/SEQ", -1) == 0 && 
2129
            last_seq != -1 )
2130
    {
2131
        history = new History(oid, last_seq);
2132

    
2133
        history_records.resize(history->seq + 1);
2134
        history_records[history->seq] = history;
2135
    }
2136

    
2137
    // -------------------------------------------------------------------------
2138
    // Virtual Machine Snapshots
2139
    // -------------------------------------------------------------------------
2140
    ObjectXML::get_nodes("/VM/SNAPSHOTS", content);
2141

    
2142
    for (vector<xmlNodePtr>::iterator it=content.begin();it!=content.end();it++)
2143
    {
2144
        Snapshots * snap = new Snapshots(-1, false);
2145

    
2146
        rc += snap->from_xml_node(*it);
2147

    
2148
        if ( rc != 0)
2149
        {
2150
            delete snap;
2151
            break;
2152
        }
2153

    
2154
        disks.set_snapshots(snap->get_disk_id(), snap);
2155
    }
2156

    
2157
    if (!content.empty())
2158
    {
2159
        ObjectXML::free_nodes(content);
2160
        content.clear();
2161
    }
2162

    
2163
    // -------------------------------------------------------------------------
2164
    // -------------------------------------------------------------------------
2165
    if (rc != 0)
2166
    {
2167
        return -1;
2168
    }
2169

    
2170
    return 0;
2171
}
2172

    
2173
/* -------------------------------------------------------------------------- */
2174
/* -------------------------------------------------------------------------- */
2175

    
2176
int VirtualMachine::update_info(const string& monitor_data)
2177
{
2178
    int    rc;
2179
    string error;
2180

    
2181
    ostringstream oss;
2182

    
2183
    last_poll = time(0);
2184

    
2185
    rc = monitoring.update(monitor_data, error);
2186

    
2187
    if ( rc != 0)
2188
    {
2189
        oss << "Ignoring monitoring information, error:" << error
2190
            << ". Monitor information was: " << monitor_data;
2191

    
2192
        NebulaLog::log("VMM", Log::ERROR, oss);
2193

    
2194
        set_template_error_message(oss.str());
2195

    
2196
        log("VMM", Log::ERROR, oss);
2197

    
2198
        return -1;
2199
    }
2200

    
2201
    set_vm_info();
2202

    
2203
    clear_template_monitor_error();
2204

    
2205
    oss << "VM " << oid << " successfully monitored: " << monitor_data;
2206

    
2207
    NebulaLog::log("VMM", Log::DEBUG, oss);
2208

    
2209
    return 0;
2210
};
2211

    
2212
/* -------------------------------------------------------------------------- */
2213
/* -------------------------------------------------------------------------- */
2214

    
2215
int VirtualMachine::replace_template(
2216
        const string&   tmpl_str,
2217
        bool            keep_restricted,
2218
        string&         error)
2219
{
2220
    VirtualMachineTemplate * new_tmpl =
2221
            new VirtualMachineTemplate(false,'=',"USER_TEMPLATE");
2222

    
2223
    if ( new_tmpl == 0 )
2224
    {
2225
        error = "Cannot allocate a new template";
2226
        return -1;
2227
    }
2228

    
2229
    if ( new_tmpl->parse_str_or_xml(tmpl_str, error) != 0 )
2230
    {
2231
        delete new_tmpl;
2232
        return -1;
2233
    }
2234

    
2235
    if (keep_restricted)
2236
    {
2237
        new_tmpl->remove_restricted();
2238

    
2239
        if (user_obj_template != 0)
2240
        {
2241
            user_obj_template->remove_all_except_restricted();
2242

    
2243
            new_tmpl->merge(user_obj_template);
2244
        }
2245
    }
2246

    
2247
    delete user_obj_template;
2248

    
2249
    user_obj_template = new_tmpl;
2250

    
2251
    return 0;
2252
}
2253

    
2254
/* -------------------------------------------------------------------------- */
2255
/* -------------------------------------------------------------------------- */
2256

    
2257
int VirtualMachine::append_template(
2258
        const string&   tmpl_str,
2259
        bool            keep_restricted,
2260
        string&         error)
2261
{
2262
    VirtualMachineTemplate * new_tmpl =
2263
            new VirtualMachineTemplate(false,'=',"USER_TEMPLATE");
2264

    
2265
    if ( new_tmpl == 0 )
2266
    {
2267
        error = "Cannot allocate a new template";
2268
        return -1;
2269
    }
2270

    
2271
    if ( new_tmpl->parse_str_or_xml(tmpl_str, error) != 0 )
2272
    {
2273
        delete new_tmpl;
2274
        return -1;
2275
    }
2276

    
2277
    if (keep_restricted)
2278
    {
2279
        new_tmpl->remove_restricted();
2280
    }
2281

    
2282
    if (user_obj_template != 0)
2283
    {
2284
        user_obj_template->merge(new_tmpl);
2285
        delete new_tmpl;
2286
    }
2287
    else
2288
    {
2289
        user_obj_template = new_tmpl;
2290
    }
2291

    
2292
    return 0;
2293
}
2294

    
2295
/* -------------------------------------------------------------------------- */
2296
/* -------------------------------------------------------------------------- */
2297

    
2298
void VirtualMachine::set_template_error_message(const string& message)
2299
{
2300
    set_template_error_message("ERROR", message);
2301
}
2302

    
2303
/* -------------------------------------------------------------------------- */
2304

    
2305
void VirtualMachine::set_template_error_message(const string& name,
2306
                                               const string& message)
2307
{
2308
    SingleAttribute * attr;
2309
    ostringstream     error_value;
2310

    
2311
    error_value << one_util::log_time() << " : " << message;
2312

    
2313
    attr = new SingleAttribute(name, error_value.str());
2314

    
2315
    user_obj_template->erase(name);
2316
    user_obj_template->set(attr);
2317
}
2318

    
2319
/* -------------------------------------------------------------------------- */
2320
/* -------------------------------------------------------------------------- */
2321

    
2322
void VirtualMachine::clear_template_error_message()
2323
{
2324
    user_obj_template->erase("ERROR");
2325
}
2326

    
2327
/* -------------------------------------------------------------------------- */
2328
/* -------------------------------------------------------------------------- */
2329

    
2330
void VirtualMachine::set_template_monitor_error(const string& message)
2331
{
2332
    set_template_error_message("ERROR_MONITOR", message);
2333
}
2334

    
2335
/* -------------------------------------------------------------------------- */
2336

    
2337
void VirtualMachine::clear_template_monitor_error()
2338
{
2339
    user_obj_template->erase("ERROR_MONITOR");
2340
}
2341

    
2342
/* -------------------------------------------------------------------------- */
2343
/* -------------------------------------------------------------------------- */
2344

    
2345
void VirtualMachine::get_public_clouds(const string& pname, set<string> &clouds) const
2346
{
2347
    vector<VectorAttribute *>                 attrs;
2348
    vector<VectorAttribute *>::const_iterator it;
2349

    
2350
    user_obj_template->get(pname, attrs);
2351

    
2352
    if ( !attrs.empty() && pname == "EC2" )
2353
    {
2354
            clouds.insert("ec2");
2355
    }
2356

    
2357
    for (it = attrs.begin(); it != attrs.end(); it++)
2358
    {
2359
        string type = (*it)->vector_value("TYPE");
2360

    
2361
        if (!type.empty())
2362
        {
2363
            clouds.insert(type);
2364
        }
2365
    }
2366
}
2367

    
2368
/* -------------------------------------------------------------------------- */
2369
/* -------------------------------------------------------------------------- */
2370

    
2371
int VirtualMachine::parse_public_clouds(const char * pname, string& error)
2372
{
2373
    vector<VectorAttribute *>           attrs;
2374
    vector<VectorAttribute *>::iterator it;
2375

    
2376
    string * str;
2377
    string p_vatt;
2378

    
2379
    int rc  = 0;
2380
    int num = user_obj_template->remove(pname, attrs);
2381

    
2382
    for (it = attrs.begin(); it != attrs.end(); it++)
2383
    {
2384
        str = (*it)->marshall();
2385

    
2386
        if ( str == 0 )
2387
        {
2388
            ostringstream oss;
2389
            oss << "Internal error processing " << pname;
2390
            error = oss.str();
2391
            rc    = -1;
2392
            break;
2393
        }
2394

    
2395
        rc = parse_template_attribute(*str, p_vatt, error);
2396

    
2397
        delete str;
2398

    
2399
        if ( rc != 0 )
2400
        {
2401
            rc = -1;
2402
            break;
2403
        }
2404

    
2405
        VectorAttribute * nvatt = new VectorAttribute(pname);
2406

    
2407
        nvatt->unmarshall(p_vatt);
2408

    
2409
        user_obj_template->set(nvatt);
2410
    }
2411

    
2412
    for (int i = 0; i < num ; i++)
2413
    {
2414
        delete attrs[i];
2415
    }
2416

    
2417
    return rc;
2418
}
2419

    
2420
/* -------------------------------------------------------------------------- */
2421
/* -------------------------------------------------------------------------- */
2422

    
2423
/**
2424
 * Replaces the values of a vector value, preserving the existing ones
2425
 */
2426
static void replace_vector_values(Template *old_tmpl, Template *new_tmpl,
2427
        const char * name, const string * vnames, int num)
2428
{
2429
    string value;
2430

    
2431
    VectorAttribute * new_attr = new_tmpl->get(name);
2432
    VectorAttribute * old_attr = old_tmpl->get(name);
2433

    
2434
    if ( new_attr == 0 )
2435
    {
2436
        old_tmpl->erase(name);
2437
    }
2438
    else if ( old_attr == 0 )
2439
    {
2440
        old_tmpl->set(new_attr->clone());
2441
    }
2442
    else
2443
    {
2444
        for (int i=0; i < num; i++)
2445
        {
2446
            if ( new_attr->vector_value(vnames[i], value) == -1 )
2447
            {
2448
                old_attr->remove(vnames[i]);
2449
            }
2450
            else
2451
            {
2452
                old_attr->replace(vnames[i], value);
2453
            }
2454
        }
2455
    }
2456
};
2457

    
2458
/* -------------------------------------------------------------------------- */
2459

    
2460
int VirtualMachine::updateconf(VirtualMachineTemplate& tmpl, string &err)
2461
{
2462
    switch (state)
2463
    {
2464
        case PENDING:
2465
        case HOLD:
2466
        case POWEROFF:
2467
        case UNDEPLOYED:
2468
        case CLONING:
2469
        case CLONING_FAILURE:
2470
            break;
2471

    
2472
        case ACTIVE:
2473
            switch (lcm_state)
2474
            {
2475
                case LCM_INIT:
2476
                case PROLOG:
2477
                case EPILOG:
2478
                case SHUTDOWN:
2479
                case CLEANUP_RESUBMIT:
2480
                case SHUTDOWN_POWEROFF:
2481
                case CLEANUP_DELETE:
2482
                case HOTPLUG_SAVEAS_POWEROFF:
2483
                case SHUTDOWN_UNDEPLOY:
2484
                case EPILOG_UNDEPLOY:
2485
                case PROLOG_UNDEPLOY:
2486
                case HOTPLUG_PROLOG_POWEROFF:
2487
                case HOTPLUG_EPILOG_POWEROFF:
2488
                case BOOT_FAILURE:
2489
                case PROLOG_FAILURE:
2490
                case EPILOG_FAILURE:
2491
                case EPILOG_UNDEPLOY_FAILURE:
2492
                case PROLOG_MIGRATE_POWEROFF:
2493
                case PROLOG_MIGRATE_POWEROFF_FAILURE:
2494
                case BOOT_UNDEPLOY_FAILURE:
2495
                case PROLOG_UNDEPLOY_FAILURE:
2496
                case DISK_SNAPSHOT_POWEROFF:
2497
                case DISK_SNAPSHOT_REVERT_POWEROFF:
2498
                case DISK_SNAPSHOT_DELETE_POWEROFF:
2499
                    break;
2500

    
2501
                default:
2502
                    err = "configuration cannot be updated in state " + state_str();
2503
                    return -1;
2504
            };
2505

    
2506
        case INIT:
2507
        case DONE:
2508
        case SUSPENDED:
2509
        case STOPPED:
2510

    
2511
            err = "configuration cannot be updated in state " + state_str();
2512
            return -1;
2513
    }
2514

    
2515
    // -------------------------------------------------------------------------
2516
    // Update OS
2517
    // -------------------------------------------------------------------------
2518
    string os_names[] = {"ARCH", "MACHINE", "KERNEL", "INITRD", "BOOTLOADER",
2519
        "BOOT"};
2520

    
2521
    replace_vector_values(obj_template, &tmpl, "OS", os_names, 6);
2522

    
2523
    if ( set_boot_order(obj_template, err) != 0 )
2524
    {
2525
        return -1;
2526
    }
2527

    
2528
    // -------------------------------------------------------------------------
2529
    // Update FEATURES:
2530
    // -------------------------------------------------------------------------
2531
    string features_names[] = {"PAE", "ACPI", "APIC", "LOCALTIME", "HYPERV",
2532
        "GUEST_AGENT"};
2533

    
2534
    replace_vector_values(obj_template, &tmpl, "FEATURES", features_names, 6);
2535

    
2536
    // -------------------------------------------------------------------------
2537
    // Update INPUT:
2538
    // -------------------------------------------------------------------------
2539
    string input_names[] = {"TYPE", "BUS"};
2540

    
2541
    replace_vector_values(obj_template, &tmpl, "INPUT", input_names, 2);
2542

    
2543
    // -------------------------------------------------------------------------
2544
    // Update GRAPHICS:
2545
    // -------------------------------------------------------------------------
2546
    string graphics_names[] = {"TYPE", "LISTEN", "PASSWD", "KEYMAP"};
2547

    
2548
    replace_vector_values(obj_template, &tmpl, "GRAPHICS", graphics_names, 4);
2549

    
2550
    // -------------------------------------------------------------------------
2551
    // Update RAW:
2552
    // -------------------------------------------------------------------------
2553
    string raw_names[] = {"TYPE", "DATA", "DATA_VMX"};
2554

    
2555
    replace_vector_values(obj_template, &tmpl, "RAW", raw_names, 3);
2556

    
2557
    // -------------------------------------------------------------------------
2558
    // Update CONTEXT: any value
2559
    // -------------------------------------------------------------------------
2560
    VectorAttribute * context_bck = obj_template->get("CONTEXT");
2561
    VectorAttribute * context_new = tmpl.get("CONTEXT");
2562

    
2563
    if ( context_bck == 0 && context_new != 0 )
2564
    {
2565
        err = "Virtual machine does not have context, cannot add a new one.";
2566

    
2567
        return -1;
2568
    }
2569
    else if ( context_bck != 0 && context_new != 0 )
2570
    {
2571
        context_new = context_new->clone();
2572

    
2573
        context_new->replace("TARGET",  context_bck->vector_value("TARGET"));
2574
        context_new->replace("DISK_ID", context_bck->vector_value("DISK_ID"));
2575

    
2576
        obj_template->remove(context_bck);
2577
        obj_template->set(context_new);
2578

    
2579
        if ( generate_token_context(context_new, err) != 0 ||
2580
               generate_network_context(context_new, err) != 0  )
2581
        {
2582
            obj_template->erase("CONTEXT");
2583
            obj_template->set(context_bck);
2584

    
2585
            return -1;
2586
        }
2587

    
2588
        delete context_bck;
2589
    }
2590

    
2591
    return 0;
2592
}
2593

    
2594
/* -------------------------------------------------------------------------- */
2595
/* -------------------------------------------------------------------------- */
2596
/* VirtualMachine Disks Interface                                             */
2597
/* -------------------------------------------------------------------------- */
2598
/* -------------------------------------------------------------------------- */
2599

    
2600
int VirtualMachine::get_disk_images(string& error_str)
2601
{
2602
    vector<Attribute *> adisks;
2603
    vector<Attribute *> acontext_disks;
2604

    
2605
    vector<Attribute*>::iterator it;
2606

    
2607
    int num_context = user_obj_template->remove("CONTEXT", acontext_disks);
2608
    int num_disks   = user_obj_template->remove("DISK", adisks);
2609

    
2610
    for (it = acontext_disks.begin(); it != acontext_disks.end(); )
2611
    {
2612
        if ( (*it)->type() != Attribute::VECTOR )
2613
        {
2614
            delete *it;
2615
            num_context--;
2616
            it = acontext_disks.erase(it);
2617
        }
2618
        else
2619
        {
2620
            obj_template->set(*it);
2621
            ++it;
2622
        }
2623
    }
2624

    
2625
    for (it = adisks.begin(); it != adisks.end(); )
2626
    {
2627
        if ( (*it)->type() != Attribute::VECTOR )
2628
        {
2629
            delete *it;
2630
            num_disks--;
2631
            it = adisks.erase(it);
2632
        }
2633
        else
2634
        {
2635
            obj_template->set(*it);
2636
            ++it;
2637
        }
2638
    }
2639

    
2640
    if ( num_disks > 20 )
2641
    {
2642
        error_str = "Exceeded the maximum number of disks (20)";
2643
        return -1;
2644
    }
2645

    
2646
    VectorAttribute * context = 0;
2647

    
2648
    if ( num_context > 0 )
2649
    {
2650
        context = static_cast<VectorAttribute * >(acontext_disks[0]);
2651
    }
2652

    
2653
    return disks.get_images(oid, uid, adisks, context, error_str);
2654
}
2655

    
2656
/* -------------------------------------------------------------------------- */
2657
/* -------------------------------------------------------------------------- */
2658

    
2659
void VirtualMachine::release_disk_images(vector<Template *>& quotas)
2660
{
2661
    bool image_error = (state == ACTIVE && lcm_state != EPILOG) &&
2662
                        state != PENDING && state != HOLD &&
2663
                        state != CLONING && state != CLONING_FAILURE;
2664

    
2665
    disks.release_images(oid, image_error, quotas);
2666
}
2667

    
2668
/* -------------------------------------------------------------------------- */
2669
/* -------------------------------------------------------------------------- */
2670

    
2671
int VirtualMachine::set_up_attach_disk(VirtualMachineTemplate * tmpl, string& err)
2672
{
2673
    VectorAttribute * new_vdisk = tmpl->get("DISK");
2674

    
2675
    if ( new_vdisk == 0 )
2676
    {
2677
        err = "Internal error parsing DISK attribute";
2678
        return -1;
2679
    }
2680

    
2681
    new_vdisk = new_vdisk->clone();
2682

    
2683
    VectorAttribute * context = get_template_attribute("CONTEXT");
2684

    
2685
    VirtualMachineDisk * new_disk;
2686

    
2687
    new_disk = disks.set_up_attach(oid, uid, get_cid(), new_vdisk, context, err);
2688

    
2689
    if ( new_disk == 0 )
2690
    {
2691
        delete new_vdisk;
2692
        return -1;
2693
    }
2694

    
2695
    // -------------------------------------------------------------------------
2696
    // Add new disk to template and set info in history before attaching
2697
    // -------------------------------------------------------------------------
2698
    set_vm_info();
2699

    
2700
    obj_template->set(new_disk->vector_attribute());
2701

    
2702
    return 0;
2703
}
2704

    
2705
/* -------------------------------------------------------------------------- */
2706
/* -------------------------------------------------------------------------- */
2707
/* Disk save as interface                                                     */
2708
/* -------------------------------------------------------------------------- */
2709
/* -------------------------------------------------------------------------- */
2710

    
2711
int VirtualMachine::set_saveas_state()
2712
{
2713
    switch (state)
2714
    {
2715
        case ACTIVE:
2716
            if (lcm_state != RUNNING)
2717
            {
2718
                return -1;
2719
            }
2720

    
2721
            set_state(HOTPLUG_SAVEAS);
2722
            break;
2723

    
2724
        case POWEROFF:
2725
            set_state(ACTIVE);
2726
            set_state(HOTPLUG_SAVEAS_POWEROFF);
2727
            break;
2728

    
2729
        case SUSPENDED:
2730
            set_state(ACTIVE);
2731
            set_state(HOTPLUG_SAVEAS_SUSPENDED);
2732
            break;
2733

    
2734
        default:
2735
            return -1;
2736
    }
2737

    
2738
    return 0;
2739
}
2740

    
2741
/* -------------------------------------------------------------------------- */
2742
/* -------------------------------------------------------------------------- */
2743

    
2744
int VirtualMachine::clear_saveas_state()
2745
{
2746
    switch (lcm_state)
2747
    {
2748
        case HOTPLUG_SAVEAS:
2749
            set_state(RUNNING);
2750
            break;
2751

    
2752
        case HOTPLUG_SAVEAS_POWEROFF:
2753
            set_state(POWEROFF);
2754
            set_state(LCM_INIT);
2755
            break;
2756

    
2757
        case HOTPLUG_SAVEAS_SUSPENDED:
2758
            set_state(SUSPENDED);
2759
            set_state(LCM_INIT);
2760
            break;
2761

    
2762
        default:
2763
            return -1;
2764
    }
2765

    
2766
    return 0;
2767
}
2768

    
2769
/* -------------------------------------------------------------------------- */
2770
/* -------------------------------------------------------------------------- */
2771
/* VirtualMachine Nic interface                                                */
2772
/* -------------------------------------------------------------------------- */
2773
/* -------------------------------------------------------------------------- */
2774

    
2775
int VirtualMachine::get_network_leases(string& estr)
2776
{
2777
    /* ---------------------------------------------------------------------- */
2778
    /* Get the NIC attributes:                                                */
2779
    /*   * NIC                                                                */
2780
    /*   * PCI + TYPE = NIC                                                   */
2781
    /* ---------------------------------------------------------------------- */
2782
    vector<Attribute  * > anics;
2783

    
2784
    user_obj_template->remove("NIC", anics);
2785

    
2786
    for (vector<Attribute*>::iterator it = anics.begin(); it != anics.end(); )
2787
    {
2788
        if ( (*it)->type() != Attribute::VECTOR )
2789
        {
2790
            delete *it;
2791
            it = anics.erase(it);
2792
        }
2793
        else
2794
        {
2795
            obj_template->set(*it);
2796
            ++it;
2797
        }
2798
    }
2799

    
2800
    vector<VectorAttribute *> pcis;
2801
    vector<VectorAttribute *>::iterator it;
2802

    
2803
    get_template_attribute("PCI", pcis);
2804

    
2805
    for (it =pcis.begin(); it != pcis.end(); ++it)
2806
    {
2807
        if ( (*it)->vector_value("TYPE") == "NIC" )
2808
        {
2809
            anics.push_back(*it);
2810
        }
2811
    }
2812

    
2813
    /* ---------------------------------------------------------------------- */
2814
    /* Get the network leases & security groups for the NICs and PCIs         */
2815
    /* ---------------------------------------------------------------------- */
2816
    vector<VectorAttribute*> sgs;
2817

    
2818
    VectorAttribute * nic_default = obj_template->get("NIC_DEFAULT");
2819

    
2820
    if (nics.get_network_leases(oid, uid, anics, nic_default, sgs, estr) == -1)
2821
    {
2822
        return -1;
2823
    }
2824

    
2825
    /* ---------------------------------------------------------------------- */
2826
    /* Get the associated secutiry groups for NICs and PCI TYPE=NIC           */
2827
    /* ---------------------------------------------------------------------- */
2828

    
2829
    obj_template->set(sgs);
2830

    
2831
    return 0;
2832
}
2833

    
2834
/* -------------------------------------------------------------------------- */
2835
/* -------------------------------------------------------------------------- */
2836

    
2837
int VirtualMachine::set_up_attach_nic(VirtualMachineTemplate * tmpl, string& err)
2838
{
2839
    // -------------------------------------------------------------------------
2840
    // Get the new NIC attribute from the template
2841
    // -------------------------------------------------------------------------
2842
    VectorAttribute * new_nic = tmpl->get("NIC");
2843

    
2844
    if ( new_nic == 0 )
2845
    {
2846
        err = "Wrong format or missing NIC attribute";
2847
        return -1;
2848
    }
2849

    
2850
    new_nic = new_nic->clone();
2851

    
2852
    // -------------------------------------------------------------------------
2853
    // Setup nic for attachment
2854
    // -------------------------------------------------------------------------
2855
    vector<VectorAttribute *> sgs;
2856

    
2857
    VectorAttribute * nic_default = obj_template->get("NIC_DEFAULT");
2858

    
2859
    int rc = nics.set_up_attach_nic(oid, uid, get_cid(), new_nic, nic_default,
2860
                sgs, err);
2861

    
2862
    if ( rc != 0 )
2863
    {
2864
        delete new_nic;
2865
        return -1;
2866
    }
2867

    
2868
    // -------------------------------------------------------------------------
2869
    // Add new nic to template and set info in history before attaching
2870
    // -------------------------------------------------------------------------
2871
    set_vm_info();
2872

    
2873
    obj_template->set(new_nic);
2874

    
2875
    for(vector<VectorAttribute*>::iterator it=sgs.begin(); it!=sgs.end(); ++it)
2876
    {
2877
        obj_template->set(*it);
2878
    }
2879

    
2880
    return 0;
2881
}
2882

    
2883
/* -------------------------------------------------------------------------- */
2884
/* -------------------------------------------------------------------------- */
2885

    
2886
int VirtualMachine::set_detach_nic(int nic_id)
2887
{
2888
    VirtualMachineNic * nic = nics.get_nic(nic_id);
2889

    
2890
    if ( nic == 0 )
2891
    {
2892
        return -1;
2893
    }
2894

    
2895
    nic->set_attach();
2896

    
2897
    clear_nic_context(nic_id);
2898

    
2899
    return 0;
2900
}
2901

    
2902
/* -------------------------------------------------------------------------- */
2903
/* -------------------------------------------------------------------------- */
2904
/* VirtualMachine VMGroup interface                                           */
2905
/* -------------------------------------------------------------------------- */
2906
/* -------------------------------------------------------------------------- */
2907

    
2908
int VirtualMachine::get_vmgroup(string& error)
2909
{
2910
    vector<Attribute  *> vmgroups;
2911
    vector<Attribute*>::iterator it;
2912

    
2913
    bool found;
2914
    VectorAttribute * thegroup = 0;
2915

    
2916
    user_obj_template->remove("VMGROUP", vmgroups);
2917

    
2918
    for (it = vmgroups.begin(), found = false; it != vmgroups.end(); )
2919
    {
2920
        if ( (*it)->type() != Attribute::VECTOR || found )
2921
        {
2922
            delete *it;
2923
            it = vmgroups.erase(it);
2924
        }
2925
        else
2926
        {
2927
            thegroup = dynamic_cast<VectorAttribute *>(*it);
2928
            found    = true;
2929

    
2930
            ++it;
2931
        }
2932
    }
2933

    
2934
    if ( thegroup == 0 )
2935
    {
2936
        return 0;
2937
    }
2938

    
2939
    VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool();
2940
    int rc;
2941

    
2942
    rc = vmgrouppool->vmgroup_attribute(thegroup, get_uid(), get_oid(), error);
2943

    
2944
    if ( rc != 0 )
2945
    {
2946
        delete thegroup;
2947

    
2948
        return -1;
2949
    }
2950

    
2951
    obj_template->set(thegroup);
2952

    
2953
    return 0;
2954
}
2955

    
2956
/* -------------------------------------------------------------------------- */
2957
/* -------------------------------------------------------------------------- */
2958

    
2959
void VirtualMachine::release_vmgroup()
2960
{
2961
    VectorAttribute * thegroup = obj_template->get("VMGROUP");
2962

    
2963
    if ( thegroup == 0 )
2964
    {
2965
        return;
2966
    }
2967

    
2968
    VMGroupPool * vmgrouppool = Nebula::instance().get_vmgrouppool();
2969

    
2970
    vmgrouppool->del_vm(thegroup, get_oid());
2971
}
2972