Statistics
| Branch: | Tag: | Revision:

one / src / nebula / Nebula.cc @ 2d46c598

History | View | Annotate | Download (17.9 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 "Nebula.h"
18
#include "NebulaLog.h"
19
#include "VirtualMachine.h"
20
#include "SqliteDB.h"
21
#include "MySqlDB.h"
22

    
23
#include <stdlib.h>
24
#include <stdexcept>
25
#include <libxml/parser.h>
26

    
27
#include <signal.h>
28
#include <unistd.h>
29
#include <fcntl.h>
30
#include <sys/types.h>
31
#include <sys/stat.h>
32
#include <pthread.h>
33

    
34
using namespace std;
35

    
36
/* -------------------------------------------------------------------------- */
37
/* -------------------------------------------------------------------------- */
38

    
39
void Nebula::start()
40
{
41
    int             rc;
42
    int             fd;
43
    sigset_t        mask;
44
    int             signal;
45
    char            hn[80];
46
    string          scripts_remote_dir;
47

    
48
    if ( gethostname(hn,79) != 0 )
49
    {
50
        throw runtime_error("Error getting hostname");
51
    }
52

    
53
    hostname = hn;
54

    
55
    // -----------------------------------------------------------
56
    // Configuration
57
    // -----------------------------------------------------------
58

    
59
    nebula_configuration = new NebulaTemplate(etc_location, var_location);
60

    
61
    rc = nebula_configuration->load_configuration();
62

    
63
    if ( rc != 0 )
64
    {
65
        throw runtime_error("Could not load nebula configuration file.");
66
    }
67

    
68
    string   config_fname = var_location + "config";
69
    ofstream config_file(config_fname.c_str(), ios_base::trunc & ios_base::out);
70

    
71
    if (config_file.fail() == false)
72
    {
73
        config_file << *nebula_configuration << endl;
74
        config_file.close();
75
    }
76

    
77
    nebula_configuration->get("SCRIPTS_REMOTE_DIR", scripts_remote_dir);
78
    hook_location = scripts_remote_dir + "/hooks/";
79

    
80
    // -----------------------------------------------------------
81
    // Log system
82
    // -----------------------------------------------------------
83

    
84
    ostringstream os;
85

    
86
    try
87
    {
88
        string              log_fname;
89
        int                 log_level_int;
90
        Log::MessageType    clevel = Log::ERROR;
91

    
92
        log_fname = log_location + "oned.log";
93

    
94
        nebula_configuration->get("DEBUG_LEVEL", log_level_int);
95

    
96
        if (0 <= log_level_int && log_level_int <= 3 )
97
        {
98
            clevel = static_cast<Log::MessageType>(log_level_int);
99
        }
100

    
101
        // Initializing ONE Daemon log system
102

    
103
        NebulaLog::init_log_system(NebulaLog::FILE_TS,
104
                                   clevel,
105
                                   log_fname.c_str(),
106
                                   ios_base::trunc);
107

    
108
        NebulaLog::log("ONE",Log::INFO,"Init OpenNebula Log system");
109

    
110
        os << "Log Level: " << clevel << " [0=ERROR,1=WARNING,2=INFO,3=DEBUG]";
111

    
112
        NebulaLog::log("ONE",Log::INFO,os);
113
    }
114
    catch(runtime_error&)
115
    {
116
        throw;
117
    }
118

    
119

    
120
    NebulaLog::log("ONE",Log::INFO,"----------------------------------------");
121
    NebulaLog::log("ONE",Log::INFO,"     OpenNebula Configuration File      ");
122
    NebulaLog::log("ONE",Log::INFO,"----------------------------------------");
123

    
124
    os.str("");
125
    os << "\n----------------------------------\n";
126
    os << *nebula_configuration;
127
    os << "----------------------------------";
128

    
129
    NebulaLog::log("ONE",Log::INFO,os);
130

    
131
    // -----------------------------------------------------------
132
    // Initialize the XML library
133
    // -----------------------------------------------------------
134
    xmlInitParser();
135

    
136
    // -----------------------------------------------------------
137
    // Pools
138
    // -----------------------------------------------------------
139

    
140
    try
141
    {
142
        vector<const Attribute *> dbs;
143
        int  rc;
144

    
145
        bool   db_is_sqlite = true;
146

    
147
        string server  = "localhost";
148
        string port_str;
149
        int    port    = 0;
150
        string user    = "oneadmin";
151
        string passwd  = "oneadmin";
152
        string db_name = "opennebula";
153

    
154
        rc = nebula_configuration->get("DB", dbs);
155

    
156
        if ( rc != 0 )
157
        {
158
            string value;
159
            const  VectorAttribute * db = static_cast<const VectorAttribute *>
160
                                              (dbs[0]);
161
            value = db->vector_value("BACKEND");
162

    
163
            if (value == "mysql")
164
            {
165
                db_is_sqlite = false;
166

    
167
                value = db->vector_value("SERVER");
168
                if (!value.empty())
169
                {
170
                    server = value;
171
                }
172

    
173
                istringstream   is;
174

    
175
                port_str = db->vector_value("PORT");
176

    
177
                is.str(port_str);
178
                is >> port;
179

    
180
                if( is.fail() )
181
                {
182
                    port = 0;
183
                }
184

    
185
                value = db->vector_value("USER");
186
                if (!value.empty())
187
                {
188
                    user = value;
189
                }
190

    
191
                value = db->vector_value("PASSWD");
192
                if (!value.empty())
193
                {
194
                    passwd = value;
195
                }
196

    
197
                value = db->vector_value("DB_NAME");
198
                if (!value.empty())
199
                {
200
                    db_name = value;
201
                }
202
            }
203
        }
204

    
205
        if ( db_is_sqlite )
206
        {
207
            string  db_name = var_location + "one.db";
208

    
209
            db = new SqliteDB(db_name);
210
        }
211
        else
212
        {
213
            ostringstream   oss;
214

    
215
            db = new MySqlDB(server,port,user,passwd,db_name);
216

    
217
            oss << "CREATE DATABASE IF NOT EXISTS " << db_name;
218
            rc = db->exec(oss);
219

    
220
            if ( rc != 0 )
221
            {
222
                throw runtime_error("Could not create database.");
223
            }
224

    
225
            oss.str("");
226
            oss << "USE " << db_name;
227
            rc = db->exec(oss);
228
            if ( rc != 0 )
229
            {
230
                throw runtime_error("Could not open database.");
231
            }
232
        }
233

    
234
        NebulaLog::log("ONE",Log::INFO,"Checking database version.");
235
        rc = check_db_version();
236

    
237
        if( rc == -1 )
238
        {
239
            throw runtime_error("Database version mismatch.");
240
        }
241

    
242
        if( rc == -2 )
243
        {
244
            NebulaLog::log("ONE",Log::INFO,"Bootstraping OpenNebula database.");
245

    
246
            bootstrap();
247
            VirtualMachinePool::bootstrap(db);
248
            HostPool::bootstrap(db);
249
            VirtualNetworkPool::bootstrap(db);
250
            GroupPool::bootstrap(db);
251
            UserPool::bootstrap(db);
252
            ImagePool::bootstrap(db);
253
            VMTemplatePool::bootstrap(db);
254
            AclManager::bootstrap(db);
255
        }
256
    }
257
    catch (exception&)
258
    {
259
        throw;
260
    }
261

    
262
    try
263
    {
264
        string  mac_prefix;
265
        int     size;
266
        string  default_image_type;
267
        string  default_device_prefix;
268
        string  scripts_remote_dir;
269

    
270
        vector<const Attribute *> vm_hooks;
271
        vector<const Attribute *> host_hooks;
272

    
273
        nebula_configuration->get("VM_HOOK", vm_hooks);
274
        nebula_configuration->get("HOST_HOOK", host_hooks);
275

    
276
        vmpool = new VirtualMachinePool(db, vm_hooks, hook_location);
277
        hpool  = new HostPool(db, host_hooks, hook_location);
278

    
279
        nebula_configuration->get("MAC_PREFIX", mac_prefix);
280
        nebula_configuration->get("NETWORK_SIZE", size);
281

    
282
        vnpool = new VirtualNetworkPool(db,mac_prefix,size);
283

    
284
        gpool = new GroupPool(db);
285

    
286
        upool  = new UserPool(db);
287

    
288
        nebula_configuration->get("DEFAULT_IMAGE_TYPE", default_image_type);
289
        nebula_configuration->get("DEFAULT_DEVICE_PREFIX",
290
                                  default_device_prefix);
291

    
292
        ipool  = new ImagePool(db,
293
                               default_image_type,
294
                               default_device_prefix);
295

    
296
        tpool = new VMTemplatePool(db);
297
    }
298
    catch (exception&)
299
    {
300
        throw;
301
    }
302

    
303
    // -----------------------------------------------------------
304
    // Close stds, we no longer need them
305
    // -----------------------------------------------------------
306

    
307
    fd = open("/dev/null", O_RDWR);
308

    
309
    dup2(fd,0);
310
    dup2(fd,1);
311
    dup2(fd,2);
312

    
313
    close(fd);
314

    
315
    fcntl(0,F_SETFD,0); // Keep them open across exec funcs
316
    fcntl(1,F_SETFD,0);
317
    fcntl(2,F_SETFD,0);
318

    
319
    // -----------------------------------------------------------
320
    // Block all signals before creating any Nebula thread
321
    // -----------------------------------------------------------
322

    
323
    sigfillset(&mask);
324

    
325
    pthread_sigmask(SIG_BLOCK, &mask, NULL);
326

    
327
    // -----------------------------------------------------------
328
    //Managers
329
    // -----------------------------------------------------------
330

    
331
    MadManager::mad_manager_system_init();
332

    
333
    time_t timer_period;
334

    
335
    nebula_configuration->get("MANAGER_TIMER", timer_period);
336

    
337
    // ---- Virtual Machine Manager ----
338
    try
339
    {
340
        time_t                    poll_period;
341
        vector<const Attribute *> vmm_mads;
342

    
343
        nebula_configuration->get("VM_POLLING_INTERVAL", poll_period);
344

    
345
        nebula_configuration->get("VM_MAD", vmm_mads);
346

    
347
        vmm = new VirtualMachineManager(
348
            vmpool,
349
            hpool,
350
            timer_period,
351
            poll_period,
352
            vmm_mads);
353
    }
354
    catch (bad_alloc&)
355
    {
356
        throw;
357
    }
358

    
359
    rc = vmm->start();
360

    
361
    if ( rc != 0 )
362
    {
363
        throw runtime_error("Could not start the Virtual Machine Manager");
364
    }
365

    
366
    // ---- Life-cycle Manager ----
367
    try
368
    {
369
        lcm = new LifeCycleManager(vmpool,hpool);
370
    }
371
    catch (bad_alloc&)
372
    {
373
        throw;
374
    }
375

    
376
    rc = lcm->start();
377

    
378
    if ( rc != 0 )
379
    {
380
        throw runtime_error("Could not start the Life-cycle Manager");
381
    }
382

    
383
    // ---- Information Manager ----
384
    try
385
    {
386
        vector<const Attribute *>   im_mads;
387
        time_t                      monitor_period;
388

    
389
        nebula_configuration->get("HOST_MONITORING_INTERVAL", monitor_period);
390

    
391
        nebula_configuration->get("IM_MAD", im_mads);
392

    
393
        im = new InformationManager(hpool,
394
                                    timer_period,
395
                                    monitor_period,
396
                                    remotes_location,
397
                                    im_mads);
398
    }
399
    catch (bad_alloc&)
400
    {
401
        throw;
402
    }
403

    
404
    rc = im->start();
405

    
406
    if ( rc != 0 )
407
    {
408
        throw runtime_error("Could not start the Information Manager");
409
    }
410

    
411
    // ---- Transfer Manager ----
412
    try
413
    {
414
        vector<const Attribute *> tm_mads;
415

    
416
        nebula_configuration->get("TM_MAD", tm_mads);
417

    
418
        tm = new TransferManager(vmpool, hpool, tm_mads);
419
    }
420
    catch (bad_alloc&)
421
    {
422
        throw;
423
    }
424

    
425
    rc = tm->start();
426

    
427
    if ( rc != 0 )
428
    {
429
        throw runtime_error("Could not start the Transfer Manager");
430
    }
431

    
432
    // ---- Dispatch Manager ----
433
    try
434
    {
435
        dm = new DispatchManager(vmpool,hpool);
436
    }
437
    catch (bad_alloc&)
438
    {
439
        throw;
440
    }
441

    
442
    rc = dm->start();
443

    
444
    if ( rc != 0 )
445
    {
446
       throw runtime_error("Could not start the Dispatch Manager");
447
    }
448

    
449
    // ---- Hook Manager ----
450
    try
451
    {
452
        vector<const Attribute *> hm_mads;
453

    
454
        nebula_configuration->get("HM_MAD", hm_mads);
455

    
456
        hm = new HookManager(hm_mads,vmpool);
457
    }
458
    catch (bad_alloc&)
459
    {
460
        throw;
461
    }
462

    
463
    rc = hm->start();
464

    
465
    if ( rc != 0 )
466
    {
467
       throw runtime_error("Could not start the Hook Manager");
468
    }
469

    
470
    // ---- Auth Manager ----
471
    try
472
    {
473
        vector<const Attribute *> auth_mads;
474

    
475
        nebula_configuration->get("AUTH_MAD", auth_mads);
476

    
477
        if (!auth_mads.empty())
478
        {
479
            //Defaults 60s to timeout auth requests
480
            authm = new AuthManager(timer_period,60,auth_mads);
481
        }
482
        else
483
        {
484
            authm = 0; //Built-in authm/authz
485
        }
486
    }
487
    catch (bad_alloc&)
488
    {
489
        throw;
490
    }
491

    
492
    if (authm != 0)
493
    {
494
        rc = authm->start();
495

    
496
        if ( rc != 0 )
497
        {
498
          throw runtime_error("Could not start the Auth Manager");
499
        }
500
    }
501

    
502
    // ---- ACL Manager ----
503
    try
504
    {
505
        aclm = new AclManager(db);
506
    }
507
    catch (bad_alloc&)
508
    {
509
        throw;
510
    }
511

    
512
    rc = aclm->start();
513

    
514
    if ( rc != 0 )
515
    {
516
       throw runtime_error("Could not start the ACL Manager");
517
    }
518

    
519
    // ---- Image Manager ----
520
    try
521
    {
522
        vector<const Attribute *> image_mads;
523

    
524
        nebula_configuration->get("IMAGE_MAD", image_mads);
525

    
526
        imagem = new ImageManager(ipool,image_mads);
527
    }
528
    catch (bad_alloc&)
529
    {
530
        throw;
531
    }
532

    
533
    rc = imagem->start();
534

    
535
    if ( rc != 0 )
536
    {
537
       throw runtime_error("Could not start the Image Manager");
538
    }
539

    
540
    // ---- Request Manager ----
541
    try
542
    {
543
        int             rm_port = 0;
544

    
545
        nebula_configuration->get("PORT", rm_port);
546

    
547
        rm = new RequestManager(rm_port, log_location + "one_xmlrpc.log");
548
    }
549
    catch (bad_alloc&)
550
    {
551
        NebulaLog::log("ONE", Log::ERROR, "Error starting RM");
552
        throw;
553
    }
554

    
555
    rc = rm->start();
556

    
557
    if ( rc != 0 )
558
    {
559
       throw runtime_error("Could not start the Request Manager");
560
    }
561

    
562
    // -----------------------------------------------------------
563
    // Load mads
564
    // -----------------------------------------------------------
565

    
566
    sleep(2);
567

    
568
    vmm->load_mads(0);
569

    
570
    im->load_mads(0);
571
    tm->load_mads(0);
572
    hm->load_mads(0);
573
    imagem->load_mads(0);
574

    
575
    if ( authm != 0 )
576
    {
577
        authm->load_mads(0);
578
    }
579

    
580
    // -----------------------------------------------------------
581
    // Wait for a SIGTERM or SIGINT signal
582
    // -----------------------------------------------------------
583

    
584
    sigemptyset(&mask);
585

    
586
    sigaddset(&mask, SIGINT);
587
    sigaddset(&mask, SIGTERM);
588

    
589
    sigwait(&mask, &signal);
590

    
591
    // -----------------------------------------------------------
592
    // Stop the managers & free resources
593
    // -----------------------------------------------------------
594

    
595
    vmm->trigger(VirtualMachineManager::FINALIZE,0);
596
    lcm->trigger(LifeCycleManager::FINALIZE,0);
597

    
598
    tm->trigger(TransferManager::FINALIZE,0);
599
    dm->trigger(DispatchManager::FINALIZE,0);
600

    
601
    im->finalize();
602
    rm->finalize();
603
    hm->finalize();
604
    imagem->finalize();
605

    
606
    //sleep to wait drivers???
607

    
608
    pthread_join(vmm->get_thread_id(),0);
609
    pthread_join(lcm->get_thread_id(),0);
610
    pthread_join(tm->get_thread_id(),0);
611
    pthread_join(dm->get_thread_id(),0);
612

    
613
    pthread_join(im->get_thread_id(),0);
614
    pthread_join(rm->get_thread_id(),0);
615
    pthread_join(hm->get_thread_id(),0);
616
    pthread_join(imagem->get_thread_id(),0);
617

    
618
    //XML Library
619
    xmlCleanupParser();
620

    
621
    NebulaLog::log("ONE", Log::INFO, "All modules finalized, exiting.\n");
622
}
623

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

    
627
void Nebula::bootstrap()
628
{
629
    ostringstream   oss;
630

    
631
    oss <<  "CREATE TABLE pool_control (tablename VARCHAR(32) PRIMARY KEY, "
632
            "last_oid BIGINT UNSIGNED)";
633

    
634
    db->exec(oss);
635

    
636
    oss.str("");
637
    oss <<  "CREATE TABLE db_versioning (oid INTEGER PRIMARY KEY, "
638
            "version INTEGER, timestamp INTEGER, comment VARCHAR(256))";
639

    
640
    db->exec(oss);
641

    
642
    oss.str("");
643
    oss << "INSERT INTO db_versioning (oid, version, timestamp, comment) "
644
        << "VALUES (0, " << db_version() << ", " << time(0)
645
        << ", '" << version() << " daemon bootstrap')";
646

    
647
    db->exec(oss);
648
}
649

    
650
/* -------------------------------------------------------------------------- */
651
/* -------------------------------------------------------------------------- */
652

    
653
int Nebula::check_db_version()
654
{
655
    int             rc;
656
    ostringstream   oss;
657

    
658

    
659
    int loaded_db_version = 0;
660

    
661
    // Try to read latest version
662
    set_callback( static_cast<Callbackable::Callback>(&Nebula::select_cb),
663
                  static_cast<void *>(&loaded_db_version) );
664

    
665
    oss << "SELECT version FROM db_versioning "
666
        << "WHERE oid=(SELECT MAX(oid) FROM db_versioning)";
667

    
668
    db->exec(oss, this);
669

    
670
    oss.str("");
671
    unset_callback();
672

    
673
    if( loaded_db_version == 0 )
674
    {
675
        // Table user_pool is present for all OpenNebula versions, and it
676
        // always contains at least the oneadmin user.
677
        oss << "SELECT MAX(oid) FROM user_pool";
678
        rc = db->exec(oss);
679

    
680
        oss.str("");
681

    
682
        if( rc != 0 )   // Database needs bootstrap
683
        {
684
            return -2;
685
        }
686
    }
687

    
688
    if( db_version() != loaded_db_version )
689
    {
690
        oss << "Database version mismatch. "
691
            << "Installed " << version() << " uses DB version '" << db_version()
692
            << "', and existing DB version is '"
693
            << loaded_db_version << "'.";
694

    
695
        NebulaLog::log("ONE",Log::ERROR,oss);
696
        return -1;
697
    }
698

    
699
    return 0;
700
}
701

    
702
int Nebula::select_cb(void *_loaded_db_version, int num, char **values,
703
                      char **names)
704
{
705
    istringstream   iss;
706
    int *           loaded_db_version;
707

    
708
    loaded_db_version = static_cast<int *>(_loaded_db_version);
709

    
710
    *loaded_db_version = 0;
711

    
712
    if ( (values[0]) && (num == 1) )
713
    {
714
        iss.str(values[0]);
715
        iss >> *loaded_db_version;
716
    }
717

    
718
    return 0;
719
};