Statistics
| Branch: | Tag: | Revision:

one / src / host / Host.cc @ ea876146

History | View | Annotate | Download (20.6 KB)

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

    
17
#include <limits.h>
18
#include <string.h>
19

    
20
#include <iostream>
21
#include <sstream>
22

    
23
#include "Host.h"
24
#include "Nebula.h"
25

    
26
/* ************************************************************************ */
27
/* Host :: Constructor/Destructor                                           */
28
/* ************************************************************************ */
29

    
30
Host::Host(
31
    int id,
32
    const string& _hostname,
33
    const string& _im_mad_name,
34
    const string& _vmm_mad_name,
35
    const string& _vnm_mad_name,
36
    int           _cluster_id,
37
    const string& _cluster_name):
38
        PoolObjectSQL(id,HOST,_hostname,-1,-1,"","",table),
39
        Clusterable(_cluster_id, _cluster_name),
40
        state(INIT),
41
        im_mad_name(_im_mad_name),
42
        vmm_mad_name(_vmm_mad_name),
43
        vnm_mad_name(_vnm_mad_name),
44
        last_monitored(0),
45
        vm_collection("VMS")
46
{
47
    string default_cpu; //TODO - Get these two from oned.conf
48
    string default_mem;
49

    
50
    obj_template = new HostTemplate;
51

    
52
    add_template_attribute("RESERVED_CPU", default_cpu);
53
    add_template_attribute("RESERVED_MEM", default_cpu);
54

    
55
    replace_template_attribute("IM_MAD", im_mad_name);
56
    replace_template_attribute("VM_MAD", vmm_mad_name);
57
    replace_template_attribute("VN_MAD", vnm_mad_name);
58
}
59

    
60
Host::~Host()
61
{
62
    delete obj_template;
63
}
64

    
65
/* ************************************************************************ */
66
/* Host :: Database Access Functions                                        */
67
/* ************************************************************************ */
68

    
69
const char * Host::table = "host_pool";
70

    
71
const char * Host::db_names =
72
    "oid, name, body, state, last_mon_time, uid, gid, owner_u, group_u, other_u, cid";
73

    
74
const char * Host::db_bootstrap = "CREATE TABLE IF NOT EXISTS host_pool ("
75
    "oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, state INTEGER, "
76
    "last_mon_time INTEGER, uid INTEGER, gid INTEGER, owner_u INTEGER, "
77
    "group_u INTEGER, other_u INTEGER, cid INTEGER, UNIQUE(name))";
78

    
79

    
80
const char * Host::monit_table = "host_monitoring";
81

    
82
const char * Host::monit_db_names = "hid, last_mon_time, body";
83

    
84
const char * Host::monit_db_bootstrap = "CREATE TABLE IF NOT EXISTS "
85
    "host_monitoring (hid INTEGER, last_mon_time INTEGER, body MEDIUMTEXT, "
86
    "PRIMARY KEY(hid, last_mon_time))";
