Statistics
| Branch: | Tag: | Revision:

one / src / vmm / VirtualMachineManagerDriver.cc @ dd32809e

History | View | Annotate | Download (16.8 KB)

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

    
17
#include "VirtualMachineManagerDriver.h"
18
#include "NebulaLog.h"
19
#include "LifeCycleManager.h"
20

    
21
#include "Nebula.h"
22
#include <sstream>
23

    
24
VirtualMachineManagerDriver::VirtualMachineManagerDriver(
25
    int                         userid,
26
    const map<string,string>&   attrs,
27
    bool                        sudo,
28
    VirtualMachinePool *        pool):
29
        Mad(userid,attrs,sudo),driver_conf(true),vmpool(pool)
30
{
31
    map<string,string>::const_iterator  it;
32
    char *          error_msg = 0;
33
    const char *    cfile;
34
    string          file;
35
    int             rc;
36

    
37
    it = attrs.find("DEFAULT");
38

    
39
    if ( it != attrs.end() )
40
    {
41
        if (it->second[0] != '/') //Look in ONE_LOCATION/etc or in "/etc/one"
42
        {
43
            Nebula& nd = Nebula::instance();
44

    
45
            file  = nd.get_defaults_location() + it->second;
46
            cfile = file.c_str();
47
        }
48
        else //Absolute Path
49
        {
50
            cfile = it->second.c_str();
51
        }
52

    
53
        rc = driver_conf.parse(cfile, &error_msg);
54

    
55
        if ( rc != 0 )
56
        {
57
            ostringstream   oss;
58

    
59
            if ( error_msg != 0 )
60
            {
61
                oss << "Error loading driver configuration file " << cfile <<
62
                    " : " << error_msg;
63

    
64
                free(error_msg);
65
            }
66
            else
67
            {
68
                oss << "Error loading driver configuration file " << cfile;
69
            }
70

    
71
            NebulaLog::log("VMM", Log::ERROR, oss);
72
        }
73
    }
74
}
75

    
76
/* -------------------------------------------------------------------------- */
77
/* -------------------------------------------------------------------------- */
78

    
79
void VirtualMachineManagerDriver::get_default(
80
    const char *  name,
81
    const char *  vname,
82
    string&       value) const
83
{
84
    vector<const Attribute *>   attrs;
85
    string                      sn = name;
86

    
87
    if ( driver_conf.get(sn,attrs) == 1 )
88
    {
89
        const VectorAttribute * vattr;
90

    
91
        vattr = static_cast<const VectorAttribute *>(attrs[0]);
92

    
93
        value = vattr->vector_value(vname);
94
    }
95
    else
96
    {
97
        value = "";
98
    }
99
}
100

    
101
/* ************************************************************************** */
102
/* Driver ASCII Protocol Implementation                                       */
103
/* ************************************************************************** */
104

    
105
void VirtualMachineManagerDriver::deploy (
106
    const int     oid,
107
    const string& host,
108
    const string& conf) const
109
{
110
    ostringstream os;
111

    
112
    os << "DEPLOY " << oid << " " << host << " " << conf << " -" << endl;
113

    
114
    write(os);
115
};
116

    
117
/* -------------------------------------------------------------------------- */
118
/* -------------------------------------------------------------------------- */
119

    
120
void VirtualMachineManagerDriver::shutdown (
121
    const int     oid,
122
    const string& host,
123
    const string& name) const
124
{
125
    ostringstream os;
126

    
127
    os << "SHUTDOWN " << oid << " " << host << " " << name << " -" << endl;
128

    
129
    write(os);
130
};
131

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

    
135
void VirtualMachineManagerDriver::cancel (
136
    const int     oid,
137
    const string& host,
138
    const string& name) const
139
{
140
    ostringstream os;
141

    
142
    os << "CANCEL " << oid << " " << host << " " << name << " -" << endl;
143

    
144
    write(os);
145
};
146

    
147
/* -------------------------------------------------------------------------- */
148
/* -------------------------------------------------------------------------- */
149

    
150
void VirtualMachineManagerDriver::checkpoint (
151
    const int     oid,
152
    const string& host,
153
    const string& name,
154
    const string& file) const
155
{
156
    ostringstream os;
157

    
158
    os<< "CHECKPOINT " << oid<< " "<< host<< " "<< name<< " "<< file<< endl;
159

    
160
    write(os);
161
};
162

    
163
/* -------------------------------------------------------------------------- */
164
/* -------------------------------------------------------------------------- */
165

    
166
void VirtualMachineManagerDriver::save (
167
    const int     oid,
168
    const string& host,
169
    const string& name,
170
    const string& file) const
