~ubuntu-branches/ubuntu/raring/eucalyptus/raring

« back to all changes in this revision

Viewing changes to storage/backing.c

  • Committer: Package Import Robot
  • Author(s): Brian Thomason
  • Date: 2011-11-29 13:17:52 UTC
  • mfrom: (1.2.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 185.
  • Revision ID: package-import@ubuntu.com-20111129131752-rq31al3ntutv2vvl
Tags: upstream-3.0.999beta1
ImportĀ upstreamĀ versionĀ 3.0.999beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- mode: C; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-
 
2
// vim: set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
 
3
 
 
4
/*
 
5
  Copyright (c) 2009  Eucalyptus Systems, Inc.
 
6
 
 
7
  This program is free software: you can redistribute it and/or modify
 
8
  it under the terms of the GNU General Public License as published by
 
9
  the Free Software Foundation, only version 3 of the License.
 
10
 
 
11
  This file is distributed in the hope that it will be useful, but WITHOUT
 
12
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
13
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
14
  for more details.
 
15
 
 
16
  You should have received a copy of the GNU General Public License along
 
17
  with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
 
 
19
  Please contact Eucalyptus Systems, Inc., 130 Castilian
 
20
  Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/>
 
21
  if you need additional information or have any questions.
 
22
 
 
23
  This file may incorporate work covered under the following copyright and
 
24
  permission notice:
 
25
 
 
26
  Software License Agreement (BSD License)
 
27
 
 
28
  Copyright (c) 2008, Regents of the University of California
 
29
 
 
30
 
 
31
  Redistribution and use of this software in source and binary forms, with
 
32
  or without modification, are permitted provided that the following
 
33
  conditions are met:
 
34
 
 
35
  Redistributions of source code must retain the above copyright notice,
 
36
  this list of conditions and the following disclaimer.
 
37
 
 
38
  Redistributions in binary form must reproduce the above copyright
 
39
  notice, this list of conditions and the following disclaimer in the
 
40
  documentation and/or other materials provided with the distribution.
 
41
 
 
42
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 
43
  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 
44
  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 
45
  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 
46
  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
47
  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
48
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
49
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 
50
  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
51
  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
52
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
 
53
  THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
 
54
  LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
 
55
  SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
 
56
  IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
 
57
  BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
 
58
  THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
 
59
  OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
 
60
  WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
 
61
  ANY SUCH LICENSES OR RIGHTS.
 
62
*/
 
63
 
 
64
#include <stdio.h>
 
65
#include <stdlib.h>
 
66
#include <unistd.h>
 
67
#include <string.h>
 
68
#include <sys/types.h>
 
69
#include <sys/stat.h>
 
70
#include <stdarg.h>
 
71
#include <fcntl.h>
 
72
#include <errno.h>
 
73
#include <limits.h>
 
74
#include <assert.h>
 
75
#include <dirent.h>
 
76
#include "misc.h" // logprintfl, ensure_...
 
77
#include "data.h" // ncInstance
 
78
#include "diskutil.h"
 
79
#include "eucalyptus.h"
 
80
#include "blobstore.h"
 
81
#include "walrus.h"
 
82
#include "storage-windows.h"
 
83
#include "handlers.h" // nc_state
 
84
#include "backing.h"
 
85
#include "iscsi.h"
 
86
#include "vbr.h"
 
87
#include "ipc.h" // sem
 
88
 
 
89
#define CACHE_TIMEOUT_USEC  1000000LL*60*60*2 
 
90
#define STORE_TIMEOUT_USEC  1000000LL*60*2
 
91
#define DELETE_TIMEOUT_USEC 1000000LL*10
 
92
#define FIND_TIMEOUT_USEC   50000LL // TODO: use 1000LL or less to induce rare timeouts
 
93
 
 
94
static char instances_path [MAX_PATH];
 
95
static blobstore * cache_bs = NULL;
 
96
static blobstore * work_bs = NULL;
 
97
static sem * disk_sem = NULL;
 
98
 
 
99
extern struct nc_state_t nc_state;
 
100
 
 
101
static void bs_errors (const char * msg) { 
 
102
    // we normally do not care to print all messages from blobstore as many are errors that we can handle
 
103
    logprintfl (EUCADEBUG2, "{%u} blobstore: %s", (unsigned int)pthread_self(), msg);
 
104
 
105
 
 
106
static void stat_blobstore (const char * conf_instances_path, const char * name, blobstore_meta * meta)
 
107
{
 
108
    bzero (meta, sizeof (blobstore_meta));
 
109
    char path [MAX_PATH]; 
 
110
    snprintf (path, sizeof (path), "%s/%s", conf_instances_path, name);
 
111
    blobstore * bs = blobstore_open (path, 
 
112
                                     0, // any size
 
113
                                     0, // no flags = do not create it
 
114
                                     BLOBSTORE_FORMAT_ANY, 
 
115
                                     BLOBSTORE_REVOCATION_ANY, 
 
116
                                     BLOBSTORE_SNAPSHOT_ANY);
 
117
    if (bs == NULL)
 
118
        return;
 
119
    blobstore_stat (bs, meta);
 
120
    blobstore_close (bs);
 
121
}
 
122
 
 
123
static int stale_blob_examiner (const blockblob * bb);
 
124
static bunchOfInstances ** instances = NULL;
 
125
 
 
126
int check_backing_store (bunchOfInstances ** global_instances)
 
127
{
 
128
    instances = global_instances;
 
129
 
 
130
    if (work_bs) {
 
131
        if (blobstore_fsck (work_bs, stale_blob_examiner)) {
 
132
            logprintfl (EUCAERROR, "ERROR: work directory failed integrity check: %s\n", blobstore_get_error_str(blobstore_get_error()));
 
133
            blobstore_close (cache_bs);
 
134
            return ERROR;
 
135
        }
 
136
    }
 
137
    if (cache_bs) {
 
138
        if (blobstore_fsck (cache_bs, NULL)) { // TODO: verify checksums?
 
139
            logprintfl (EUCAERROR, "ERROR: cache failed integrity check: %s\n", blobstore_get_error_str(blobstore_get_error()));
 
140
            return ERROR;
 
141
        }
 
142
    }
 
143
    return OK;
 
144
}
 
145
 
 
146
void stat_backing_store (const char * conf_instances_path, blobstore_meta * work_meta, blobstore_meta * cache_meta)
 
147
{
 
148
    assert (conf_instances_path);
 
149
    stat_blobstore (conf_instances_path, "work",  work_meta);
 
150
    stat_blobstore (conf_instances_path, "cache", cache_meta);
 
151
}
 
152
 
 
153
int init_backing_store (const char * conf_instances_path, unsigned int conf_work_size_mb, unsigned int conf_cache_size_mb)
 
154
{
 
155
    logprintfl (EUCAINFO, "initializing backing store...\n");
 
156
 
 
157
    if (conf_instances_path == NULL) {
 
158
        logprintfl (EUCAERROR, "error: INSTANCE_PATH not specified\n");
 
159
        return ERROR;
 
160
    }
 
161
    safe_strncpy (instances_path, conf_instances_path, sizeof (instances_path));
 
162
    if (check_directory (instances_path)) {
 
163
            logprintfl (EUCAERROR, "error: INSTANCE_PATH (%s) does not exist!\n", instances_path);
 
164
        return ERROR;
 
165
    }
 
166
    char cache_path [MAX_PATH]; snprintf (cache_path, sizeof (cache_path), "%s/cache", instances_path);
 
167
    if (ensure_directories_exist (cache_path, 0, NULL, NULL, BACKING_DIRECTORY_PERM) == -1) return ERROR;
 
168
    char work_path [MAX_PATH];  snprintf (work_path,  sizeof (work_path),  "%s/work", instances_path);
 
169
    if (ensure_directories_exist (work_path, 0, NULL, NULL, BACKING_DIRECTORY_PERM) == -1) return ERROR;
 
170
    unsigned long long cache_limit_blocks = conf_cache_size_mb * 2048; // convert MB to blocks
 
171
    unsigned long long work_limit_blocks  = conf_work_size_mb * 2048;
 
172
    if (work_limit_blocks==0) { // we take 0 as unlimited
 
173
        work_limit_blocks = ULLONG_MAX;
 
174
    }
 
175
 
 
176
    blobstore_set_error_function ( &bs_errors );
 
177
    if (cache_limit_blocks) {
 
178
        cache_bs = blobstore_open (cache_path, cache_limit_blocks, BLOBSTORE_FLAG_CREAT, BLOBSTORE_FORMAT_DIRECTORY, BLOBSTORE_REVOCATION_LRU, BLOBSTORE_SNAPSHOT_ANY);
 
179
        if (cache_bs==NULL) {
 
180
            logprintfl (EUCAERROR, "ERROR: failed to open/create cache blobstore: %s\n", blobstore_get_error_str(blobstore_get_error()));
 
181
            return ERROR;
 
182
        }
 
183
    }
 
184
    work_bs = blobstore_open (work_path, work_limit_blocks, BLOBSTORE_FLAG_CREAT, BLOBSTORE_FORMAT_FILES, BLOBSTORE_REVOCATION_NONE, BLOBSTORE_SNAPSHOT_ANY);
 
185
    if (work_bs==NULL) {
 
186
        logprintfl (EUCAERROR, "ERROR: failed to open/create work blobstore: %s\n", blobstore_get_error_str(blobstore_get_error()));
 
187
        logprintfl (EUCAERROR, "ERROR: %s\n", blobstore_get_last_trace());
 
188
        blobstore_close (cache_bs);
 
189
        return ERROR;
 
190
    }
 
191
 
 
192
    // set the initial value of the semaphore to the number of 
 
193
    // disk-intensive operations that can run in parallel on this node
 
194
    if (nc_state.concurrent_disk_ops && (disk_sem = sem_alloc (nc_state.concurrent_disk_ops, "mutex")) == NULL) {
 
195
        logprintfl (EUCAERROR, "failed to create and initialize disk semaphore\n");
 
196
        return ERROR;
 
197
    }
 
198
 
 
199
    return OK;
 
200
}
 
201
 
 
202
// sets id to:
 
203
// - the blockblob ID of an instance-directory blob (if vbr!=NULL): userId/instanceId/blob-....
 
204
// - the work prefix within work blobstore for an instance: userId/instanceId
 
205
static void set_id (const ncInstance * instance, virtualBootRecord * vbr, char * id, unsigned int id_size) // TODO: remove this
 
206
{
 
207
    assert (id);
 
208
    assert (instance);
 
209
    assert (strlen (instance->userId));
 
210
    assert (strlen (instance->instanceId));
 
211
    
 
212
    char suffix [1024] = "";
 
213
    if (vbr) {
 
214
        assert (vbr);
 
215
        assert (strlen (vbr->typeName));
 
216
    
 
217
        snprintf (id, id_size, "/blob-%s-%s",
 
218
                  vbr->typeName, 
 
219
                  (vbr->type==NC_RESOURCE_KERNEL||vbr->type==NC_RESOURCE_RAMDISK)?(vbr->id):(vbr->guestDeviceName));
 
220
    }
 
221
    snprintf (id, id_size, "%s/%s%s", instance->userId, instance->instanceId, suffix);
 
222
}
 
223
 
 
224
// sets id to:
 
225
// - the work prefix within work blobstore for an instance: userId/instanceId(suffix)
 
226
static void set_id2 (const ncInstance * instance, const char * suffix, char * id, unsigned int id_size)
 
227
{
 
228
    assert (id);
 
229
    assert (instance);
 
230
    assert (strlen (instance->userId));
 
231
    assert (strlen (instance->instanceId));
 
232
    snprintf (id, id_size, "%s/%s%s", instance->userId, instance->instanceId, (suffix)?(suffix):(""));
 
233
}
 
234
 
 
235
// sets path to 
 
236
// - the path of a file in an instance directory (if filename!=NULL)
 
237
// - the path of the instance directory (if instance!=NULL)
 
238
// - the path where all instance directories are kept
 
239
// this function must be kept consistent with set_id() below
 
240
static void set_path (char * path, unsigned int path_size, const ncInstance * instance, const char * filename)
 
241
{
 
242
    assert (strlen (instances_path));
 
243
    if (instance) {
 
244
        assert (strlen (instance->userId));
 
245
        assert (strlen (instance->instanceId));
 
246
        char buf [1024];
 
247
        set_id (instance, NULL, buf, sizeof (buf));
 
248
        if (filename) {
 
249
            snprintf (path, path_size, "%s/work/%s/%s", instances_path, buf, filename);
 
250
        } else {
 
251
            snprintf (path, path_size, "%s/work/%s", instances_path, buf);
 
252
        } 
 
253
    } else {
 
254
        snprintf     (path, path_size, "%s/work", instances_path);
 
255
    }
 
256
}
 
257
 
 
258
static int stale_blob_examiner (const blockblob * bb)
 
259
{
 
260
    char work_path [MAX_PATH];
 
261
    
 
262
    set_path (work_path, sizeof (work_path), NULL, NULL);
 
263
    int work_path_len = strlen (work_path);
 
264
    assert (work_path_len > 0);
 
265
 
 
266
    char * s = strstr(bb->blocks_path, work_path);
 
267
    if (s==NULL || s!=bb->blocks_path)
 
268
        return 0; // blob not under work blobstore path
 
269
 
 
270
    // parse the path past the work directory base
 
271
    safe_strncpy (work_path, bb->blocks_path, sizeof (work_path));
 
272
    s = work_path + work_path_len + 1;
 
273
    char * user_id = strtok (s, "/");
 
274
    char * inst_id = strtok (NULL, "/"); 
 
275
    char * file    = strtok (NULL, "/");
 
276
 
 
277
    ncInstance * instance = find_instance (instances, inst_id);
 
278
    if (instance == NULL) { // not found among running instances => stale
 
279
        // while we're here, try to delete extra files that aren't managed by the blobstore
 
280
        // TODO: ensure we catch any other files - perhaps by performing this cleanup after all blobs are deleted
 
281
        char path [MAX_PATH];
 
282
#define del_file(filename) snprintf (path, sizeof (path), "%s/work/%s/%s/%s", instances_path, user_id, inst_id, filename); unlink (path);
 
283
        del_file("instance.xml");
 
284
        del_file("libvirt.xml");
 
285
        del_file("console.log");
 
286
        del_file("instance.checkpoint");
 
287
        return 1;
 
288
    }
 
289
 
 
290
    return 0;
 
291
}
 
292
 
 
293
int save_instance_struct (const ncInstance * instance)
 
294
{
 
295
    if (instance==NULL) {
 
296
            logprintfl(EUCADEBUG, "save_instance_struct: NULL instance!\n");
 
297
        return ERROR;
 
298
    }
 
299
 
 
300
    char checkpoint_path [MAX_PATH];
 
301
    set_path (checkpoint_path, sizeof (checkpoint_path), instance, "instance.checkpoint");
 
302
 
 
303
    int fd;
 
304
    if ((fd = open (checkpoint_path, O_CREAT | O_WRONLY, BACKING_FILE_PERM)) < 0) {
 
305
            logprintfl(EUCADEBUG, "[%s] save_instance_struct: failed to create instance checkpoint at %s\n", instance->instanceId, checkpoint_path);
 
306
        return ERROR;
 
307
    }
 
308
 
 
309
    if (write (fd, (char *)instance, sizeof(struct ncInstance_t)) != sizeof (struct ncInstance_t)) {
 
310
            logprintfl(EUCADEBUG, "[%s] save_instance_struct: failed to write instance checkpoint at %s\n", instance->instanceId, checkpoint_path);
 
311
        close (fd);
 
312
        return ERROR;
 
313
    }
 
314
    close (fd);
 
315
    
 
316
    return OK;
 
317
}
 
318
 
 
319
ncInstance * load_instance_struct (const char * instanceId)
 
320
{
 
321
    const int meta_size = sizeof (struct ncInstance_t);
 
322
    ncInstance * instance = calloc (1, meta_size);    
 
323
    if (instance==NULL) {
 
324
            logprintfl (EUCADEBUG, "load_instance_struct: out of memory for instance struct\n");
 
325
            return NULL;
 
326
    }
 
327
    safe_strncpy (instance->instanceId, instanceId, sizeof (instance->instanceId));
 
328
 
 
329
    // we don't know userId, so we'll look for instanceId in every user's
 
330
    // directory (we're assuming that instanceIds are unique in the system)
 
331
    char user_paths [MAX_PATH];
 
332
    set_path (user_paths, sizeof (user_paths), NULL, NULL);
 
333
    DIR * insts_dir = opendir(user_paths);
 
334
    if (insts_dir == NULL) {
 
335
            logprintfl (EUCADEBUG, "load_instance_struct: failed to open %s\n", user_paths);
 
336
        goto free;
 
337
    }
 
338
    
 
339
    struct dirent * dir_entry;
 
340
    while ((dir_entry = readdir (insts_dir)) != NULL) {
 
341
        char tmp_path [MAX_PATH];
 
342
        struct stat mystat;
 
343
        
 
344
        snprintf(tmp_path, sizeof (tmp_path), "%s/%s/%s", user_paths, dir_entry->d_name, instance->instanceId);
 
345
        if (stat(tmp_path, &mystat)==0) {
 
346
            safe_strncpy (instance->userId, dir_entry->d_name, sizeof (instance->userId));
 
347
            break; // found it
 
348
        }
 
349
    }
 
350
    closedir (insts_dir);
 
351
 
 
352
    if (strlen(instance->userId)<1) {
 
353
            logprintfl (EUCADEBUG, "load_instance_struct: didn't find instance %s\n", instance->instanceId);
 
354
        goto free;
 
355
    }
 
356
 
 
357
    int fd;
 
358
    char checkpoint_path [MAX_PATH];
 
359
    set_path (checkpoint_path, sizeof (checkpoint_path), instance, "instance.checkpoint");
 
360
    if ((fd = open(checkpoint_path, O_RDONLY)) < 0 
 
361
        || read (fd, instance, meta_size) < meta_size) {
 
362
        logprintfl(EUCADEBUG, "load_instance_struct: failed to load metadata for %s from %s: %s\n", instance->instanceId, checkpoint_path, strerror (errno));
 
363
        if(fd >= 0)
 
364
            close (fd);
 
365
        goto free;
 
366
    }
 
367
    close (fd);
 
368
    instance->stateCode = NO_STATE;
 
369
    // clear out pointers, since they are now wrong
 
370
    instance->params.root       = NULL;
 
371
    instance->params.kernel     = NULL;
 
372
    instance->params.ramdisk    = NULL;
 
373
    instance->params.swap       = NULL;
 
374
    instance->params.ephemeral0 = NULL;
 
375
    vbr_parse (&(instance->params), NULL); // fix up the pointers
 
376
    return instance;
 
377
    
 
378
 free:
 
379
    if (instance) free (instance);
 
380
    return NULL;
 
381
}
 
382
 
 
383
int create_instance_backing (ncInstance * instance)
 
384
{
 
385
    int ret = ERROR;
 
386
    virtualMachine * vm = &(instance->params);
 
387
 
 
388
    // ensure instance directory exists
 
389
    set_path (instance->instancePath,    sizeof (instance->instancePath),    instance, NULL);
 
390
    if (ensure_directories_exist (instance->instancePath, 0, NULL, "root", BACKING_DIRECTORY_PERM) == -1)
 
391
        goto out;
 
392
 
 
393
    // set various instance-directory-relative paths in the instance struct
 
394
    set_path (instance->xmlFilePath,     sizeof (instance->xmlFilePath),     instance, "instance.xml");
 
395
    set_path (instance->libvirtFilePath, sizeof (instance->libvirtFilePath), instance, "libvirt.xml");
 
396
    set_path (instance->consoleFilePath, sizeof (instance->consoleFilePath), instance, "console.log");
 
397
    if (strstr (instance->platform, "windows")) {
 
398
        // generate the floppy file for windows instances
 
399
        if (makeWindowsFloppy (nc_state.home, instance->instancePath, instance->keyName, instance->instanceId)) {
 
400
            logprintfl (EUCAERROR, "[%s] error: could not create windows bootup script floppy\n", instance->instanceId);
 
401
            goto out;
 
402
        } else {
 
403
            set_path (instance->floppyFilePath, sizeof (instance->floppyFilePath), instance, "floppy");
 
404
        }
 
405
    }
 
406
    
 
407
    char work_prefix [1024]; // {userId}/{instanceId}
 
408
    set_id (instance, NULL, work_prefix, sizeof (work_prefix));
 
409
    
 
410
    // compute tree of dependencies
 
411
    artifact * sentinel = vbr_alloc_tree (vm, // the struct containing the VBR
 
412
                                          FALSE, // for Xen and KVM we do not need to make disk bootable
 
413
                                          TRUE, // make working copy of runtime-modifiable files
 
414
                                          (instance->do_inject_key)?(instance->keyName):(NULL), // the SSH key
 
415
                                          instance->instanceId); // ID is for logging
 
416
    if (sentinel == NULL) {
 
417
        logprintfl (EUCAERROR, "[%s] error: failed to prepare backing for instance\n", instance->instanceId);
 
418
        goto out;
 
419
    }
 
420
 
 
421
    sem_p (disk_sem);
 
422
    // download/create/combine the dependencies
 
423
    int rc = art_implement_tree (sentinel, work_bs, cache_bs, work_prefix, INSTANCE_PREP_TIMEOUT_USEC);
 
424
    sem_v (disk_sem);
 
425
 
 
426
    if (rc != OK) {
 
427
        logprintfl (EUCAERROR, "[%s] error: failed to implement backing for instance\n", instance->instanceId);
 
428
        goto out;
 
429
    }
 
430
 
 
431
    if (save_instance_struct (instance)) // update instance checkpoint now that the struct got updated
 
432
        goto out;
 
433
 
 
434
    ret = OK;
 
435
 out:
 
436
    if (sentinel)
 
437
        art_free (sentinel);
 
438
    return ret;
 
439
}
 
440
 
 
441
int clone_bundling_backing (ncInstance *instance, const char* filePrefix, char* blockPath)
 
442
{
 
443
    char path[MAX_PATH];
 
444
    char work_regex [1024];
 
445
    char id [BLOBSTORE_MAX_PATH];
 
446
    char workPath [BLOBSTORE_MAX_PATH];
 
447
    int ret = OK;
 
448
    int found=-1;
 
449
    blockblob *src_blob = NULL, *dest_blob = NULL;
 
450
    blockblob_meta *matches = NULL;
 
451
    
 
452
    set_path (path, sizeof (path), instance, NULL);
 
453
    set_id2 (instance, "/.*", work_regex, sizeof (work_regex));
 
454
    
 
455
    if( (found=blobstore_search (work_bs, work_regex, &matches) <= 0 ) ) {
 
456
        logprintfl (EUCAERROR, "[%s] error: failed to find blob in %s %d\n", instance->instanceId, path, found);
 
457
        return ERROR;
 
458
    }
 
459
    
 
460
    for (blockblob_meta * bm = matches; bm; bm=bm->next) {
 
461
        blockblob * bb = blockblob_open (work_bs, bm->id, 0, 0, NULL, FIND_TIMEOUT_USEC);
 
462
        if (bb!=NULL && bb->snapshot_type == BLOBSTORE_SNAPSHOT_DM && strstr(bb->blocks_path,"emi-") != NULL) { // root image contains substr 'emi-'
 
463
            src_blob = bb;
 
464
            break;
 
465
        } else if (bb!=NULL) {
 
466
            blockblob_close(bb);
 
467
        }
 
468
    } 
 
469
    if (!src_blob) {
 
470
        logprintfl (EUCAERROR, "[%s] couldn't find the blob to clone from", instance->instanceId);
 
471
        goto error;
 
472
    }
 
473
    set_id (instance, NULL, workPath, sizeof (workPath));
 
474
    snprintf (id, sizeof(id), "%s/%s", workPath, filePrefix);
 
475
    
 
476
    // open destination blob 
 
477
    dest_blob = blockblob_open (work_bs, id, src_blob->size_bytes, BLOBSTORE_FLAG_CREAT | BLOBSTORE_FLAG_EXCL, NULL, FIND_TIMEOUT_USEC); 
 
478
    if (!dest_blob) {
 
479
        logprintfl (EUCAERROR, "[%s] couldn't create the destination blob for bundling (%s)", instance->instanceId, id);
 
480
        goto error;
 
481
    }
 
482
    
 
483
    if (strlen (dest_blob->blocks_path) > 0)
 
484
        snprintf (blockPath, MAX_PATH, "%s", dest_blob->blocks_path);
 
485
    
 
486
    // copy blob (will 'dd' eventually)
 
487
    if (blockblob_copy (src_blob, 0, dest_blob, 0, src_blob->size_bytes) != OK) {
 
488
        logprintfl (EUCAERROR, "[%s] couldn't copy block blob for bundling (%s)", instance->instanceId, id);
 
489
        goto error;
 
490
    }
 
491
    
 
492
    goto free;
 
493
 error: 
 
494
    ret = ERROR; 
 
495
 free:
 
496
    // free the search results
 
497
    for (blockblob_meta * bm = matches; bm;) {
 
498
        blockblob_meta * next = bm->next;
 
499
        free (bm);
 
500
        bm = next;
 
501
    } 
 
502
    
 
503
    if(src_blob)
 
504
        blockblob_close(src_blob);
 
505
    if(dest_blob)
 
506
        blockblob_close(dest_blob);
 
507
    return ret;
 
508
}
 
509
 
 
510
int destroy_instance_backing (ncInstance * instance, int do_destroy_files)
 
511
{
 
512
    int ret = OK;
 
513
    int total_prereqs = 0;
 
514
    char path [MAX_PATH];
 
515
    virtualMachine * vm = &(instance->params);
 
516
    
 
517
    // find and detach iSCSI targets, if any
 
518
    for (int i=0; i<EUCA_MAX_VBRS && i<vm->virtualBootRecordLen; i++) {
 
519
        virtualBootRecord * vbr = &(vm->virtualBootRecord[i]);
 
520
        if (vbr->locationType==NC_LOCATION_IQN) {
 
521
            if (disconnect_iscsi_target (vbr->resourceLocation)) {
 
522
                logprintfl(EUCAERROR, "[%s] error: failed to disconnect iSCSI target attached to %s\n", instance->instanceId, vbr->backingPath);
 
523
            } 
 
524
        }
 
525
    }
 
526
 
 
527
    // see if instance directory is there (sometimes startup fails before it is created)
 
528
    set_path (path, sizeof (path), instance, NULL);
 
529
    if (check_path (path))
 
530
        return ret;
 
531
 
 
532
    // to ensure that we are able to delete all blobs, we chown files back to 'eucalyptus'
 
533
    // (e.g., libvirt on KVM on Maverick chowns them to libvirt-qemu while
 
534
    // VM is running and then chowns them to root after termination)
 
535
    set_path (path, sizeof (path), instance, "*");
 
536
    if (diskutil_ch (path, EUCALYPTUS_ADMIN, NULL, BACKING_FILE_PERM)) {
 
537
        logprintfl (EUCAWARN, "[%s] error: failed to chown files before cleanup\n", instance->instanceId);
 
538
    }
 
539
 
 
540
    if (do_destroy_files) {
 
541
        char work_regex [1024]; // {userId}/{instanceId}/.*
 
542
        set_id2 (instance, "/.*", work_regex, sizeof (work_regex));
 
543
 
 
544
        if (blobstore_delete_regex (work_bs, work_regex) == -1) {
 
545
            logprintfl (EUCAERROR, "[%s] error: failed to remove some artifacts in %s\n", instance->instanceId, path);
 
546
        }
 
547
 
 
548
        // remove the known leftover files
 
549
        unlink (instance->xmlFilePath);
 
550
        unlink (instance->libvirtFilePath);
 
551
        unlink (instance->consoleFilePath);
 
552
        if (strlen (instance->floppyFilePath)) {
 
553
            unlink (instance->floppyFilePath);
 
554
        }
 
555
        set_path (path, sizeof (path), instance, "instance.checkpoint");
 
556
        unlink (path);
 
557
        for (int i=0; i < EUCA_MAX_VOLUMES; ++i) {
 
558
            ncVolume * volume = &instance->volumes[i];
 
559
            snprintf (path, sizeof (path), EUCALYPTUS_VOLUME_XML_PATH_FORMAT, instance->instancePath, volume->volumeId);
 
560
            unlink (path);
 
561
        }
 
562
        // bundle instance will leave additional files
 
563
        // let's delete every file in the directory
 
564
        struct dirent **files;
 
565
        int n = scandir(instance->instancePath, &files, 0, alphasort);
 
566
        char toDelete[MAX_PATH];
 
567
        if (n>0){
 
568
            while (n--) {
 
569
               struct dirent *entry = files[n];
 
570
               if( entry !=NULL && strncmp(entry->d_name, ".",1)!=0 && strncmp(entry->d_name, "..", 2)!=0){
 
571
                    snprintf(toDelete, MAX_PATH, "%s/%s", instance->instancePath, entry->d_name);
 
572
                    unlink(toDelete);
 
573
                    free(entry);
 
574
               }
 
575
            }
 
576
            free(files);
 
577
        }
 
578
    }
 
579
   
 
580
    // Finally try to remove the directory.
 
581
    // If either the user or our code introduced
 
582
    // any new files, this last step will fail.
 
583
    set_path (path, sizeof (path), instance, NULL);
 
584
    if (rmdir (path) && do_destroy_files) {
 
585
        logprintfl (EUCAWARN, "[%s] warning: failed to remove backing directory %s\n", instance->instanceId, path);
 
586
    }
 
587
    
 
588
    return ret;
 
589
}