87
/* ------------------------------------------------------------------------ */
88
/* ------------------------------------------------------------------------ */
89

    
90
int Host::insert_replace(SqlDB *db, bool replace, string& error_str)
91
{
92
    ostringstream   oss;
93

    
94
    int    rc;
95
    string xml_body;
96

    
97
    char * sql_hostname;
98
    char * sql_xml;
99

    
100
    // Set the owner and group to oneadmin
101
    set_user(0, "");
102
    set_group(GroupPool::ONEADMIN_ID, GroupPool::ONEADMIN_NAME);
103

    
104
   // Update the Host
105

    
106
    sql_hostname = db->escape_str(name.c_str());
107

    
108
    if ( sql_hostname == 0 )
109
    {
110
        goto error_hostname;
111
    }
112

    
113
    sql_xml = db->escape_str(to_xml(xml_body).c_str());
114

    
115
    if ( sql_xml == 0 )
116
    {
117
        goto error_body;
118
    }
119

    
120
    if ( validate_xml(sql_xml) != 0 )
121
    {
122
        goto error_xml;
123
    }
124

    
125
    if(replace)
126
    {
127
        oss << "REPLACE";
128
    }
129
    else
130
    {
131
        oss << "INSERT";
132
    }
133

    
134
    // Construct the SQL statement to Insert or Replace
135

    
136
    oss <<" INTO "<<table <<" ("<< db_names <<") VALUES ("
137
        <<          oid                 << ","
138
        << "'" <<   sql_hostname        << "',"
139
        << "'" <<   sql_xml             << "',"
140
        <<          state               << ","
141
        <<          last_monitored      << ","
142
        <<          uid                 << ","
143
        <<          gid                 << ","
144
        <<          owner_u             << ","
145
        <<          group_u             << ","
146
        <<          other_u             << ","
147
        <<          cluster_id          << ")";
148

    
149
    rc = db->exec(oss);
150

    
151
    db->free_str(sql_hostname);
152
    db->free_str(sql_xml);
153

    
154
    return rc;
155

    
156
error_xml:
157
    db->free_str(sql_hostname);
158
    db->free_str(sql_xml);
159

    
160
    error_str = "Error transforming the Host to XML.";
161

    
162
    goto error_common;
163

    
164
error_body:
165
    db->free_str(sql_hostname);
166
    goto error_generic;
167

    
168
error_hostname:
169
    goto error_generic;
170

    
171
error_generic:
172
    error_str = "Error inserting Host in DB.";
173
error_common:
174
    return -1;
175
}
176

    
177
/* ------------------------------------------------------------------------ */
178
/* ------------------------------------------------------------------------ */
179

    
180
int Host::extract_ds_info(
181
            string          &parse_str,
182
            Template        &tmpl,
183
            map<int, const VectorAttribute*> &ds)
184
{
185
    char *    error_msg;
186
    int       rc;
187

    
188
    const VectorAttribute *  vatt;
189
    vector<const Attribute*> ds_att;
190

    
191
    vector<const Attribute*>::const_iterator it;
192

    
193
    // -------------------------------------------------------------------------
194
    // Parse Template
195
    // -------------------------------------------------------------------------
196
    rc = tmpl.parse(parse_str, &error_msg);
197

    
198
    if ( rc != 0 )
199
    {
200
        ostringstream ess;
201

    
202
        ess << "Error parsing host information: " << error_msg
203
            << ". Monitoring information: " << endl << parse_str;
204

    
205
        NebulaLog::log("ONE", Log::ERROR, ess);
206

    
207
        touch(false);
208

    
209
        set_template_error_message("Error parsing monitor information."
210
            " Check oned.log for more details.");
211

    
212
        free(error_msg);
213

    
214
        return -1;
215
    }
216

    
217
    // -------------------------------------------------------------------------
218
    // Get DS information
219
    // -------------------------------------------------------------------------
220
    tmpl.get("DS", ds_att);
221

    
222
    for (it = ds_att.begin(); it != ds_att.end(); it++)
223
    {
224
        int dsid;
225

    
226
        vatt = dynamic_cast<const VectorAttribute*>(*it);
227

    
228
        if (vatt == 0)
229
        {
230
            continue;
231
        }
232

    
233
        rc = vatt->vector_value("ID", dsid);
234

    
235
        if (rc == 0 && dsid != -1)
236
        {
237
            ds.insert(make_pair(dsid, vatt));
238
        }
239
    }
240

    
241
    return 0;
242
}
243

    
244
/* ------------------------------------------------------------------------ */
245
/* ------------------------------------------------------------------------ */
246

    
247
int Host::update_info(Template        &tmpl,
248
                      bool            &with_vm_info,
249
                      set<int>        &lost,
250
                      map<int,string> &found,
251
                      set<int>        &found_twice,
252
                      const set<int>  &non_shared_ds,
253
                      long long       reserved_cpu,
254
                      long long       reserved_mem)