171
{
172
    ostringstream os;
173

    
174
    os<< "SAVE " << oid << " " << host << " " << name << " "<< file << endl;
175

    
176
    write(os);
177
};
178

    
179
/* -------------------------------------------------------------------------- */
180
/* -------------------------------------------------------------------------- */
181

    
182
void VirtualMachineManagerDriver::restore (
183
    const int     oid,
184
    const string& host,
185
    const string& name,
186
    const string& file) const
187
{
188
    ostringstream os;
189

    
190
    os << "RESTORE " << oid << " " << host << " " << name << " " << file<< endl;
191

    
192
    write(os);
193
};
194

    
195
/* -------------------------------------------------------------------------- */
196
/* -------------------------------------------------------------------------- */
197

    
198
void VirtualMachineManagerDriver::migrate (
199
    const int     oid,
200
    const string& shost,
201
    const string& name,
202
    const string& dhost) const
203
{
204
    ostringstream os;
205

    
206
    os<< "MIGRATE " << oid << " "<< shost<< " "<< name<< " "<< dhost<< endl;
207

    
208
    write(os);
209
};
210

    
211
/* -------------------------------------------------------------------------- */
212
/* -------------------------------------------------------------------------- */
213

    
214
void VirtualMachineManagerDriver::poll (
215
    const int     oid,
216
    const string& host,
217
    const string& name) const
218
{
219
    ostringstream os;
220

    
221
    os << "POLL " << oid << " " << host << " " << name << " -" << endl;
222

    
223
    write(os);
224
};
225

    
226
/* ************************************************************************** */
227
/* MAD Interface                                                              */
228
/* ************************************************************************** */
229

    
230
/* -------------------------------------------------------------------------- */
231
/* Helpers for the protocol function                                          */
232
/* -------------------------------------------------------------------------- */
233

    
234
static void log_error(VirtualMachine* vm, 
235
                      ostringstream&  os, 
236
                      istringstream&  is,
237
                      const char *    msg)
238
{
239
    string info;
240

    
241
    getline(is,info);
242

    
243
    os.str("");
244
    os << msg;
245

    
246
    if (!info.empty() && info[0] != '-')
247
    {
248
        os << ": " << info;
249
        vm->set_template_error_message(os.str());
250
    }
251

    
252
    vm->log("VMM",Log::ERROR,os);
253
}
254

    
255
/* -------------------------------------------------------------------------- */
256
/* -------------------------------------------------------------------------- */
257

    
258
void VirtualMachineManagerDriver::protocol(
259
    string&     message)
