Statistics
| Branch: | Tag: | Revision:

one / src / image / Image.cc @ 4bf3dea1

History | View | Annotate | Download (15.2 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 <limits.h>
18
#include <string.h>
19

    
20
#include <iostream>
21
#include <sstream>
22
#include <openssl/evp.h>
23
#include <iomanip>
24

    
25
#include "Image.h"
26
#include "ImagePool.h"
27

    
28
#include "AuthManager.h"
29
#include "UserPool.h"
30

    
31
#define TO_UPPER(S) transform(S.begin(),S.end(),S.begin(),(int(*)(int))toupper)
32

    
33
/* ************************************************************************ */
34
/* Image :: Constructor/Destructor                                          */
35
/* ************************************************************************ */
36

    
37
Image::Image(int             _uid, 
38
             const string&   _user_name, 
39
             ImageTemplate * _image_template):
40
        PoolObjectSQL(-1,"",_uid,table),
41
        user_name(_user_name),
42
        type(OS),
43
        regtime(time(0)),
44
        source(""),
45
        state(INIT),
46
        running_vms(0)
47
{
48
    if (_image_template != 0)
49
    {
50
        obj_template = _image_template;
51
    }
52
    else
53
    {
54
        obj_template = new ImageTemplate;
55
    }
56
}
57

    
58
Image::~Image()
59
{
60
    if (obj_template != 0)
61
    {
62
        delete obj_template;
63
    }
64
}
65

    
66
/* ************************************************************************ */
67
/* Image :: Database Access Functions                                       */
68
/* ************************************************************************ */
69

    
70
const char * Image::table = "image_pool";
71

    
72
const char * Image::db_names = "oid, name, body, uid, public";
73

    
74
const char * Image::db_bootstrap = "CREATE TABLE IF NOT EXISTS image_pool ("
75
    "oid INTEGER PRIMARY KEY, name VARCHAR(256), body TEXT, uid INTEGER, "
76
    "public INTEGER, UNIQUE(name,uid) )";
77

    
78
/* ------------------------------------------------------------------------ */
79
/* ------------------------------------------------------------------------ */
80

    
81
string Image::generate_source(int uid, const string& name)
82
{
83
    ostringstream tmp_hashstream;
84
    ostringstream tmp_sourcestream;
85

    
86
    tmp_hashstream << uid << ":" << name;
87

    
88
    tmp_sourcestream << ImagePool::source_prefix() << "/";
89
    tmp_sourcestream << sha1_digest(tmp_hashstream.str());
90

    
91
    return tmp_sourcestream.str();
92
}
93

    
94
/* ------------------------------------------------------------------------ */
95
/* ------------------------------------------------------------------------ */
96

    
97
int Image::insert(SqlDB *db, string& error_str)
98
{
99
    int rc;
100

    
101
    string path_attr;
102
    string type_att;
103
    string public_attr;
104
    string persistent_attr;
105
    string dev_prefix;
106

    
107
    // ---------------------------------------------------------------------
108
    // Check default image attributes
109
    // ---------------------------------------------------------------------
110

    
111
    // ------------ NAME --------------------
112

    
113
    get_template_attribute("NAME", name);
114

    
115
    // ------------ TYPE --------------------
116

    
117
    get_template_attribute("TYPE", type_att);
118

    
119
    TO_UPPER(type_att);
120

    
121
    if ( type_att.empty() == true )
122
    {
123
        type_att = ImagePool::default_type();
124
    }
125

    
126
    if (set_type(type_att) != 0)
127
    {
128
        goto error_type;
129
    }
130

    
131
    // ------------ PUBLIC --------------------
132

    
133
    get_template_attribute("PUBLIC", public_attr);
134

    
135
    obj_template->erase("PUBLIC");
136

    
137
    TO_UPPER(public_attr);
138

    
139
    public_img = (public_attr == "YES");
140

    
141
    // ------------ PERSISTENT --------------------
142

    
143
    get_template_attribute("PERSISTENT", persistent_attr);
144

    
145
    obj_template->erase("PERSISTENT");
146

    
147
    TO_UPPER(persistent_attr);
148

    
149
    persistent_img = (persistent_attr == "YES");
150

    
151
    // An image cannot be public and persistent simultaneously
152

    
153
    if ( public_img && persistent_img )
154
    {
155
        goto error_public_and_persistent;
156
    }
157

    
158
    // ------------ PREFIX --------------------
159

    
160
    get_template_attribute("DEV_PREFIX", dev_prefix);
161

    
162
    if( dev_prefix.empty() )
163
    {
164
        SingleAttribute * dev_att = new SingleAttribute("DEV_PREFIX",
165
                                          ImagePool::default_dev_prefix());
166
        obj_template->set(dev_att);
167
    }
168

    
169
    // ------------ PATH & SOURCE --------------------
170

    
171
    get_template_attribute("PATH", path_attr);
172
    get_template_attribute("SOURCE", source);
173

    
174
    // The template should contain PATH or SOURCE
175
    if ( source.empty() && path_attr.empty() )
176
    {
177
        string size_attr;
178
        string fstype_attr;
179

    
180
        istringstream iss;
181
        int size_mb;
182

    
183
        get_template_attribute("SIZE",   size_attr);
184
        get_template_attribute("FSTYPE", fstype_attr);
185

    
186
        // DATABLOCK image needs SIZE and FSTYPE
187
        if (type != DATABLOCK || size_attr.empty() || fstype_attr.empty())
188
        {
189
            goto error_no_path;
190
        }
191

    
192
        iss.str(size_attr);
193

    
194
        iss >> size_mb;
195

    
196
        if (iss.fail() == true)
197
        {
198
            goto error_size_format;
199
        }
200
    }
201
    else if ( !source.empty() && !path_attr.empty() )
202
    {
203
        goto error_path_and_source;
204
    }
205

    
206
    if (source.empty())
207
    {
208
        source = Image::generate_source(uid,name);
209
    }
210

    
211
    state = LOCKED; //LOCKED till the ImageManager copies it to the Repository
212

    
213
    //--------------------------------------------------------------------------
214
    // Insert the Image
215
    //--------------------------------------------------------------------------
216

    
217
    rc = insert_replace(db, false);
218

    
219
    if ( rc == -1 )
220
    {
221
        error_str = "Error inserting Image in DB.";
222
    }
223

    
224
    return rc;
225

    
226
error_type:
227
    error_str = "Incorrect TYPE in template.";
228
    goto error_common;
229

    
230
error_public_and_persistent:
231
    error_str = "Image cannot be public and persistent.";
232
    goto error_common;
233

    
234
error_no_path:
235
    if ( type == DATABLOCK )
236
    {
237
        error_str = "A DATABLOCK type IMAGE has to declare a PATH, or both "
238
                    "SIZE and FSTYPE.";
239
    }
240
    else
241
    {
242
        error_str = "No PATH in template.";
243
    }
244
    goto error_common;
245

    
246
error_size_format:
247
    error_str = "Wrong number in SIZE.";
248
    goto error_common;
249

    
250
error_path_and_source:
251
    error_str = "Template malformed, PATH and SOURCE are mutuallly exclusive.";
252
    goto error_common;
253

    
254
error_common:
255
    NebulaLog::log("IMG", Log::ERROR, error_str);
256
    return -1;
257
}
258

    
259
/* ------------------------------------------------------------------------ */
260
/* ------------------------------------------------------------------------ */
261

    
262
int Image::update(SqlDB *db)
263
{
264
    return insert_replace(db, true);;
265
}
266

    
267
/* ------------------------------------------------------------------------ */
268
/* ------------------------------------------------------------------------ */
269

    
270
int Image::insert_replace(SqlDB *db, bool replace)
271
{
272
    ostringstream   oss;
273

    
274
    int    rc;
275

    
276
    string xml_body;
277

    
278
    char * sql_name;
279
    char * sql_xml;
280

    
281
    // Update the Image
282

    
283
    sql_name = db->escape_str(name.c_str());
284

    
285
    if ( sql_name == 0 )
286
    {
287
        goto error_name;
288
    }
289

    
290
    sql_xml = db->escape_str(to_xml(xml_body).c_str());
291

    
292
    if ( sql_xml == 0 )
293
    {
294
        goto error_body;
295
    }
296

    
297
    if(replace)
298
    {
299
        oss << "REPLACE";
300
    }
301
    else
302
    {
303
        oss << "INSERT";
304
    }
305

    
306
    // Construct the SQL statement to Insert or Replace
307

    
308
    oss <<" INTO "<< table <<" ("<< db_names <<") VALUES ("
309
        <<          oid             << ","
310
        << "'" <<   sql_name        << "',"
311
        << "'" <<   sql_xml         << "',"
312
        <<          uid             << ","
313
        <<          public_img      << ")";
314

    
315
    rc = db->exec(oss);
316

    
317
    db->free_str(sql_name);
318
    db->free_str(sql_xml);
319

    
320
    return rc;
321

    
322
error_body:
323
    db->free_str(sql_name);
324
error_name:
325
    return -1;
326
}
327

    
328
/* ************************************************************************ */
329
/* Image :: Misc                                                             */
330
/* ************************************************************************ */
331

    
332
ostream& operator<<(ostream& os, Image& image)
333
{
334
    string image_str;
335

    
336
    os << image.to_xml(image_str);
337

    
338
    return os;
339
}
340

    
341
/* ------------------------------------------------------------------------ */
342
/* ------------------------------------------------------------------------ */
343

    
344
string& Image::to_xml(string& xml) const
345
{
346
    string template_xml;
347
    ostringstream   oss;
348

    
349
    oss <<
350
        "<IMAGE>" <<
351
            "<ID>"             << oid             << "</ID>"          <<
352
            "<UID>"            << uid             << "</UID>"         <<
353
            "<USERNAME>"       << user_name       << "</USERNAME>"    <<
354
            "<NAME>"           << name            << "</NAME>"        <<
355
            "<TYPE>"           << type            << "</TYPE>"        <<
356
            "<PUBLIC>"         << public_img      << "</PUBLIC>"      <<
357
            "<PERSISTENT>"     << persistent_img  << "</PERSISTENT>"  <<
358
            "<REGTIME>"        << regtime         << "</REGTIME>"     <<
359
            "<SOURCE>"         << source          << "</SOURCE>"      <<
360
            "<STATE>"          << state           << "</STATE>"       <<
361
            "<RUNNING_VMS>"    << running_vms     << "</RUNNING_VMS>" <<
362
            obj_template->to_xml(template_xml)                      <<
363
        "</IMAGE>";
364

    
365
    xml = oss.str();
366

    
367
    return xml;
368
}
369

    
370
/* ------------------------------------------------------------------------ */
371
/* ------------------------------------------------------------------------ */
372

    
373
int Image::from_xml(const string& xml)
374
{
375
    vector<xmlNodePtr> content;
376
    int int_state;
377
    int int_type;
378

    
379
    int rc = 0;
380

    
381
    // Initialize the internal XML object
382
    update_from_str(xml);
383

    
384
    // Get class base attributes
385
    rc += xpath(oid, "/IMAGE/ID", -1);
386
    rc += xpath(uid, "/IMAGE/UID", -1);
387
    rc += xpath(user_name, "/IMAGE/USERNAME", "not_found");
388
    rc += xpath(name, "/IMAGE/NAME", "not_found");
389

    
390
    rc += xpath(int_type, "/IMAGE/TYPE", 0);
391
    rc += xpath(public_img, "/IMAGE/PUBLIC", 0);
392
    rc += xpath(persistent_img, "/IMAGE/PERSISTENT", 0);
393
    rc += xpath(regtime, "/IMAGE/REGTIME", 0);
394

    
395
    rc += xpath(source, "/IMAGE/SOURCE", "not_found");
396
    rc += xpath(int_state, "/IMAGE/STATE", 0);
397
    rc += xpath(running_vms, "/IMAGE/RUNNING_VMS", -1);
398

    
399
    type  = static_cast<ImageType>(int_type);
400
    state = static_cast<ImageState>(int_state);
401

    
402
    // Get associated classes
403
    ObjectXML::get_nodes("/IMAGE/TEMPLATE", content);
404
    if( content.size() < 1 )
405
    {
406
        return -1;
407
    }
408

    
409
    rc += obj_template->from_xml_node(content[0]);
410

    
411
    if (rc != 0)
412
    {
413
        return -1;
414
    }
415

    
416
    return 0;
417
}
418

    
419
/* ------------------------------------------------------------------------ */
420
/* ------------------------------------------------------------------------ */
421

    
422
int Image::disk_attribute(  VectorAttribute * disk,
423
                            int *             index,
424
                            ImageType*        img_type)
425
{
426
    string  bus;
427
    string  target;
428
    string  driver;
429

    
430
    ostringstream  iid;
431

    
432
    *img_type = type;
433
    bus       = disk->vector_value("BUS");
434
    target    = disk->vector_value("TARGET");
435
    driver    = disk->vector_value("DRIVER");
436
    iid << oid;
437

    
438
    string template_bus;
439
    string template_target;
440
    string prefix;
441
    string template_driver;
442

    
443
    get_template_attribute("BUS", template_bus);
444
    get_template_attribute("TARGET", template_target);
445
    get_template_attribute("DRIVER", template_driver);
446

    
447
    get_template_attribute("DEV_PREFIX", prefix);
448

    
449
   //---------------------------------------------------------------------------
450
   //                       BASE DISK ATTRIBUTES
451
   //---------------------------------------------------------------------------
452

    
453
    disk->replace("IMAGE",    name);
454
    disk->replace("IMAGE_ID", iid.str());
455
    disk->replace("SOURCE",   source);
456

    
457
    if (bus.empty() && !template_bus.empty()) //BUS in Image, not in DISK
458
    {
459
        disk->replace("BUS",template_bus);
460
    }
461

    
462
    if (driver.empty() && !template_driver.empty())//DRIVER in Image,not in DISK
463
    {
464
        disk->replace("DRIVER",template_driver);
465
    }
466

    
467
   //---------------------------------------------------------------------------
468
   //   TYPE, READONLY, CLONE, and SAVE attributes
469
   //---------------------------------------------------------------------------
470

    
471
    if ( persistent_img )
472
    {
473
        disk->replace("CLONE","NO");
474
        disk->replace("SAVE","YES");
475
    }
476
    else
477
    {
478
        disk->replace("CLONE","YES");
479
        disk->replace("SAVE","NO");
480
    }
481

    
482
    switch(type)
483
    {
484
        case OS:
485
        case DATABLOCK:
486
          disk->replace("TYPE","DISK");
487
          disk->replace("READONLY","NO");
488
        break;
489

    
490
        case CDROM:
491
          disk->replace("TYPE","CDROM");
492
          disk->replace("READONLY","YES");
493
        break;
494
    }
495

    
496
   //---------------------------------------------------------------------------
497
   //   TARGET attribute
498
   //---------------------------------------------------------------------------
499

    
500
    if (target.empty()) //No TARGET in DISK attribute
501
    {
502
        if (!template_target.empty())
503
        {
504
            disk->replace("TARGET", template_target);
505
        }
506
        else
507
        {
508
            switch(type)
509
            {
510
                case OS:
511
                    prefix += "a";
512
                break;
513

    
514
                case CDROM:
515
                    prefix += "c"; // b is for context
516
                break;
517

    
518
                case DATABLOCK:
519
                    prefix += static_cast<char>(('e'+ *index));
520
                    *index  = *index + 1;
521
                break;
522

    
523
            }
524

    
525
            disk->replace("TARGET", prefix);
526
        }
527
    }
528

    
529
    return 0;
530
}
531

    
532
/* -------------------------------------------------------------------------- */
533
/* -------------------------------------------------------------------------- */
534

    
535
string Image::sha1_digest(const string& pass)
536
{
537
    EVP_MD_CTX     mdctx;
538
    unsigned char  md_value[EVP_MAX_MD_SIZE];
539
    unsigned int   md_len;
540
    ostringstream  oss;
541

    
542
    EVP_MD_CTX_init(&mdctx);
543
    EVP_DigestInit_ex(&mdctx, EVP_sha1(), NULL);
544

    
545
    EVP_DigestUpdate(&mdctx, pass.c_str(), pass.length());
546

    
547
    EVP_DigestFinal_ex(&mdctx,md_value,&md_len);
548
    EVP_MD_CTX_cleanup(&mdctx);
549

    
550
    for(unsigned int i = 0; i<md_len; i++)
551
    {
552
        oss << setfill('0') << setw(2) << hex << nouppercase
553
            << (unsigned short) md_value[i];
554
    }
555

    
556
    return oss.str();
557
}
558

    
559
/* ------------------------------------------------------------------------ */
560
/* ------------------------------------------------------------------------ */