255
{
256
    VectorAttribute*             vatt;
257
    vector<Attribute*>::iterator it;
258
    vector<Attribute*>           vm_att;
259
    vector<Attribute*>           ds_att;
260
    vector<Attribute*>           local_ds_att;
261

    
262
    int   rc;
263
    int   vmid;
264
    float val;
265

    
266
    string error_st;
267

    
268
    ostringstream zombie;
269
    ostringstream wild;
270

    
271
    set<int>::iterator set_it;
272

    
273
    set<int> prev_tmp_lost   = tmp_lost_vms;
274
    set<int> prev_tmp_zombie = tmp_zombie_vms;
275
    set<int> prev_tmp_found  = tmp_found_vms;
276

    
277
    int num_zombies = 0;
278
    int num_wilds   = 0;
279

    
280
    // -------------------------------------------------------------------------
281
    // Remove expired information from current template
282
    // -------------------------------------------------------------------------
283
    clear_template_error_message();
284

    
285
    remove_template_attribute("ZOMBIES");
286
    remove_template_attribute("TOTAL_ZOMBIES");
287

    
288
    remove_template_attribute("WILDS");
289
    remove_template_attribute("TOTAL_WILDS");
290

    
291
    remove_template_attribute("VM");
292
    remove_template_attribute("VM_POLL");
293

    
294
    remove_template_attribute("DS");
295

    
296
    // -------------------------------------------------------------------------
297
    // Copy monitor, extract share info & update last_monitored and state
298
    // -------------------------------------------------------------------------
299

    
300
    obj_template->merge(&tmpl, error_st);
301

    
302
    touch(true);
303

    
304
    if (isEnabled())
305
    {
306
        get_reserved_capacity(reserved_cpu, reserved_mem);
307

    
308
        erase_template_attribute("TOTALCPU", val);
309
        host_share.max_cpu = val - reserved_cpu;
310
        erase_template_attribute("TOTALMEMORY", val);
311
        host_share.max_mem = val - reserved_mem;
312
        erase_template_attribute("DS_LOCATION_TOTAL_MB", val);
313
        host_share.max_disk = val;
314

    
315
        erase_template_attribute("FREECPU", val);
316
        host_share.free_cpu = val;
317
        erase_template_attribute("FREEMEMORY", val);
318
        host_share.free_mem = val;
319
        erase_template_attribute("DS_LOCATION_FREE_MB", val);
320
        host_share.free_disk = val;
321

    
322
        erase_template_attribute("USEDCPU", val);
323
        host_share.used_cpu = val;
324
        erase_template_attribute("USEDMEMORY", val);
325
        host_share.used_mem = val;
326
        erase_template_attribute("DS_LOCATION_USED_MB", val);
327
        host_share.used_disk = val;
328
    }
329

    
330
    // -------------------------------------------------------------------------
331
    // Correlate VM information with the list of running VMs
332
    // -------------------------------------------------------------------------
333

    
334
    erase_template_attribute("VM_POLL", with_vm_info);
335

    
336
    obj_template->remove("VM", vm_att);
337

    
338
    tmp_lost_vms = vm_collection.get_collection_copy();
339

    
340
    tmp_zombie_vms.clear();
341

    
342
    tmp_found_vms.clear();
343

    
344
    for (it = vm_att.begin(); it != vm_att.end(); it++)
345
    {
346
        vatt = dynamic_cast<VectorAttribute*>(*it);
347

    
348
        if (vatt == 0)
349
        {
350
            delete *it;
351
            continue;
352
        }
353

    
354
        rc = vatt->vector_value("ID", vmid);
355

    
356
        if (rc == 0 && vmid == -1) //Check if it is an imported
357
        {
358
            Nebula&  nd = Nebula::instance();
359
            VirtualMachinePool * vmpool = nd.get_vmpool();
360

    
361
            vmid = vmpool->get_vmid(vatt->vector_value("DEPLOY_ID"));
362
        }
363

    
364
        if (rc == 0 && vmid != -1)
365
        {
366
            if (tmp_lost_vms.erase(vmid) == 1) //Good, known
367
            {
368
                found.insert(make_pair(vmid, vatt->vector_value("POLL")));
369

    
370
                tmp_found_vms.insert(vmid);
371

    
372
                if (prev_tmp_found.count(vmid) == 1)
373
                {
374
                    found_twice.insert(vmid);
375
                }
376
            }
377
            else //Bad, known but should not be here
378
            {
379
                tmp_zombie_vms.insert(vmid);
380

    
381
                // Reported as zombie at least 2 times?
382
                if (prev_tmp_zombie.count(vmid) == 1)
383
                {
384
                    string zname;
385

    
386
                    if (num_zombies++ > 0)
387
                    {
388
                        zombie << ", ";
389
                    }
390

    
391
                    zname = vatt->vector_value("VM_NAME");
392

    
393
                    if (zname.empty())
394
                    {
395
                        zname = vatt->vector_value("DEPLOY_ID");
396
                    }
397

    
398
                    zombie << zname;
399
                }
400
            }
401
        }
402
        else if (rc == 0) //not ours
403
        {
404
            string wname;
405

    
406
            if (num_wilds++ > 0)
407
            {
408
                wild << ", ";
409
            }
410

    
411
            wname = vatt->vector_value("VM_NAME");
412

    
413
            if (wname.empty())
414
            {
415
                wname = vatt->vector_value("DEPLOY_ID");
416
            }
417

    
418
            wild << wname;
419
        }
420

    
421
        delete *it;
422
    }
423

    
424
    for(set_it = tmp_lost_vms.begin(); set_it != tmp_lost_vms.end(); set_it++)
425
    {
426
        // Reported as lost at least 2 times?
427
        if (prev_tmp_lost.count(*set_it) == 1)
428
        {
429
            lost.insert(*set_it);
430
        }
431
    }
432

    
433
    if (num_wilds > 0)
434
    {
435
        add_template_attribute("TOTAL_WILDS", num_wilds);
436
        add_template_attribute("WILDS", wild.str());
437
    }
438

    
439
    if (num_zombies > 0)
440
    {
441
        add_template_attribute("TOTAL_ZOMBIES", num_zombies);
442
        add_template_attribute("ZOMBIES", zombie.str());
443
    }
444

    
445
    // -------------------------------------------------------------------------
446
    // Copy system datastore monitorization (non_shared) to host share
447
    // -------------------------------------------------------------------------
448

    
449
    obj_template->remove("DS", ds_att);
450

    
451
    for (it = ds_att.begin(); it != ds_att.end(); it++)
452
    {
453
        int dsid;
454

    
455
        vatt = dynamic_cast<VectorAttribute*>(*it);
456

    
457
        if (vatt == 0)
458
        {
459
            delete *it;
460
            continue;
461
        }
462

    
463
        rc = vatt->vector_value("ID", dsid);
464

    
465
        if (rc == 0 && non_shared_ds.count(dsid) == 1)
466
        {
467
            local_ds_att.push_back(vatt);
468
        }
469
        else
470
        {
471
            delete *it;
472
        }
473
    }
474

    
475
    host_share.set_ds_monitorization(local_ds_att);
476

    
477
    return 0;
478
}
479

    
480
/* -------------------------------------------------------------------------- */
481
/* -------------------------------------------------------------------------- */
482

    
483
void Host::disable()
484
{
485
    state = DISABLED;
486

    
487
    host_share.max_cpu = 0;
488
    host_share.max_mem = 0;
489

    
490
    host_share.free_cpu = 0;
491
    host_share.free_mem = 0;
492

    
493
    host_share.used_cpu = 0;
494
    host_share.used_mem = 0;
495

    
496
    remove_template_attribute("TOTALCPU");
497
    remove_template_attribute("TOTALMEMORY");
498

    
499
    remove_template_attribute("FREECPU");
500
    remove_template_attribute("FREEMEMORY");
501

    
502
    remove_template_attribute("USEDCPU");
503
    remove_template_attribute("USEDMEMORY");
504
}
505

    
506
/* -------------------------------------------------------------------------- */
507
/* -------------------------------------------------------------------------- */
508

    
509
void Host::error_info(const string& message, set<int> &vm_ids)
510
{
511
    ostringstream oss;
512

    
513
    vm_ids = vm_collection.get_collection_copy();
514

    
515
    oss << "Error monitoring Host " << get_name() << " (" << get_oid() << ")"
516
        << ": " << message;
517

    
518
    NebulaLog::log("ONE", Log::ERROR, oss);
519

    
520
    touch(false);
521

    
522
    set_template_error_message(oss.str());
523
}
524

    
525
/* -------------------------------------------------------------------------- */
526
/* -------------------------------------------------------------------------- */
527

    
528
int Host::update_monitoring(SqlDB * db)
529
{
530
    ostringstream   oss;
531
    int             rc;
532

    
533
    string xml_body;
534
    string error_str;
535
    char * sql_xml;
536

    
537
    sql_xml = db->escape_str(to_xml(xml_body).c_str());
538

    
539
    if ( sql_xml == 0 )
540
    {
541
        goto error_body;
542
    }
543

    
544
    if ( validate_xml(sql_xml) != 0 )
545
    {
546
        goto error_xml;
547
    }
548

    
549
    oss << "REPLACE INTO " << monit_table << " ("<< monit_db_names <<") VALUES ("
550
        <<          oid             << ","
551
        <<          last_monitored       << ","
552
        << "'" <<   sql_xml         << "')";
553

    
554
    db->free_str(sql_xml);
555

    
556
    rc = db->exec(oss);
557

    
558
    return rc;
559

    
560
error_xml:
561
    db->free_str(sql_xml);
562

    
563
    error_str = "could not transform the Host to XML.";
564

    
565
    goto error_common;
566

    
567
error_body:
568
    error_str = "could not insert the Host in the DB.";
569

    
570
error_common:
571
    oss.str("");
572
    oss << "Error updating Host monitoring information, " << error_str;
573

    
574
    NebulaLog::log("ONE",Log::ERROR, oss);
575

    
576
    return -1;
577
}
578

    
579
/* ------------------------------------------------------------------------ */
580
/* ------------------------------------------------------------------------ */
581

    
582
bool Host::is_public_cloud() const
583
{
584
    bool is_public_cloud = false;
585

    
586
    get_template_attribute("PUBLIC_CLOUD", is_public_cloud);
587

    
588
    return is_public_cloud;
589
}
590

    
591
/* ************************************************************************ */
592
/* Host :: Misc                                                             */
593
/* ************************************************************************ */
594

    
595
string& Host::to_xml(string& xml) const
596
{
597
    string template_xml;
598
    string share_xml;
599

    
600
    ostringstream oss;
601
    string        vm_collection_xml;
602

    
603
    oss <<
604
    "<HOST>"
605
       "<ID>"               << oid              << "</ID>"              <<
606
       "<NAME>"             << name             << "</NAME>"            <<
607
       "<STATE>"            << state            << "</STATE>"           <<
608
       "<IM_MAD><![CDATA["  << im_mad_name      << "]]></IM_MAD>"       <<
609
       "<VM_MAD><![CDATA["  << vmm_mad_name     << "]]></VM_MAD>"       <<
610
       "<VN_MAD><![CDATA["  << vnm_mad_name     << "]]></VN_MAD>"       <<
611
       "<LAST_MON_TIME>"    << last_monitored   << "</LAST_MON_TIME>"   <<
612
       "<CLUSTER_ID>"       << cluster_id       << "</CLUSTER_ID>"      <<
613
       "<CLUSTER>"          << cluster          << "</CLUSTER>"         <<
614
       host_share.to_xml(share_xml)  <<
615
       vm_collection.to_xml(vm_collection_xml) <<
616
       obj_template->to_xml(template_xml) <<
617
    "</HOST>";
618

    
619
    xml = oss.str();
620

    
621
    return xml;
622
}
623

    
624
/* ------------------------------------------------------------------------ */
625
/* ------------------------------------------------------------------------ */
626

    
627
int Host::from_xml(const string& xml)
628
{
629
    vector<xmlNodePtr> content;
630

    
631
    int int_state;
632
    int rc = 0;
633

    
634
    // Initialize the internal XML object
635
    update_from_str(xml);
636

    
637
    // Get class base attributes
638
    rc += xpath(oid, "/HOST/ID", -1);
639
    rc += xpath(name, "/HOST/NAME", "not_found");
640
    rc += xpath(int_state, "/HOST/STATE", 0);
641

    
642
    rc += xpath(im_mad_name, "/HOST/IM_MAD", "not_found");
643
    rc += xpath(vmm_mad_name, "/HOST/VM_MAD", "not_found");
644
    rc += xpath(vnm_mad_name, "/HOST/VN_MAD", "not_found");
645

    
646
    rc += xpath(last_monitored, "/HOST/LAST_MON_TIME", 0);
647

    
648
    rc += xpath(cluster_id, "/HOST/CLUSTER_ID", -1);
649
    rc += xpath(cluster,    "/HOST/CLUSTER",    "not_found");
650

    
651
    state = static_cast<HostState>( int_state );
652

    
653
    // Set the owner and group to oneadmin
654
    set_user(0, "");
655
    set_group(GroupPool::ONEADMIN_ID, GroupPool::ONEADMIN_NAME);
656

    
657
    // ------------ Host Share ---------------
658

    
659
    ObjectXML::get_nodes("/HOST/HOST_SHARE", content);
660

    
661
    if (content.empty())
662
    {
663
        return -1;
664
    }
665

    
666
    rc += host_share.from_xml_node( content[0] );
667

    
668
    ObjectXML::free_nodes(content);
669

    
670
    content.clear();
671

    
672
    // ------------ Host Template ---------------
673

    
674
    ObjectXML::get_nodes("/HOST/TEMPLATE", content);
675

    
676
    if( content.empty())
677
    {
678
        return -1;
679
    }
680

    
681
    rc += obj_template->from_xml_node( content[0] );
682

    
683
    ObjectXML::free_nodes(content);
684

    
685
    content.clear();
686

    
687
    // ------------ VMS collection ---------------
688

    
689
    ObjectXML::get_nodes("/HOST/VMS", content);
690

    
691
    if (content.empty())
692
    {
693
        return -1;
694
    }
695

    
696
    rc += vm_collection.from_xml_node(content[0]);
697

    
698
    ObjectXML::free_nodes(content);
699

    
700
    if (rc != 0)
701
    {
702
        return -1;
703
    }
704

    
705
    return 0;
706
}
707

    
708

    
709
int Host::post_update_template(string& error)
710
{
711
    string vcenter_password;
712
    string new_im_mad;
713
    string new_vm_mad;
714
    string new_vn_mad;
715

    
716
    erase_template_attribute("VCENTER_PASSWORD", vcenter_password);
717

    
718
    if (!vcenter_password.empty())
719
    {
720
        Nebula& nd = Nebula::instance();
721
        string  one_key;
722
        string  * encrypted;
723

    
724
        nd.get_configuration_attribute("ONE_KEY", one_key);
725

    
726
        if (!one_key.empty())
727
        {
728
            encrypted = one_util::aes256cbc_encrypt(vcenter_password, one_key);
729

    
730
            add_template_attribute("VCENTER_PASSWORD", *encrypted);
731

    
732
            delete encrypted;
733
        }
734
        else
735
        {
736
            add_template_attribute("VCENTER_PASSWORD", vcenter_password);
737
        }
738
    }
739

    
740
    get_template_attribute("IM_MAD", new_im_mad);
741
    get_template_attribute("VM_MAD", new_vm_mad);
742
    get_template_attribute("VN_MAD", new_vn_mad);
743

    
744
    if (new_im_mad != ""){
745
        im_mad_name = new_im_mad;
746
    }
747

    
748
    if (new_im_mad != ""){
749
        vmm_mad_name = new_vm_mad;
750
    }
751

    
752
    if (new_im_mad != ""){
753
        vnm_mad_name = new_vn_mad;
754
    }
755

    
756
    replace_template_attribute("IM_MAD", im_mad_name);
757
    replace_template_attribute("VM_MAD", vmm_mad_name);
758
    replace_template_attribute("VN_MAD", vnm_mad_name);
759

    
760
    return 0;
761
};