Statistics
| Branch: | Tag: | Revision:

one / src / nebula / Nebula.cc @ bfaabf35

History | View | Annotate | Download (17.5 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

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

    
52
    hostname = hn;
53

    
54
    // -----------------------------------------------------------
55
    // Configuration
56
    // -----------------------------------------------------------
57

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

    
60
    rc = nebula_configuration->load_configuration();
61

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

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

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

    
76
    // -----------------------------------------------------------
77
    // Log system
78
    // -----------------------------------------------------------
79

    
80
    ostringstream os;
81

    
82
    try
83
    {
84
        string              log_fname;
85
        int                 log_level_int;
86
        Log::MessageType    clevel = Log::ERROR;
87

    
88
        log_fname = log_location + "oned.log";
89

    
90
        nebula_configuration->get("DEBUG_LEVEL", log_level_int);
91

    
92
        if (0 <= log_level_int && log_level_int <= 3 )
93
        {
94
            clevel = static_cast<Log::MessageType>(log_level_int);
95
        }
96

    
97
        // Initializing ONE Daemon log system
98

    
99
        NebulaLog::init_log_system(NebulaLog::FILE_TS,
100
                                   clevel,
101
                                   log_fname.c_str(),
102
                                   ios_base::trunc);
103

    
104
        NebulaLog::log("ONE",Log::INFO,"Init OpenNebula Log system");
105

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

    
108
        NebulaLog::log("ONE",Log::INFO,os);
109
    }
110
    catch(runtime_error&)
111
    {
112
        throw;
113
    }
114

    
115

    
116
    NebulaLog::log("ONE",Log::INFO,"----------------------------------------");
117
    NebulaLog::log("ONE",Log::INFO,"     OpenNebula Configuration File      ");
118
    NebulaLog::log("ONE",Log::INFO,"----------------------------------------");
119

    
120
    os.str("");
121
    os << "\n----------------------------------\n";
122
    os << *nebula_configuration;
123
    os << "----------------------------------";
124

    
125
    NebulaLog::log("ONE",Log::INFO,os);
126

    
127
    // -----------------------------------------------------------
128
    // Initialize the XML library
129
    // -----------------------------------------------------------
130
    xmlInitParser();
131

    
132
    // -----------------------------------------------------------
133
    // Pools
134
    // -----------------------------------------------------------
135

    
136
    try
137
    {
138
        vector<const Attribute *> dbs;
139
        int  rc;
140

    
141
        bool   db_is_sqlite = true;
142

    
143
        string server  = "localhost";
144
        string port_str;
145
        int    port    = 0;
146
        string user    = "oneadmin";
147
        string passwd  = "oneadmin";
148
        string db_name = "opennebula";
149

    
150
        rc = nebula_configuration->get("DB", dbs);
151

    
152
        if ( rc != 0 )
153
        {
154
            string value;
155
            const  VectorAttribute * db = static_cast<const VectorAttribute *>
156
                                              (dbs[0]);
157
            value = db->vector_value("BACKEND");
158

    
159
            if (value == "mysql")
160
            {
161
                db_is_sqlite = false;
162

    
163
                value = db->vector_value("SERVER");
164
                if (!value.empty())
165
                {
166
                    server = value;
167
                }
168

    
169
                istringstream   is;
170

    
171
                port_str = db->vector_value("PORT");
172

    
173
                is.str(port_str);
174
                is >> port;
175

    
176
                if( is.fail() )
177
                {
178
                    port = 0;
179
                }
180

    
181
                value = db->vector_value("USER");
182
                if (!value.empty())
183
                {
184
                    user = value;
185
                }
186

    
187
                value = db->vector_value("PASSWD");
188
                if (!value.empty())
189
                {
190
                    passwd = value;
191
                }
192

    
193
                value = db->vector_value("DB_NAME");
194
                if (!value.empty())
195
                {
196
                    db_name = value;
197
                }
198
            }
199
        }
200

    
201
        if ( db_is_sqlite )
202
        {
203
            string  db_name = var_location + "one.db";
204

    
205
            db = new SqliteDB(db_name);
206
        }
207
        else
208
        {
209
            ostringstream   oss;
210

    
211
            db = new MySqlDB(server,port,user,passwd,db_name);
212

    
213
            oss << "CREATE DATABASE IF NOT EXISTS " << db_name;
214
            rc = db->exec(oss);
215

    
216
            if ( rc != 0 )
217
            {
218
                throw runtime_error("Could not create database.");
219
            }
220

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

    
230
        NebulaLog::log("ONE",Log::INFO,"Checking database version.");
231
        rc = check_db_version();
232

    
233
        if( rc == -1 )
234
        {
235
            throw runtime_error("Database version mismatch.");
236
        }
237

    
238
        if( rc == -2 )
239
        {
240
            NebulaLog::log("ONE",Log::INFO,"Bootstraping OpenNebula database.");
241

    
242
            bootstrap();
243
            VirtualMachinePool::bootstrap(db);
244
            HostPool::bootstrap(db);
245
            VirtualNetworkPool::bootstrap(db);
246
            GroupPool::bootstrap(db);
247
            UserPool::bootstrap(db);
248
            ImagePool::bootstrap(db);
249
            VMTemplatePool::bootstrap(db);
250
        }
251
    }
252
    catch (exception&)
253
    {
254
        throw;
255
    }
256

    
257
    try
258
    {
259
        string  mac_prefix;
260
        int     size;
261
        string  default_image_type;
262
        string  default_device_prefix;
263

    
264
        vector<const Attribute *> vm_hooks;
265
        vector<const Attribute *> host_hooks;
266

    
267
        nebula_configuration->get("VM_HOOK", vm_hooks);
268
        nebula_configuration->get("HOST_HOOK", host_hooks);
269

    
270
        vmpool = new VirtualMachinePool(db, vm_hooks, hook_location);
271
        hpool  = new HostPool(db, host_hooks, hook_location);
272

    
273
        nebula_configuration->get("MAC_PREFIX", mac_prefix);
274
        nebula_configuration->get("NETWORK_SIZE", size);
275

    
276
        vnpool = new VirtualNetworkPool(db,mac_prefix,size);
277

    
278
        gpool = new GroupPool(db);
279

    
280
        upool  = new UserPool(db);
281

    
282
        nebula_configuration->get("DEFAULT_IMAGE_TYPE", default_image_type);
283
        nebula_configuration->get("DEFAULT_DEVICE_PREFIX",
284
                                  default_device_prefix);
285

    
286
        ipool  = new ImagePool(db,
287
                               default_image_type,
288
                               default_device_prefix);
289

    
290
        tpool = new VMTemplatePool(db);
291
    }
292
    catch (exception&)
293
    {
294
        throw;
295
    }
296

    
297
    // -----------------------------------------------------------
298
    // Close stds, we no longer need them
299
    // -----------------------------------------------------------
300

    
301
    fd = open("/dev/null", O_RDWR);
302

    
303
    dup2(fd,0);
304
    dup2(fd,1);
305
    dup2(fd,2);
306

    
307
    close(fd);
308

    
309
    fcntl(0,F_SETFD,0); // Keep them open across exec funcs
310
    fcntl(1,F_SETFD,0);
311
    fcntl(2,F_SETFD,0);
312

    
313
    // -----------------------------------------------------------
314
    // Block all signals before creating any Nebula thread
315
    // -----------------------------------------------------------
316

    
317
    sigfillset(&mask);
318

    
319
    pthread_sigmask(SIG_BLOCK, &mask, NULL);
320

    
321
    // -----------------------------------------------------------
322
    //Managers
323
    // -----------------------------------------------------------
324

    
325
    MadManager::mad_manager_system_init();
326

    
327
    time_t timer_period;
328

    
329
    nebula_configuration->get("MANAGER_TIMER", timer_period);
330

    
331
    // ---- Virtual Machine Manager ----
332
    try
333
    {
334
        time_t                    poll_period;
335
        vector<const Attribute *> vmm_mads;
336

    
337
        nebula_configuration->get("VM_POLLING_INTERVAL", poll_period);
338

    
339
        nebula_configuration->get("VM_MAD", vmm_mads);
340

    
341
        vmm = new VirtualMachineManager(
342
            vmpool,
343
            hpool,
344
            timer_period,
345
            poll_period,
346
            vmm_mads);
347
    }
348
    catch (bad_alloc&)
349
    {
350
        throw;
351
    }
352

    
353
    rc = vmm->start();
354

    
355
    if ( rc != 0 )
356
    {
357
        throw runtime_error("Could not start the Virtual Machine Manager");
358
    }
359

    
360
    // ---- Life-cycle Manager ----
361
    try
362
    {
363
        lcm = new LifeCycleManager(vmpool,hpool);
364
    }
365
    catch (bad_alloc&)
366
    {
367
        throw;
368
    }
369

    
370
    rc = lcm->start();
371

    
372
    if ( rc != 0 )
373
    {
374
        throw runtime_error("Could not start the Life-cycle Manager");
375
    }
376

    
377
    // ---- Information Manager ----
378
    try
379
    {
380
        vector<const Attribute *>   im_mads;
381
        time_t                      monitor_period;
382

    
383
        nebula_configuration->get("HOST_MONITORING_INTERVAL", monitor_period);
384

    
385
        nebula_configuration->get("IM_MAD", im_mads);
386

    
387
        im = new InformationManager(hpool,
388
                                    timer_period,
389
                                    monitor_period,
390
                                    remotes_location,
391
                                    im_mads);
392
    }
393
    catch (bad_alloc&)
394
    {
395
        throw;
396
    }
397

    
398
    rc = im->start();
399

    
400
    if ( rc != 0 )
401
    {
402
        throw runtime_error("Could not start the Information Manager");
403
    }
404

    
405
    // ---- Transfer Manager ----
406
    try
407
    {
408
        vector<const Attribute *> tm_mads;
409

    
410
        nebula_configuration->get("TM_MAD", tm_mads);
411

    
412
        tm = new TransferManager(vmpool, hpool, tm_mads);
413
    }
414
    catch (bad_alloc&)
415
    {
416
        throw;
417
    }
418

    
419
    rc = tm->start();
420

    
421
    if ( rc != 0 )
422
    {
423
        throw runtime_error("Could not start the Transfer Manager");
424
    }
425

    
426
    // ---- Dispatch Manager ----
427
    try
428
    {
429
        dm = new DispatchManager(vmpool,hpool);
430
    }
431
    catch (bad_alloc&)
432
    {
433
        throw;
434
    }
435

    
436
    rc = dm->start();
437

    
438
    if ( rc != 0 )
439
    {
440
       throw runtime_error("Could not start the Dispatch Manager");
441
    }
442

    
443
    // ---- Request Manager ----
444
    try
445
    {
446
        int             rm_port = 0;
447

    
448
        nebula_configuration->get("PORT", rm_port);
449

    
450
        rm = new RequestManager(rm_port, log_location + "one_xmlrpc.log");
451
    }
452
    catch (bad_alloc&)
453
    {
454
        NebulaLog::log("ONE", Log::ERROR, "Error starting RM");
455
        throw;
456
    }
457

    
458
    rc = rm->start();
459

    
460
    if ( rc != 0 )
461
    {
462
       throw runtime_error("Could not start the Request Manager");
463
    }
464

    
465
    // ---- Hook Manager ----
466
    try
467
    {
468
        vector<const Attribute *> hm_mads;
469

    
470
        nebula_configuration->get("HM_MAD", hm_mads);
471

    
472
        hm = new HookManager(hm_mads,vmpool);
473
    }
474
    catch (bad_alloc&)
475
    {
476
        throw;
477
    }
478

    
479
    rc = hm->start();
480

    
481
    if ( rc != 0 )
482
    {
483
       throw runtime_error("Could not start the Hook Manager");
484
    }
485

    
486
    // ---- Auth Manager ----
487
    try
488
    {
489
        vector<const Attribute *> auth_mads;
490

    
491
        nebula_configuration->get("AUTH_MAD", auth_mads);
492

    
493
        if (!auth_mads.empty())
494
        {
495
            //Defaults 60s to timeout auth requests
496
            authm = new AuthManager(timer_period,60,auth_mads);
497
        }
498
        else
499
        {
500
            authm = 0; //Built-in authm/authz
501
        }
502
    }
503
    catch (bad_alloc&)
504
    {
505
        throw;
506
    }
507

    
508
    if (authm != 0)
509
    {
510
        rc = authm->start();
511

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

    
518
    // ---- ACL Manager ----
519
    aclm = new AclManager();
520

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

    
526
        nebula_configuration->get("IMAGE_MAD", image_mads);
527

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

    
535
    rc = imagem->start();
536

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

    
542
    // -----------------------------------------------------------
543
    // Load mads
544
    // -----------------------------------------------------------
545

    
546
    sleep(2);
547

    
548
    vmm->load_mads(0);
549

    
550
    im->load_mads(0);
551
    tm->load_mads(0);
552
    hm->load_mads(0);
553
    imagem->load_mads(0);
554

    
555
    if ( authm != 0 )
556
    {
557
        authm->load_mads(0);
558
    }
559

    
560
    // -----------------------------------------------------------
561
    // Wait for a SIGTERM or SIGINT signal
562
    // -----------------------------------------------------------
563

    
564
    sigemptyset(&mask);
565

    
566
    sigaddset(&mask, SIGINT);
567
    sigaddset(&mask, SIGTERM);
568

    
569
    sigwait(&mask, &signal);
570

    
571
    // -----------------------------------------------------------
572
    // Stop the managers & free resources
573
    // -----------------------------------------------------------
574

    
575
    vmm->trigger(VirtualMachineManager::FINALIZE,0);
576
    lcm->trigger(LifeCycleManager::FINALIZE,0);
577

    
578
    tm->trigger(TransferManager::FINALIZE,0);
579
    dm->trigger(DispatchManager::FINALIZE,0);
580

    
581
    im->finalize();
582
    rm->finalize();
583
    hm->finalize();
584
    imagem->finalize();
585

    
586
    //sleep to wait drivers???
587

    
588
    pthread_join(vmm->get_thread_id(),0);
589
    pthread_join(lcm->get_thread_id(),0);
590
    pthread_join(tm->get_thread_id(),0);
591
    pthread_join(dm->get_thread_id(),0);
592

    
593
    pthread_join(im->get_thread_id(),0);
594
    pthread_join(rm->get_thread_id(),0);
595
    pthread_join(hm->get_thread_id(),0);
596
    pthread_join(imagem->get_thread_id(),0);
597

    
598
    //XML Library
599
    xmlCleanupParser();
600

    
601
    NebulaLog::log("ONE", Log::INFO, "All modules finalized, exiting.\n");
602
}
603

    
604
/* -------------------------------------------------------------------------- */
605
/* -------------------------------------------------------------------------- */
606

    
607
void Nebula::bootstrap()
608
{
609
    ostringstream   oss;
610

    
611
    oss <<  "CREATE TABLE pool_control (tablename VARCHAR(32) PRIMARY KEY, "
612
            "last_oid BIGINT UNSIGNED)";
613

    
614
    db->exec(oss);
615

    
616
    oss.str("");
617
    oss <<  "CREATE TABLE db_versioning (oid INTEGER PRIMARY KEY, "
618
            "version INTEGER, timestamp INTEGER, comment VARCHAR(256))";
619

    
620
    db->exec(oss);
621

    
622
    oss.str("");
623
    oss << "INSERT INTO db_versioning (oid, version, timestamp, comment) "
624
        << "VALUES (0, " << db_version() << ", " << time(0)
625
        << ", '" << version() << " daemon bootstrap')";
626

    
627
    db->exec(oss);
628
}
629

    
630
/* -------------------------------------------------------------------------- */
631
/* -------------------------------------------------------------------------- */
632

    
633
int Nebula::check_db_version()
634
{
635
    int             rc;
636
    ostringstream   oss;
637

    
638

    
639
    int loaded_db_version = 0;
640

    
641
    // Try to read latest version
642
    set_callback( static_cast<Callbackable::Callback>(&Nebula::select_cb),
643
                  static_cast<void *>(&loaded_db_version) );
644

    
645
    oss << "SELECT version FROM db_versioning "
646
        << "WHERE oid=(SELECT MAX(oid) FROM db_versioning)";
647

    
648
    db->exec(oss, this);
649

    
650
    oss.str("");
651
    unset_callback();
652

    
653
    if( loaded_db_version == 0 )
654
    {
655
        // Table user_pool is present for all OpenNebula versions, and it
656
        // always contains at least the oneadmin user.
657
        oss << "SELECT MAX(oid) FROM user_pool";
658
        rc = db->exec(oss);
659

    
660
        oss.str("");
661

    
662
        if( rc != 0 )   // Database needs bootstrap
663
        {
664
            return -2;
665
        }
666
    }
667

    
668
    if( db_version() != loaded_db_version )
669
    {
670
        oss << "Database version mismatch. "
671
            << "Installed " << version() << " uses DB version '" << db_version()
672
            << "', and existing DB version is '"
673
            << loaded_db_version << "'.";
674

    
675
        NebulaLog::log("ONE",Log::ERROR,oss);
676
        return -1;
677
    }
678

    
679
    return 0;
680
}
681

    
682
int Nebula::select_cb(void *_loaded_db_version, int num, char **values,
683
                      char **names)
684
{
685
    istringstream   iss;
686
    int *           loaded_db_version;
687

    
688
    loaded_db_version = static_cast<int *>(_loaded_db_version);
689

    
690
    *loaded_db_version = 0;
691

    
692
    if ( (values[0]) && (num == 1) )
693
    {
694
        iss.str(values[0]);
695
        iss >> *loaded_db_version;
696
    }
697

    
698
    return 0;
699
};