260
{
261
    istringstream is(message);
262
    ostringstream os;
263

    
264
    string action;
265
    string result;
266

    
267
    int              id;
268
    VirtualMachine * vm;
269

    
270

    
271
    os << "Message received: " << message;
272
    NebulaLog::log("VMM", Log::DEBUG, os);
273

    
274
    // Parse the driver message
275
    if ( is.good() )
276
        is >> action >> ws;
277
    else
278
        return;
279

    
280
    if ( is.good() )
281
        is >> result >> ws;
282
    else
283
        return;
284

    
285
    if ( is.good() )
286
    {
287
        is >> id >> ws;
288

    
289
        if ( is.fail() )
290
        {
291
            if ( action == "LOG" )
292
            {
293
                string info;
294

    
295
                is.clear();
296
                getline(is,info);
297
                NebulaLog::log("VMM", log_type(result[0]), info.c_str());
298
            }
299

    
300
            return;
301
        }
302
    }
303
    else
304
        return;
305

    
306
    // Get the VM from the pool
307
    vm = vmpool->get(id,true);
308

    
309
    if ( vm == 0 )
310
    {
311
        return;
312
    }
313

    
314
    if ( vm->get_lcm_state() == VirtualMachine::CLEANUP ||
315
         vm->get_lcm_state() == VirtualMachine::FAILURE ||
316
         vm->get_lcm_state() == VirtualMachine::LCM_INIT )
317
    {
318
        os.str("");
319
        os << "Ignored: " << message;
320
        vm->log("VMM",Log::WARNING,os);
321

    
322
        vm->unlock();
323
        return;
324
    }
325

    
326
    // Driver Actions
327
    if ( action == "DEPLOY" )
328
    {
329
        Nebula              &ne = Nebula::instance();
330
        LifeCycleManager *  lcm = ne.get_lcm();
331

    
332
        if (result == "SUCCESS")
333
        {
334
            string deploy_id;
335
            time_t thetime = time(0);
336

    
337
            is >> deploy_id;
338

    
339
            vm->update_info(deploy_id);
340
            vm->set_last_poll(thetime);
341

    
342
            vmpool->update(vm);
343

    
344
            lcm->trigger(LifeCycleManager::DEPLOY_SUCCESS, id);
345
        }
346
        else
347
        {
348
            log_error(vm,os,is,"Error deploying virtual machine");
349
            vmpool->update(vm);
350

    
351
            lcm->trigger(LifeCycleManager::DEPLOY_FAILURE, id);
352
        }
353
    }
354
    else if (action == "SHUTDOWN" )
355
    {
356
        Nebula              &ne  = Nebula::instance();
357
        LifeCycleManager    *lcm = ne.get_lcm();
358

    
359
        if (result == "SUCCESS")
360
        {
361
            lcm->trigger(LifeCycleManager::SHUTDOWN_SUCCESS, id);
362
        }
363
        else
364
        {
365
            log_error(vm,os,is,"Error shuting down VM");
366
            vmpool->update(vm);
367

    
368
            lcm->trigger(LifeCycleManager::SHUTDOWN_FAILURE, id);
369
        }
370
    }
371
    else if ( action == "CANCEL" )
372
    {
373
        Nebula              &ne  = Nebula::instance();
374
        LifeCycleManager    *lcm = ne.get_lcm();
375

    
376
        if (result == "SUCCESS")
377
        {
378
            lcm->trigger(LifeCycleManager::CANCEL_SUCCESS, id);
379
        }
380
        else
381
        {
382
            log_error(vm,os,is,"Error canceling VM");
383
            vmpool->update(vm);
384

    
385
            lcm->trigger(LifeCycleManager::CANCEL_FAILURE, id);
386
        }
387
    }
388
    else if ( action == "SAVE" )
389
    {
390
        Nebula              &ne  = Nebula::instance();
391
        LifeCycleManager    *lcm = ne.get_lcm();
392

    
393
        if (result == "SUCCESS")
394
        {
395
            lcm->trigger(LifeCycleManager::SAVE_SUCCESS, id);
396
        }
397
        else
398
        {
399
            log_error(vm,os,is,"Error saving VM state");
400
            vmpool->update(vm);
401

    
402
            lcm->trigger(LifeCycleManager::SAVE_FAILURE, id);
403
        }
404
    }
405
    else if ( action == "RESTORE" )
406
    {
407
        Nebula              &ne  = Nebula::instance();
408
        LifeCycleManager    *lcm = ne.get_lcm();
409

    
410
        if (result == "SUCCESS")
411
        {
412
            lcm->trigger(LifeCycleManager::DEPLOY_SUCCESS, id);
413
        }
414
        else
415
        {
416
            log_error(vm,os,is,"Error restoring VM");
417
            vmpool->update(vm);
418

    
419
            lcm->trigger(LifeCycleManager::DEPLOY_FAILURE, id);
420
        }
421
    }
422
    else if ( action == "MIGRATE" )
423
    {
424
        Nebula              &ne  = Nebula::instance();
425
        LifeCycleManager    *lcm = ne.get_lcm();
426

    
427
        if (result == "SUCCESS")
428
        {
429
            lcm->trigger(LifeCycleManager::DEPLOY_SUCCESS, id);
430
        }
431
        else
432
        {
433
            log_error(vm,os,is,"Error live migrating VM");
434
            vmpool->update(vm);
435

    
436
            lcm->trigger(LifeCycleManager::DEPLOY_FAILURE, id);
437
        }
438
    }
439
    else if ( action == "POLL" )
440
    {
441
        if (result == "SUCCESS")
442
        {
443
            size_t          pos;
444

    
445
            string          tmp;
446
            string          var;
447
            ostringstream   os;
448
            istringstream   tiss;
449

    
450
            int             cpu    = -1;
451
            int             memory = -1;
452
            int             net_tx = -1;
453
            int             net_rx = -1;
454
            char            state  = '-';
455

    
456
            string monitor_str = is.str();
457
            bool   parse_error = false;
458

    
459
            while(is.good())
460
            {
461
                is >> tmp >> ws;
462

    
463
                pos = tmp.find('=');
464

    
465
                if ( pos == string::npos )
466
                {
467
                    parse_error = true;
468
                    continue;
469
                }
470

    
471
                tmp.replace(pos,1," ");
472

    
473
                tiss.clear();
474

    
475
                tiss.str(tmp);
476

    
477
                tiss >> var >> ws;
478

    
479
                if (!tiss.good())
480
                {
481
                    parse_error = true;
482
                    continue;
483
                }
484

    
485
                if (var == "USEDMEMORY")
486
                {
487
                    tiss >> memory;
488
                }
489
                else if (var == "USEDCPU")
490
                {
491
                    tiss >> cpu;
492
                }
493
                else if (var == "NETRX")
494
                {
495
                    tiss >> net_rx;
496
                }
497
                else if (var == "NETTX")
498
                {
499
                    tiss >> net_tx;
500
                }
501
                else if (var == "STATE")
502
                {
503
                    tiss >> state;
504
                }
505
                else if (!var.empty())
506
                {
507
                    string val;
508

    
509
                    os.str("");
510
                    os << "Adding custom monitoring attribute: " << tmp;
511

    
512
                    vm->log("VMM",Log::WARNING,os);
513

    
514
                    tiss >> val;
515

    
516
                    vm->replace_template_attribute(var,val);
517
                }
518
            }
519

    
520
            if (parse_error)
521
            {
522
                os.str("");
523
                os << "Error parsing monitoring str:\"" << monitor_str <<"\"";
524

    
525
                vm->log("VMM",Log::ERROR,os);
526

    
527
                vm->set_template_error_message(os.str());
528
                vmpool->update(vm);
529

    
530
                vm->unlock();
531
                return;
532
            }
533

    
534
            vm->update_info(memory,cpu,net_tx,net_rx);
535

    
536
            vmpool->update(vm);
537

    
538
            if (state != '-' &&
539
                (vm->get_lcm_state() == VirtualMachine::RUNNING ||
540
                 vm->get_lcm_state() == VirtualMachine::UNKNOWN))
541
            {
542
                Nebula              &ne  = Nebula::instance();
543
                LifeCycleManager *  lcm = ne.get_lcm();
544

    
545
                switch (state)
546
                {
547
                case 'a': // Still active, good!
548
                    os.str("");
549
                    os  << "Monitor Information:\n"
550
                        << "\tCPU   : "<< cpu    << "\n"
551
                        << "\tMemory: "<< memory << "\n"
552
                        << "\tNet_TX: "<< net_tx << "\n"
553
                        << "\tNet_RX: "<< net_rx;
554
                    vm->log("VMM",Log::DEBUG,os);
555

    
556
                    if ( vm->get_lcm_state() == VirtualMachine::UNKNOWN)
557
                    {
558
                        vm->log("VMM",Log::INFO,"VM was now found, new state is"
559
                                " RUNNING");
560
                        vm->set_state(VirtualMachine::RUNNING);
561
                        vmpool->update(vm);
562
                    }
563
                    break;
564

    
565
                case 'p': // It's paused
566
                    vm->log("VMM",Log::INFO,"VM running but new state "
567
                            "from monitor is PAUSED.");
568

    
569
                    lcm->trigger(LifeCycleManager::MONITOR_SUSPEND, id);
570
                    break;
571

    
572
                case 'e': //Failed
573
                    vm->log("VMM",Log::INFO,"VM running but new state "
574
                            "from monitor is ERROR.");
575

    
576
                    lcm->trigger(LifeCycleManager::MONITOR_FAILURE, id);
577
                    break;
578

    
579
                case 'd': //The VM was not found
580
                    vm->log("VMM",Log::INFO,"VM running but it was not found."
581
                            " Restart and delete actions available or try to"
582
                            " recover it manually");
583

    
584
                    lcm->trigger(LifeCycleManager::MONITOR_DONE, id);
585
                    break;
586
                }
587
            }
588
        }
589
        else
590
        {
591
            log_error(vm,os,is,"Error monitoring VM");
592
            vmpool->update(vm);
593

    
594
            vm->log("VMM",Log::ERROR,os);
595
        }
596
    }
597
    else if (action == "LOG")
598
    {
599
        string info;
600

    
601
        getline(is,info);
602
        vm->log("VMM",log_type(result[0]),info.c_str());
603
    }
604

    
605
    vm->unlock();
606
}
607

    
608
/* -------------------------------------------------------------------------- */
609
/* -------------------------------------------------------------------------- */
610

    
611
void VirtualMachineManagerDriver::recover()
612
{
613
    NebulaLog::log("VMM",Log::INFO,"Recovering VMM drivers");
614
}