Statistics
| Branch: | Tag: | Revision:

one / src / vmm / LibVirtDriverKVM.cc @ e050429a

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 "LibVirtDriver.h"
18

    
19
#include "Nebula.h"
20
#include <sstream>
21
#include <fstream>
22
#include <libgen.h>
23

    
24
int LibVirtDriver::deployment_description_kvm(
25
        const VirtualMachine *  vm,
26
        const string&           file_name) const
27
{
28
    ofstream                    file;
29

    
30
    int                         num;
31
    vector<const Attribute *>   attrs;
32

    
33
    string  vcpu;
34
    string  memory;
35

    
36
    int     memory_in_kb = 0;
37

    
38
    string  emulator_path = "";
39

    
40
    string  kernel     = "";
41
    string  initrd     = "";
42
    string  boot       = "";
43
    string  root       = "";
44
    string  kernel_cmd = "";
45
    string  bootloader = "";
46
    string  arch       = "";
47

    
48
    const VectorAttribute * disk;
49
    const VectorAttribute * context;
50

    
51
    string  type       = "";
52
    string  target     = "";
53
    string  bus        = "";
54
    string  ro         = "";
55
    string  driver     = "";
56
    string  default_driver = "";
57
    bool    readonly;
58

    
59
    const VectorAttribute * nic;
60

    
61
    string  mac        = "";
62
    string  bridge     = "";
63
    string  script     = "";
64
    string  model      = "";
65
    string  ip         = "";
66
    string  filter     = "";
67
    string  default_filter = "";
68

    
69
    const VectorAttribute * graphics;
70

    
71
    string  listen     = "";
72
    string  port       = "";
73
    string  passwd     = "";
74
    string  keymap     = "";
75

    
76
    const VectorAttribute * input;
77

    
78
    const VectorAttribute * features;
79

    
80
    string     pae     = "";
81
    string     acpi    = "";
82

    
83
    const VectorAttribute * raw;
84
    string data;
85

    
86
    // ------------------------------------------------------------------------
87

    
88
    file.open(file_name.c_str(), ios::out);
89

    
90
    if (file.fail() == true)
91
    {
92
        goto error_file;
93
    }
94

    
95
    // ------------------------------------------------------------------------
96
    // Starting XML document
97
    // ------------------------------------------------------------------------
98

    
99
    file << "<domain type='" << emulator << "'>" << endl;
100

    
101
    // ------------------------------------------------------------------------
102
    // Domain name
103
    // ------------------------------------------------------------------------
104

    
105
    file << "\t<name>one-" << vm->get_oid() << "</name>" << endl;
106

    
107
    // ------------------------------------------------------------------------
108
    // CPU
109
    // ------------------------------------------------------------------------
110

    
111
    vm->get_template_attribute("VCPU", vcpu);
112

    
113
    if(vcpu.empty())
114
    {
115
        get_default("VCPU", vcpu);
116
    }
117

    
118
    if (!vcpu.empty())
119
    {
120
        file << "\t<vcpu>" << vcpu << "</vcpu>" << endl;
121
    }
122

    
123
    // ------------------------------------------------------------------------
124
    // Memory
125
    // ------------------------------------------------------------------------
126

    
127
    vm->get_template_attribute("MEMORY",memory);
128

    
129
    if (memory.empty())
130
    {
131
        get_default("MEMORY",memory);
132
    }
133

    
134
    if (!memory.empty())
135
    {
136
        memory_in_kb = atoi(memory.c_str()) * 1024;
137

    
138
        file << "\t<memory>" << memory_in_kb << "</memory>" << endl;
139
    }
140
    else
141
    {
142
        goto error_memory;
143
    }
144

    
145
    // ------------------------------------------------------------------------
146
    //  OS and boot options
147
    // ------------------------------------------------------------------------
148

    
149
    file << "\t<os>" << endl;
150

    
151
    num = vm->get_template_attribute("OS",attrs);
152

    
153
    // Get values & defaults
154

    
155
    if ( num > 0 )
156
    {
157
        const VectorAttribute * os;
158

    
159
        os = dynamic_cast<const VectorAttribute *>(attrs[0]);
160

    
161
        if( os != 0 )
162
        {
163
            kernel     = os->vector_value("KERNEL");
164
            initrd     = os->vector_value("INITRD");
165
            boot       = os->vector_value("BOOT");
166
            root       = os->vector_value("ROOT");
167
            kernel_cmd = os->vector_value("KERNEL_CMD");
168
            bootloader = os->vector_value("BOOTLOADER");
169
            arch       = os->vector_value("ARCH");
170
        }
171
    }
172

    
173
    if ( arch.empty() )
174
    {
175
        get_default("OS","ARCH",arch);
176

    
177
        if ( arch.empty() )
178
        {
179
            goto error_arch;
180
        }
181
    }
182

    
183
    if (emulator == "kvm")
184
    {
185
        file << "\t\t<type arch='" << arch << "'>hvm</type>" << endl;
186
    }
187

    
188
    if ( kernel.empty() )
189
    {
190
        get_default("OS","KERNEL",kernel);
191
    }
192

    
193
    if ( initrd.empty() )
194
    {
195
        get_default("OS","INITRD",initrd);
196
    }
197

    
198
    if ( bootloader.empty() )
199
    {
200
        get_default("OS","BOOTLOADER",bootloader);
201
    }
202

    
203
    if ( boot.empty() )
204
    {
205
        get_default("OS","BOOT",boot);
206

    
207
        if ( boot.empty() )
208
        {
209
            goto error_boot;
210
        }
211
    }
212

    
213
    if ( root.empty() )
214
    {
215
        get_default("OS","ROOT",root);
216
    }
217

    
218
    if ( kernel_cmd.empty() )
219
    {
220
        get_default("OS","KERNEL_CMD",kernel_cmd);
221
    }
222

    
223
    // Start writing to the file with the info we got
224

    
225
    if ( !kernel.empty() )
226
    {
227
        file << "\t\t<kernel>" << kernel << "</kernel>" << endl;
228

    
229
        if ( !initrd.empty() )
230
        {
231
            file << "\t\t<initrd>" << initrd << "</initrd>" << endl;
232
        }
233

    
234
        if ( !root.empty() )
235
        {
236
            kernel_cmd = "root=/dev/" + root + " " + kernel_cmd;
237
        }
238

    
239
        if (!kernel_cmd.empty())
240
        {
241
            file << "\t\t<cmdline>" << kernel_cmd << "</cmdline>" << endl;
242
        }
243
    }
244
    else if ( !bootloader.empty() )
245
    {
246
        file << "\t\t<bootloader>" << bootloader << "</bootloader>" << endl;
247
    }
248

    
249

    
250
    file << "\t\t<boot dev='" << boot << "'/>" << endl;
251

    
252
    file << "\t</os>" << endl;
253

    
254
    attrs.clear();
255

    
256
    // ------------------------------------------------------------------------
257
    // Disks
258
    // ------------------------------------------------------------------------
259

    
260
    file << "\t<devices>" << endl;
261

    
262
    if (emulator == "kvm")
263
    {
264
        get_default("EMULATOR",emulator_path);
265

    
266
        if(emulator_path.empty())
267
        {
268
            emulator_path = "/usr/bin/kvm";
269
        }
270

    
271
        file << "\t\t<emulator>" << emulator_path << "</emulator>" << endl;
272
    }
273

    
274
    get_default("DISK","DRIVER",default_driver);
275

    
276
    if (default_driver.empty())
277
    {
278
        default_driver = "raw";
279
    }
280

    
281
    num = vm->get_template_attribute("DISK",attrs);
282

    
283
    for (int i=0; i < num ;i++)
284
    {
285
        disk = dynamic_cast<const VectorAttribute *>(attrs[i]);
286

    
287
        if ( disk == 0 )
288
        {
289
         continue;
290
        }
291

    
292
        type   = disk->vector_value("TYPE");
293
        target = disk->vector_value("TARGET");
294
        ro     = disk->vector_value("READONLY");
295
        bus    = disk->vector_value("BUS");
296
        driver = disk->vector_value("DRIVER");
297

    
298
        if (target.empty())
299
        {
300
            goto error_disk;
301
        }
302

    
303
        readonly = false;
304

    
305
        if ( !ro.empty() )
306
        {
307
            transform(ro.begin(),ro.end(),ro.begin(),(int(*)(int))toupper);
308

    
309
            if ( ro == "YES" )
310
            {
311
                readonly = true;
312
            }
313
        }
314

    
315
        // ---- Disk type and source for the image ----
316

    
317
        if (type.empty() == false)
318
        {
319
            transform(type.begin(),type.end(),type.begin(),(int(*)(int))toupper);
320
        }
321

    
322
        if ( type == "BLOCK" )
323
        {
324
            file << "\t\t<disk type='block' device='disk'>" << endl
325
                 << "\t\t\t<source dev='" << vm->get_remote_dir() << "/disk."
326
                 << i << "'/>" << endl;
327
        }
328
        else if ( type == "CDROM" )
329
        {
330
            file << "\t\t<disk type='file' device='cdrom'>" << endl
331
                 << "\t\t\t<source file='" << vm->get_remote_dir() << "/disk."
332
                 << i << "'/>" << endl;
333
        }
334
        else
335
        {
336
            file << "\t\t<disk type='file' device='disk'>" << endl
337
                 << "\t\t\t<source file='" << vm->get_remote_dir() << "/disk."
338
                 << i << "'/>" << endl;
339
        }
340

    
341
        // ---- target device to map the disk ----
342

    
343
        file << "\t\t\t<target dev='" << target << "'";
344

    
345
        // ---- bus ----
346

    
347
        if (!bus.empty())
348
        {
349
            file << " bus='" << bus << "'/>" << endl;
350
        }
351
        else
352
        {
353
            file << "/>" << endl;
354
        }
355

    
356
        // ---- readonly attribute for the disk ----
357

    
358
        if (readonly)
359
        {
360
            file << "\t\t\t<readonly/>" << endl;
361
        }
362

    
363
        // ---- Image Format using qemu driver ----
364

    
365
        file << "\t\t\t<driver name='qemu' type='";
366

    
367
        if ( !driver.empty() )
368
        {
369
            file << driver << "'/>" << endl;
370
        }
371
        else
372
        {
373
            file << default_driver << "'/>" << endl;
374
        }
375

    
376
        file << "\t\t</disk>" << endl;
377
    }
378

    
379
    attrs.clear();
380

    
381
    // ------------------------------------------------------------------------
382
    // Context Device
383
    // ------------------------------------------------------------------------
384

    
385
    if ( vm->get_template_attribute("CONTEXT",attrs) == 1 )
386
    {
387
        context = dynamic_cast<const VectorAttribute *>(attrs[0]);
388
        target  = context->vector_value("TARGET");
389
        driver  = context->vector_value("DRIVER");
390

    
391
        if ( !target.empty() )
392
        {
393
            file << "\t\t<disk type='file' device='cdrom'>" << endl;
394
            file << "\t\t\t<source file='" << vm->get_remote_dir() << "/disk."
395
                 << num << "'/>" << endl;
396
            file << "\t\t\t<target dev='" << target << "'/>" << endl;
397
            file << "\t\t\t<readonly/>" << endl;
398

    
399
            file << "\t\t\t<driver name='qemu' type='";
400

    
401
            if ( !driver.empty() )
402
            {
403
                file << driver << "'/>" << endl;
404
            }
405
            else
406
            {
407
                file << default_driver << "'/>" << endl;
408
            }
409

    
410
            file << "\t\t</disk>" << endl;
411
        }
412
        else
413
        {
414
            vm->log("VMM", Log::WARNING, "Could not find target device to"
415
                " attach context, will continue without it.");
416
        }
417
    }
418

    
419
    attrs.clear();
420

    
421
    // ------------------------------------------------------------------------
422
    // Network interfaces
423
    // ------------------------------------------------------------------------
424

    
425
    get_default("NIC","FILTER",default_filter);
426

    
427
    num = vm->get_template_attribute("NIC",attrs);
428

    
429
    for(int i=0; i<num; i++)
430
    {
431
        nic = dynamic_cast<const VectorAttribute *>(attrs[i]);
432

    
433
        if ( nic == 0 )
434
        {
435
            continue;
436
        }
437

    
438
        bridge = nic->vector_value("BRIDGE");
439
        mac    = nic->vector_value("MAC");
440
        target = nic->vector_value("TARGET");
441
        script = nic->vector_value("SCRIPT");
442
        model  = nic->vector_value("MODEL");
443
        ip     = nic->vector_value("IP");
444
        filter = nic->vector_value("FILTER");
445

    
446
        if ( bridge.empty() )
447
        {
448
            file << "\t\t<interface type='ethernet'>" << endl;
449
        }
450
        else
451
        {
452
            file << "\t\t<interface type='bridge'>" << endl;
453
            file << "\t\t\t<source bridge='" << bridge << "'/>" << endl;
454
        }
455

    
456
        if( !mac.empty() )
457
        {
458
            file << "\t\t\t<mac address='" << mac << "'/>" << endl;
459
        }
460

    
461
        if( !target.empty() )
462
        {
463
            file << "\t\t\t<target dev='" << target << "'/>" << endl;
464
        }
465

    
466
        if( !script.empty() )
467
        {
468
            file << "\t\t\t<script path='" << script << "'/>" << endl;
469
        }
470

    
471
        if( !model.empty() )
472
        {
473
            file << "\t\t\t<model type='" << model << "'/>" << endl;
474
        }
475

    
476
        if (!ip.empty() )
477
        {
478
            string * the_filter = 0;
479

    
480
            if (!filter.empty())
481
            {
482
                the_filter = &filter;
483
            } 
484
            else if (!default_filter.empty())
485
            {
486
                the_filter = &default_filter;
487
            }
488

    
489
            if ( the_filter != 0 )
490
            {
491
                file <<"\t\t\t<filterref filter='"<< *the_filter <<"'/>"<<endl;
492
                file << "\t\t\t\t<parameter name='IP' value='" 
493
                     << ip << "'/>" << endl;
494
                file << "\t\t\t</filterref>" << endl; 
495
            }
496
        }
497

    
498
        file << "\t\t</interface>" << endl;
499
    }
500

    
501
    attrs.clear();
502

    
503
    // ------------------------------------------------------------------------
504
    // Graphics
505
    // ------------------------------------------------------------------------
506

    
507
    if ( vm->get_template_attribute("GRAPHICS",attrs) > 0 )
508
    {
509
        graphics = dynamic_cast<const VectorAttribute *>(attrs[0]);
510

    
511
        if ( graphics != 0 )
512
        {
513
            type   = graphics->vector_value("TYPE");
514
            listen = graphics->vector_value("LISTEN");
515
            port   = graphics->vector_value("PORT");
516
            passwd = graphics->vector_value("PASSWD");
517
            keymap = graphics->vector_value("KEYMAP");
518

    
519
            if ( type == "vnc" || type == "VNC" )
520
            {
521
                file << "\t\t<graphics type='vnc'";
522

    
523
                if ( !listen.empty() )
524
                {
525
                    file << " listen='" << listen << "'";
526
                }
527

    
528
                if ( !port.empty() )
529
                {
530
                    file << " port='" << port << "'";
531
                }
532

    
533
                if ( !passwd.empty() )
534
                {
535
                    file << " passwd='" << passwd << "'";
536
                }
537

    
538
                if ( !keymap.empty() )
539
                {
540
                    file << " keymap='" << keymap << "'";
541
                }
542

    
543
                file << "/>" << endl;
544
            }
545
            else
546
            {
547
                vm->log("VMM", Log::WARNING,
548
                        "Not supported graphics type, ignored.");
549
            }
550
        }
551
    }
552

    
553
    attrs.clear();
554

    
555
    // ------------------------------------------------------------------------
556
    // Input
557
    // ------------------------------------------------------------------------
558

    
559
    if ( vm->get_template_attribute("INPUT",attrs) > 0 )
560
    {
561
        input = dynamic_cast<const VectorAttribute *>(attrs[0]);
562

    
563
        if ( input != 0 )
564
        {
565
            type = input->vector_value("TYPE");
566
            bus  = input->vector_value("BUS");
567

    
568
            if ( !type.empty() )
569
            {
570
                file << "\t\t<input type='" << type << "'";
571

    
572
                if ( !bus.empty() )
573
                {
574
                    file << " bus='" << bus << "'";
575
                }
576

    
577
                file << "/>" << endl;
578
            }
579
        }
580
    }
581

    
582
    attrs.clear();
583

    
584
    file << "\t</devices>" << endl;
585

    
586
    // ------------------------------------------------------------------------
587
    // Features
588
    // ------------------------------------------------------------------------
589

    
590
    num = vm->get_template_attribute("FEATURES",attrs);
591

    
592
    if ( num > 0 )
593
    {
594
        features = dynamic_cast<const VectorAttribute *>(attrs[0]);
595

    
596
        if ( features != 0 )
597
        {
598
            pae  = features->vector_value("PAE");
599
            acpi = features->vector_value("ACPI");
600
        }
601
    }
602

    
603
    if ( pae.empty() )
604
    {
605
        get_default("FEATURES", "PAE", pae);
606
    }
607

    
608
    if ( acpi.empty() )
609
    {
610
        get_default("FEATURES", "ACPI", acpi);
611
    }
612

    
613
    if( acpi == "yes" || pae == "yes" )
614
    {
615
        file << "\t<features>" << endl;
616

    
617
        if ( pae == "yes" )
618
        {
619
            file << "\t\t<pae/>" << endl;
620
        }
621

    
622
        if ( acpi == "yes" )
623
        {
624
            file << "\t\t<acpi/>" << endl;
625
        }
626

    
627
        file << "\t</features>" << endl;
628
    }
629

    
630
    attrs.clear();
631

    
632
    // ------------------------------------------------------------------------
633
    // Raw KVM attributes
634
    // ------------------------------------------------------------------------
635

    
636
    num = vm->get_template_attribute("RAW",attrs);
637

    
638
    for(int i=0; i<num;i++)
639
    {
640
        raw = dynamic_cast<const VectorAttribute *>(attrs[i]);
641

    
642
        if ( raw == 0 )
643
        {
644
            continue;
645
        }
646

    
647
        type = raw->vector_value("TYPE");
648

    
649
        transform(type.begin(),type.end(),type.begin(),(int(*)(int))toupper);
650

    
651
        if ( type == "KVM" )
652
        {
653
            data = raw->vector_value("DATA");
654
            file << "\t" << data << endl;
655
        }
656
    }
657

    
658
    file << "</domain>" << endl;
659

    
660
    file.close();
661

    
662
    return 0;
663

    
664
error_file:
665
    vm->log("VMM", Log::ERROR, "Could not open KVM deployment file.");
666
    return -1;
667

    
668
error_memory:
669
    vm->log("VMM", Log::ERROR, "No MEMORY defined and no default provided.");
670
    file.close();
671
    return -1;
672

    
673
error_arch:
674
    vm->log("VMM", Log::ERROR, "No ARCH defined and no default provided.");
675
    file.close();
676
    return -1;
677

    
678
error_boot:
679
    vm->log("VMM", Log::ERROR, "No BOOT device defined and no default provided.");
680
    file.close();
681
    return -1;
682

    
683
error_disk:
684
    vm->log("VMM", Log::ERROR, "Wrong target value in DISK.");
685
    file.close();
686
    return -1;
687
}