Statistics
| Branch: | Tag: | Revision:

one / src / image / Image.cc @ f2c04245

History | View | Annotate | Download (14 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
int Image::insert(SqlDB *db, string& error_str)
82
{
83
    int rc;
84

    
85
    string path_attr;
86
    string type_att;
87
    string public_attr;
88
    string persistent_attr;
89
    string dev_prefix;
90
    string source_attr;
91

    
92
    // ---------------------------------------------------------------------
93
    // Check default image attributes
94
    // ---------------------------------------------------------------------
95

    
96
    // ------------ NAME --------------------
97

    
98
    get_template_attribute("NAME", name);
99

    
100
    // ------------ TYPE --------------------
101

    
102
    get_template_attribute("TYPE", type_att);
103

    
104
    TO_UPPER(type_att);
105

    
106
    if ( type_att.empty() == true )
107
    {
108
        type_att = ImagePool::default_type();
109
    }
110

    
111
    if (set_type(type_att) != 0)
112
    {
113
        goto error_type;
114
    }
115

    
116
    // ------------ PUBLIC --------------------
117

    
118
    get_template_attribute("PUBLIC", public_attr);
119

    
120
    obj_template->erase("PUBLIC");
121

    
122
    TO_UPPER(public_attr);
123

    
124
    public_img = (public_attr == "YES");
125

    
126
    // ------------ PERSISTENT --------------------
127

    
128
    get_template_attribute("PERSISTENT", persistent_attr);
129

    
130
    obj_template->erase("PERSISTENT");
131

    
132
    TO_UPPER(persistent_attr);
133

    
134
    persistent_img = (persistent_attr == "YES");
135

    
136
    // An image cannot be public and persistent simultaneously
137

    
138
    if ( public_img && persistent_img )
139
    {
140
        goto error_public_and_persistent;
141
    }
142

    
143
    // ------------ PREFIX --------------------
144

    
145
    get_template_attribute("DEV_PREFIX", dev_prefix);
146

    
147
    if( dev_prefix.empty() )
148
    {
149
        SingleAttribute * dev_att = new SingleAttribute("DEV_PREFIX",
150
                                          ImagePool::default_dev_prefix());
151

    
152
        obj_template->set(dev_att);
153
    }
154

    
155
    // ------------ PATH & SOURCE --------------------
156

    
157
    get_template_attribute("PATH", path_attr);
158
    get_template_attribute("SOURCE", source_attr);
159

    
160
    // The template should contain PATH or SOURCE
161
    if ( source_attr.empty() && path_attr.empty() )
162
    {
163
        string size_attr;
164
        string fstype_attr;
165

    
166
        istringstream iss;
167
        int size_mb;
168

    
169
        get_template_attribute("SIZE",   size_attr);
170
        get_template_attribute("FSTYPE", fstype_attr);
171

    
172
        // DATABLOCK image needs SIZE and FSTYPE
173
        if (type != DATABLOCK || size_attr.empty() || fstype_attr.empty())
174
        {
175
            goto error_no_path;
176
        }
177

    
178
        iss.str(size_attr);
179

    
180
        iss >> size_mb;
181

    
182
        if (iss.fail() == true)
183
        {
184
            goto error_size_format;
185
        }
186
    }
187
    else if ( !source_attr.empty() && !path_attr.empty() )
188
    {
189
        goto error_path_and_source;
190
    }
191
    else if ( !source_attr.empty() )
192
    {
193
        source = source_attr;
194
    }
195

    
196
    state = LOCKED; //LOCKED till the ImageManager copies it to the Repository
197

    
198
    //--------------------------------------------------------------------------
199
    // Insert the Image
200
    //--------------------------------------------------------------------------
201

    
202
    rc = insert_replace(db, false);
203

    
204
    if ( rc == -1 )
205
    {
206
        error_str = "Error inserting Image in DB.";
207
    }
208

    
209
    return rc;
210

    
211
error_type:
212
    error_str = "Incorrect TYPE in template.";
213
    goto error_common;
214

    
215
error_public_and_persistent:
216
    error_str = "Image cannot be public and persistent.";
217
    goto error_common;
218

    
219
error_no_path:
220
    if ( type == DATABLOCK )
221
    {
222
        error_str = "A DATABLOCK type IMAGE has to declare a PATH, or both "
223
                    "SIZE and FSTYPE.";
224
    }
225
    else
226
    {
227
        error_str = "No PATH in template.";
228
    }
229
    goto error_common;
230

    
231
error_size_format:
232
    error_str = "Wrong number in SIZE.";
233
    goto error_common;
234

    
235
error_path_and_source:
236
    error_str = "Template malformed, PATH and SOURCE are mutuallly exclusive.";
237
    goto error_common;
238

    
239
error_common:
240
    NebulaLog::log("IMG", Log::ERROR, error_str);
241
    return -1;
242
}
243

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

    
247
int Image::update(SqlDB *db)
248
{
249
    return insert_replace(db, true);;
250
}
251

    
252
/* ------------------------------------------------------------------------ */
253
/* ------------------------------------------------------------------------ */
254

    
255
int Image::insert_replace(SqlDB *db, bool replace)
256
{
257
    ostringstream   oss;
258

    
259
    int    rc;
260

    
261
    string xml_body;
262

    
263
    char * sql_name;
264
    char * sql_xml;
265

    
266
    // Update the Image
267

    
268
    sql_name = db->escape_str(name.c_str());
269

    
270
    if ( sql_name == 0 )
271
    {
272
        goto error_name;
273
    }
274

    
275
    sql_xml = db->escape_str(to_xml(xml_body).c_str());
276

    
277
    if ( sql_xml == 0 )
278
    {
279
        goto error_body;
280
    }
281

    
282
    if(replace)
283
    {
284
        oss << "REPLACE";
285
    }
286
    else
287
    {
288
        oss << "INSERT";
289
    }
290

    
291
    // Construct the SQL statement to Insert or Replace
292

    
293
    oss <<" INTO "<< table <<" ("<< db_names <<") VALUES ("
294
        <<          oid             << ","
295
        << "'" <<   sql_name        << "',"
296
        << "'" <<   sql_xml         << "',"
297
        <<          uid             << ","
298
        <<          public_img      << ")";
299

    
300
    rc = db->exec(oss);
301

    
302
    db->free_str(sql_name);
303
    db->free_str(sql_xml);
304

    
305
    return rc;
306

    
307
error_body:
308
    db->free_str(sql_name);
309
error_name:
310
    return -1;
311
}
312

    
313
/* ************************************************************************ */
314
/* Image :: Misc                                                             */
315
/* ************************************************************************ */
316

    
317
ostream& operator<<(ostream& os, Image& image)
318
{
319
    string image_str;
320

    
321
    os << image.to_xml(image_str);
322

    
323
    return os;
324
}
325

    
326
/* ------------------------------------------------------------------------ */
327
/* ------------------------------------------------------------------------ */
328

    
329
string& Image::to_xml(string& xml) const
330
{
331
    string template_xml;
332
    ostringstream   oss;
333

    
334
    oss <<
335
        "<IMAGE>" <<
336
            "<ID>"             << oid             << "</ID>"          <<
337
            "<UID>"            << uid             << "</UID>"         <<
338
            "<USERNAME>"       << user_name       << "</USERNAME>"    <<
339
            "<NAME>"           << name            << "</NAME>"        <<
340
            "<TYPE>"           << type            << "</TYPE>"        <<
341
            "<PUBLIC>"         << public_img      << "</PUBLIC>"      <<
342
            "<PERSISTENT>"     << persistent_img  << "</PERSISTENT>"  <<
343
            "<REGTIME>"        << regtime         << "</REGTIME>"     <<
344
            "<SOURCE>"         << source          << "</SOURCE>"      <<
345
            "<STATE>"          << state           << "</STATE>"       <<
346
            "<RUNNING_VMS>"    << running_vms     << "</RUNNING_VMS>" <<
347
            obj_template->to_xml(template_xml)                      <<
348
        "</IMAGE>";
349

    
350
    xml = oss.str();
351

    
352
    return xml;
353
}
354

    
355
/* ------------------------------------------------------------------------ */
356
/* ------------------------------------------------------------------------ */
357

    
358
int Image::from_xml(const string& xml)
359
{
360
    vector<xmlNodePtr> content;
361
    int int_state;
362
    int int_type;
363

    
364
    int rc = 0;
365

    
366
    // Initialize the internal XML object
367
    update_from_str(xml);
368

    
369
    // Get class base attributes
370
    rc += xpath(oid, "/IMAGE/ID", -1);
371
    rc += xpath(uid, "/IMAGE/UID", -1);
372
    rc += xpath(user_name, "/IMAGE/USERNAME", "not_found");
373
    rc += xpath(name, "/IMAGE/NAME", "not_found");
374

    
375
    rc += xpath(int_type, "/IMAGE/TYPE", 0);
376
    rc += xpath(public_img, "/IMAGE/PUBLIC", 0);
377
    rc += xpath(persistent_img, "/IMAGE/PERSISTENT", 0);
378
    rc += xpath(regtime, "/IMAGE/REGTIME", 0);
379

    
380
    rc += xpath(source, "/IMAGE/SOURCE", "not_found");
381
    rc += xpath(int_state, "/IMAGE/STATE", 0);
382
    rc += xpath(running_vms, "/IMAGE/RUNNING_VMS", -1);
383

    
384
    type  = static_cast<ImageType>(int_type);
385
    state = static_cast<ImageState>(int_state);
386

    
387
    // Get associated classes
388
    ObjectXML::get_nodes("/IMAGE/TEMPLATE", content);
389
    if( content.size() < 1 )
390
    {
391
        return -1;
392
    }
393

    
394
    rc += obj_template->from_xml_node(content[0]);
395

    
396
    if (rc != 0)
397
    {
398
        return -1;
399
    }
400

    
401
    return 0;
402
}
403

    
404
/* ------------------------------------------------------------------------ */
405
/* ------------------------------------------------------------------------ */
406

    
407
int Image::disk_attribute(  VectorAttribute * disk,
408
                            int *             index,
409
                            ImageType*        img_type)
410
{
411
    string  bus;
412
    string  target;
413
    string  driver;
414

    
415
    ostringstream  iid;
416

    
417
    *img_type = type;
418
    bus       = disk->vector_value("BUS");
419
    target    = disk->vector_value("TARGET");
420
    driver    = disk->vector_value("DRIVER");
421
    iid << oid;
422

    
423
    string template_bus;
424
    string template_target;
425
    string prefix;
426
    string template_driver;
427

    
428
    get_template_attribute("BUS", template_bus);
429
    get_template_attribute("TARGET", template_target);
430
    get_template_attribute("DRIVER", template_driver);
431

    
432
    get_template_attribute("DEV_PREFIX", prefix);
433

    
434
   //---------------------------------------------------------------------------
435
   //                       BASE DISK ATTRIBUTES
436
   //---------------------------------------------------------------------------
437

    
438
    disk->replace("IMAGE",    name);
439
    disk->replace("IMAGE_ID", iid.str());
440
    disk->replace("SOURCE",   source);
441

    
442
    if (bus.empty() && !template_bus.empty()) //BUS in Image, not in DISK
443
    {
444
        disk->replace("BUS",template_bus);
445
    }
446

    
447
    if (driver.empty() && !template_driver.empty())//DRIVER in Image,not in DISK
448
    {
449
        disk->replace("DRIVER",template_driver);
450
    }
451

    
452
   //---------------------------------------------------------------------------
453
   //   TYPE, READONLY, CLONE, and SAVE attributes
454
   //---------------------------------------------------------------------------
455

    
456
    if ( persistent_img )
457
    {
458
        disk->replace("CLONE","NO");
459
        disk->replace("SAVE","YES");
460
    }
461
    else
462
    {
463
        disk->replace("CLONE","YES");
464
        disk->replace("SAVE","NO");
465
    }
466

    
467
    switch(type)
468
    {
469
        case OS:
470
        case DATABLOCK:
471
          disk->replace("TYPE","DISK");
472
          disk->replace("READONLY","NO");
473
        break;
474

    
475
        case CDROM:
476
          disk->replace("TYPE","CDROM");
477
          disk->replace("READONLY","YES");
478
        break;
479
    }
480

    
481
   //---------------------------------------------------------------------------
482
   //   TARGET attribute
483
   //---------------------------------------------------------------------------
484

    
485
    if (target.empty()) //No TARGET in DISK attribute
486
    {
487
        if (!template_target.empty())
488
        {
489
            disk->replace("TARGET", template_target);
490
        }
491
        else
492
        {
493
            switch(type)
494
            {
495
                case OS:
496
                    prefix += "a";
497
                break;
498

    
499
                case CDROM:
500
                    prefix += "c"; // b is for context
501
                break;
502

    
503
                case DATABLOCK:
504
                    prefix += static_cast<char>(('e'+ *index));
505
                    *index  = *index + 1;
506
                break;
507

    
508
            }
509

    
510
            disk->replace("TARGET", prefix);
511
        }
512
    }
513

    
514
    return 0;
515
}
516

    
517
/* ------------------------------------------------------------------------ */
518
/* ------------------------------------------------------------------------ */