~ubuntu-core-dev/eucalyptus/ubuntu-karmic

« back to all changes in this revision

Viewing changes to node/handlers_xen.c

  • Committer: Dmitrii Zagorodnov
  • Date: 2009-01-27 21:53:41 UTC
  • mfrom: (25.1.112 eucalyptus-main)
  • Revision ID: dmitrii@cs.ucsb.edu-20090127215341-i0f0v6cmbpljmg02
merged with current main

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <stdio.h>
 
2
#include <stdlib.h>
 
3
#include <string.h> /* strlen, strcpy */
 
4
#include <time.h>
 
5
#include <limits.h> /* INT_MAX */
 
6
#include <sys/types.h> /* fork */
 
7
#include <sys/wait.h> /* waitpid */
 
8
#include <unistd.h>
 
9
#include <fcntl.h>
 
10
#include <assert.h>
 
11
#include <errno.h>
 
12
#include <sys/stat.h>
 
13
#include <pthread.h>
 
14
#include <sys/vfs.h> /* statfs */
 
15
#include <signal.h> /* SIGINT */
 
16
 
 
17
#include "ipc.h"
 
18
#include "misc.h"
 
19
#include <handlers.h>
 
20
#include <storage.h>
 
21
#include <eucalyptus.h>
 
22
#include <libvirt/libvirt.h>
 
23
#include <libvirt/virterror.h>
 
24
#include <vnetwork.h>
 
25
#include <euca_auth.h>
 
26
 
 
27
#define BUFSIZE 512 /* random buffer size used all over the place */
 
28
 
 
29
/* resource limits, in MB, will be determined by hardware if set to 0 */
 
30
static int config_max_disk  = 0;
 
31
static int config_max_mem   = 0;
 
32
static int config_max_cores = 0;
 
33
 
 
34
/* actual resource limits of the system, as determined at NC startup */
 
35
static long long mem_max  = 0; 
 
36
static long long disk_max = 0;
 
37
static int cores_max      = 0;
 
38
 
 
39
/* network configuration defaults (may be overriden from config file) */
 
40
static char config_network_path [BUFSIZE];
 
41
static int  config_network_port = NC_NET_PORT_DEFAULT;
 
42
 
 
43
static char * admin_user_id = EUCALYPTUS_ADMIN;
 
44
static char gen_libvirt_xml_command_path [BUFSIZE] = "";
 
45
static char get_xen_info_command_path [BUFSIZE] = "";
 
46
 
 
47
#define BYTES_PER_DISK_UNIT 1048576 /* disk stats are in Gigs */
 
48
#define SWAP_SIZE 512 /* for now, the only possible swap size, in MBs */
 
49
#define MAXDOMS 1024 /* max number of running domains on node */
 
50
 
 
51
vnetConfig *vnetconfig = NULL;
 
52
sem * xen_sem; /* semaphore for serializing domain creation */
 
53
sem * inst_sem; /* semaphore for guarding access to global instance structs */
 
54
bunchOfInstances * global_instances = NULL; /* will be initiated upon first call */
 
55
 
 
56
const int unbooted_cleanup_threshold = 60 * 60 * 2; /* after this many seconds any unbooted and SHUTOFF domains will be cleaned up */
 
57
const int teardown_state_duration = 60; /* after this many seconds in TEARDOWN state (no resources), we'll forget about the instance */
 
58
const int monitoring_period_duration = 5; /* how frequently we check on instances */
 
59
 
 
60
static void libvirt_error_handler (void * userData, virErrorPtr error)
 
61
{
 
62
    if ( error==NULL) {
 
63
        logprintfl (EUCAERROR, "libvirt error handler was given a NULL pointer\n");
 
64
    } else {
 
65
        /* these are common, they appear for evey non-existing domain,
 
66
         * such as BOOTING/CRASHED/SHUTOFF, which we catch elsewhere,
 
67
         * so we won't print them */
 
68
        if (error->code==10) { 
 
69
            return;
 
70
        }
 
71
        logprintfl (EUCAERROR, "libvirt: %s (code=%d)\n", error->message, error->code);
 
72
    }
 
73
}
 
74
 
 
75
static void change_state (ncInstance * instance, instance_states state)
 
76
{
 
77
    instance->state = (int) state;
 
78
    switch (state) { /* mapping from NC's internal states into external ones */
 
79
    case BOOTING:
 
80
        instance->stateCode = PENDING;
 
81
        break;
 
82
    case RUNNING:
 
83
    case BLOCKED:
 
84
    case PAUSED:
 
85
    case SHUTDOWN:
 
86
    case SHUTOFF:
 
87
    case CRASHED:
 
88
        instance->stateCode = EXTANT;
 
89
        break;
 
90
    case TEARDOWN:
 
91
        instance->stateCode = TEARDOWN;
 
92
        break;
 
93
    default:
 
94
        logprintfl (EUCAERROR, "error: change_sate(): unexpected state (%d) for instance %s\n", instance->state, instance->instanceId);        
 
95
        return;
 
96
    }
 
97
 
 
98
    strncpy(instance->stateName, instance_state_names[instance->stateCode], CHAR_BUFFER_SIZE);
 
99
}
 
100
 
 
101
static void refresh_instance_info (ncInstance * instance)
 
102
{
 
103
    int now = instance->state;
 
104
    
 
105
    /* no need to bug Xen for domains without state */
 
106
    if (now==TEARDOWN)
 
107
        return;
 
108
    
 
109
    /* try to get domain state from Xen */
 
110
    virConnectPtr conn = virConnectOpen ("xen:///"); /* NULL means local hypervisor */
 
111
    if (conn == NULL) {
 
112
        logprintfl (EUCAERROR, "warning: failed to connect to hypervisor\n");
 
113
        return;
 
114
    }
 
115
    virDomainPtr dom = virDomainLookupByName (conn, instance->instanceId);
 
116
    if (dom == NULL) { /* Xen doesn't know about it */
 
117
        if (now==RUNNING ||
 
118
            now==BLOCKED ||
 
119
            now==PAUSED ||
 
120
            now==SHUTDOWN) {
 
121
            /* Most likely the user has shut it down from the inside */
 
122
            logprintfl (EUCAWARN, "warning: hypervisor failed to find domain %s, assuming it was shut off\n", instance->instanceId);
 
123
            change_state (instance, SHUTOFF);
 
124
        }
 
125
        /* else 'now' stays in SHUTFOFF, BOOTING or CRASHED */
 
126
        virConnectClose (conn);
 
127
        return;
 
128
    }
 
129
    virDomainInfo info;
 
130
    int error = virDomainGetInfo(dom, &info);
 
131
    if (error < 0 || info.state == VIR_DOMAIN_NOSTATE) {
 
132
        logprintfl (EUCAWARN, "warning: failed to get informations for domain %s\n", instance->instanceId);
 
133
        /* what to do? hopefully we'll find out more later */
 
134
        virDomainFree (dom);
 
135
        virConnectClose (conn);
 
136
        return;
 
137
    } 
 
138
    int xen = info.state;
 
139
 
 
140
    switch (now) {
 
141
    case BOOTING:
 
142
    case RUNNING:
 
143
    case BLOCKED:
 
144
    case PAUSED:
 
145
        /* change to Xen's state, whatever it happens to be */
 
146
        change_state (instance, xen);
 
147
        break;
 
148
    case SHUTDOWN:
 
149
    case SHUTOFF:
 
150
    case CRASHED:
 
151
        if (xen==RUNNING ||
 
152
            xen==BLOCKED ||
 
153
            xen==PAUSED) {
 
154
            /* cannot go back! */
 
155
            logprintfl (EUCAWARN, "warning: detected prodigal domain %s, terminating it\n", instance->instanceId);
 
156
            sem_p (xen_sem);
 
157
            virDomainDestroy (dom);
 
158
            sem_v (xen_sem);
 
159
        } else {
 
160
            change_state (instance, xen);
 
161
        }
 
162
        break;
 
163
    default:
 
164
        logprintfl (EUCAERROR, "error: refresh...(): unexpected state (%d) for instance %s\n", now, instance->instanceId);
 
165
        return;
 
166
    }
 
167
    virDomainFree(dom);
 
168
    virConnectClose(conn);
 
169
 
 
170
    /* if instance is running, try to find out its IP address */
 
171
    if (instance->state==RUNNING ||
 
172
        instance->state==BLOCKED ||
 
173
        instance->state==PAUSED) {
 
174
        char *ip=NULL;
 
175
        int rc;
 
176
 
 
177
        if (!strncmp(instance->ncnet.publicIp, "0.0.0.0", 32)) {
 
178
            rc = discover_mac(vnetconfig, instance->ncnet.publicMac, &ip);
 
179
            if (!rc) {
 
180
                logprintfl (EUCAINFO, "discovered public IP %s for instance %s\n", ip, instance->instanceId);
 
181
                strncpy(instance->ncnet.publicIp, ip, 32);
 
182
            }
 
183
        }
 
184
        if (!strncmp(instance->ncnet.privateIp, "0.0.0.0", 32)) {
 
185
            rc = discover_mac(vnetconfig, instance->ncnet.privateMac, &ip);
 
186
            if (!rc) {
 
187
                logprintfl (EUCAINFO, "discovered private IP %s for instance %s\n", ip, instance->instanceId);
 
188
                strncpy(instance->ncnet.privateIp, ip, 32);
 
189
            }
 
190
        }
 
191
    }
 
192
}
 
193
 
 
194
static void print_running_domains (void)
 
195
{
 
196
    bunchOfInstances * head;
 
197
    char buf [BUFSIZE] = "";
 
198
    sem_p (inst_sem);
 
199
    for ( head=global_instances; head; head=head->next ) {
 
200
        ncInstance * instance = head->instance;
 
201
        if (instance->state==BOOTING 
 
202
            || instance->state==RUNNING 
 
203
            || instance->state==BLOCKED
 
204
            || instance->state==PAUSED) {
 
205
            strcat (buf, " ");
 
206
            strcat (buf, instance->instanceId);
 
207
        }
 
208
    }
 
209
    sem_v (inst_sem);
 
210
    logprintfl (EUCAINFO, "currently running/booting: %s\n", buf);
 
211
}
 
212
 
 
213
static void * monitoring_thread (void *arg)
 
214
{
 
215
    int i;
 
216
 
 
217
    for (;;) {
 
218
        bunchOfInstances * head;
 
219
        time_t now = time(NULL);
 
220
        sem_p (inst_sem);
 
221
 
 
222
    restart: 
 
223
        for ( head = global_instances; head; head = head->next ) {
 
224
            ncInstance * instance = head->instance;
 
225
 
 
226
            /* query Xen for current state, if any */
 
227
            refresh_instance_info (instance);
 
228
            /* don't touch running threads */
 
229
            if (instance->state!=BOOTING && 
 
230
                instance->state!=SHUTOFF &&
 
231
                instance->state!=SHUTDOWN &&
 
232
                instance->state!=TEARDOWN) continue;
 
233
 
 
234
            if (instance->state==TEARDOWN) {
 
235
                /* it's been long enugh, we can fugetaboutit */
 
236
                if ((now - instance->terminationTime)>teardown_state_duration) {
 
237
                    remove_instance (&global_instances, instance);
 
238
                    logprintfl (EUCAINFO, "forgetting about instance %s\n", instance->instanceId);
 
239
                    free_instance (&instance);
 
240
                    goto restart; /* reset the head since we modified the list */
 
241
                }
 
242
                continue;
 
243
            }
 
244
 
 
245
            if (instance->state==BOOTING &&
 
246
                (now - instance->launchTime)<unbooted_cleanup_threshold) /* hasn't been long enough */
 
247
                continue; /* let it be */
 
248
            
 
249
            /* ok, it's been condemned => destroy the files */
 
250
            if (scCleanupInstanceImage(instance->userId, instance->instanceId)) {
 
251
                logprintfl (EUCAWARN, "warning: failed to cleanup instance image %d\n", instance->instanceId);
 
252
            }
 
253
            
 
254
            /* check to see if this is the last instance running on vlan */
 
255
            int left = 0;
 
256
            bunchOfInstances * vnhead;
 
257
            for (vnhead = global_instances; vnhead; vnhead = vnhead->next ) {
 
258
                ncInstance * vninstance = vnhead->instance;
 
259
                if (vninstance->ncnet.vlan == (instance->ncnet).vlan 
 
260
                    && strcmp(instance->instanceId, vninstance->instanceId)) {
 
261
                    left++;
 
262
                }
 
263
            }
 
264
            if (left==0) {
 
265
                logprintfl (EUCAINFO, "stopping the network (vlan=%d)\n", (instance->ncnet).vlan);
 
266
                vnetStopNetwork (vnetconfig, (instance->ncnet).vlan, NULL, NULL);
 
267
            }
 
268
            change_state (instance, TEARDOWN); /* TEARDOWN = no more resources */
 
269
            instance->terminationTime = time (NULL);
 
270
        }
 
271
        sem_v (inst_sem);
 
272
        
 
273
        sleep (monitoring_period_duration);
 
274
    }
 
275
    
 
276
    return NULL;
 
277
}
 
278
 
 
279
static int get_value (char * s, const char * name, long long * valp) 
 
280
{
 
281
    char buf [BUFSIZE];
 
282
    if (s==NULL || name==NULL || valp==NULL) return ERROR;
 
283
    snprintf (buf, BUFSIZE, "%s=%%lld", name);
 
284
    return (sscanf_lines (s, buf, valp)==1 ? OK : ERROR);
 
285
}
 
286
 
 
287
static int doInitialize (void) 
 
288
{
 
289
    struct stat mystat;
 
290
    char config [BUFSIZE];
 
291
    char *brname, *s, *home, *pubInterface, *bridge, *mode;
 
292
    int error, rc;
 
293
 
 
294
    /* read in configuration - this should be first! */
 
295
    int do_warn = 0;
 
296
    home = getenv (EUCALYPTUS_ENV_VAR_NAME);
 
297
    if (!home) {
 
298
        home = strdup (""); /* root by default */
 
299
        do_warn = 1;
 
300
    } else {
 
301
        home = strdup (home);
 
302
    }
 
303
 
 
304
    snprintf(config, BUFSIZE, "%s/var/log/eucalyptus/nc.log", home);
 
305
    logfile(config, EUCADEBUG); // TODO: right level?
 
306
    if (do_warn) 
 
307
        logprintfl (EUCAWARN, "env variable %s not set, using /\n", EUCALYPTUS_ENV_VAR_NAME);
 
308
 
 
309
    snprintf(config, BUFSIZE, EUCALYPTUS_CONF_LOCATION, home);
 
310
    if (stat(config, &mystat)==0) {
 
311
      logprintfl (EUCAINFO, "NC is looking for configuration in %s\n", config);
 
312
      
 
313
#define GET_VAR_INT(var,name) \
 
314
            if (get_conf_var(config, name, &s)>0){\
 
315
                var = atoi(s);\
 
316
                free (s);\
 
317
            }
 
318
        
 
319
        GET_VAR_INT(config_max_mem,   CONFIG_MAX_MEM);
 
320
        GET_VAR_INT(config_max_disk,  CONFIG_MAX_DISK);
 
321
        GET_VAR_INT(config_max_cores, CONFIG_MAX_CORES);
 
322
    }
 
323
 
 
324
    if ((xen_sem = sem_alloc (1, "eucalyptus-nc-xen-semaphore")) == NULL
 
325
        || (inst_sem = sem_alloc (1, "eucalyptus-nc-inst-semaphore")) == NULL) {
 
326
        logprintfl (EUCAFATAL, "failed to create and initialize a semaphore\n");
 
327
        return ERROR_FATAL;
 
328
    }
 
329
    
 
330
    /* prompt the SC to read the configuration, too */
 
331
    rc = scInitConfig(); 
 
332
    if (rc) {
 
333
      logprintfl (EUCAFATAL, "ERROR: scInitConfig() failed\n");
 
334
      return ERROR_FATAL;
 
335
    }
 
336
 
 
337
    /* set up paths of Eucalyptus commands NC relies on */
 
338
    snprintf (gen_libvirt_xml_command_path, BUFSIZE, EUCALYPTUS_GEN_LIBVIRT_XML, home, home);
 
339
    snprintf (get_xen_info_command_path,    BUFSIZE, EUCALYPTUS_GET_XEN_INFO,    home, home);
 
340
    
 
341
    /* "adopt" currently running Xen instances */
 
342
    {
 
343
        virConnectPtr conn = NULL;
 
344
        int dom_ids[MAXDOMS];
 
345
        int num_doms = 0;
 
346
        
 
347
        logprintfl (EUCAINFO, "looking for existing Xen domains\n");
 
348
        virSetErrorFunc (NULL, libvirt_error_handler);
 
349
 
 
350
        /* check with Xen */
 
351
        conn = virConnectOpen("xen:///"); /* NULL means local hypervisor */
 
352
        if (conn == NULL) {
 
353
            logprintfl (EUCAFATAL, "Failed to connect to hypervisor\n");
 
354
            free(home);
 
355
            return ERROR_FATAL;
 
356
        }
 
357
        
 
358
        num_doms = virConnectListDomains(conn, dom_ids, MAXDOMS);
 
359
        if (num_doms > 0) {
 
360
            virDomainPtr dom = NULL;
 
361
            int i;
 
362
            
 
363
            for ( i=0; i<num_doms; i++) {
 
364
                dom = virDomainLookupByID(conn, dom_ids[i]);
 
365
                
 
366
                if (dom) {
 
367
                    int error;
 
368
                    virDomainInfo info;
 
369
                    const char * dom_name;
 
370
                    ncInstance * instance;
 
371
                    
 
372
                    error = virDomainGetInfo(dom, &info);
 
373
                    if (error < 0 || info.state == VIR_DOMAIN_NOSTATE) {
 
374
                        logprintfl (EUCAWARN, "WARNING: failed to get info on running Xen domain #%d, ignoring it\n", dom_ids[i]);
 
375
                        continue;
 
376
                    }
 
377
 
 
378
                    if (info.state == VIR_DOMAIN_SHUTDOWN ||
 
379
                        info.state == VIR_DOMAIN_SHUTOFF ||
 
380
                        info.state == VIR_DOMAIN_CRASHED ) {
 
381
                        logprintfl (EUCADEBUG, "ignoring non-running Xen domain #%d\n", dom_ids[i]);
 
382
                        continue;
 
383
                    }
 
384
                    
 
385
                    if ((dom_name = virDomainGetName(dom))==NULL) {
 
386
                        logprintfl (EUCAWARN, "WARNING: failed to get name of running Xen domain #%d, ignoring it\n", dom_ids[i]);
 
387
                        continue;
 
388
                    }
 
389
 
 
390
                    if (!strcmp(dom_name, "Domain-0")) {
 
391
                        continue;
 
392
                    }
 
393
 
 
394
                    if ((instance = scRecoverInstanceInfo (dom_name))==NULL) {
 
395
                        logprintfl (EUCAWARN, "WARNING: failed to recover Eucalyptus metadata of running Xen domain %s, ignoring it\n", dom_name);
 
396
                        continue;
 
397
                    }
 
398
                    
 
399
                    change_state (instance, info.state);                    
 
400
                    sem_p (inst_sem);
 
401
                    int err = add_instance (&global_instances, instance);
 
402
                    sem_v (inst_sem);
 
403
                    if (err) {
 
404
                        free_instance (&instance);
 
405
                        continue;
 
406
                    }
 
407
                    
 
408
                    logprintfl (EUCAINFO, "- adopted running Xen domain %s from user %s\n", instance->instanceId, instance->userId);
 
409
                    /* TODO: try to look up IPs? */
 
410
 
 
411
                    virDomainFree (dom);
 
412
                } else {
 
413
                    logprintfl (EUCAWARN, "WARNING: failed to lookup running Xen domain #%d, ignoring it\n", dom_ids[i]);
 
414
                }
 
415
            }
 
416
        } else if (num_doms==0) {
 
417
            logprintfl (EUCAINFO, "no currently running Xen domains to adopt\n");
 
418
        } else {
 
419
            logprintfl (EUCAWARN, "WARNING: failed to find out about running domains\n");
 
420
        }
 
421
        virConnectClose (conn);
 
422
    }
 
423
 
 
424
    /* network startup */
 
425
    vnetconfig = malloc(sizeof(vnetConfig));
 
426
    snprintf (config_network_path, BUFSIZE, NC_NET_PATH_DEFAULT, home);
 
427
    pubInterface = getConfString(config, "VNET_INTERFACE");
 
428
    bridge = getConfString(config, "VNET_BRIDGE");
 
429
    mode = getConfString(config, "VNET_MODE");
 
430
 
 
431
    vnetInit(vnetconfig, mode, home, config_network_path, NC, pubInterface, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, bridge);
 
432
    
 
433
    /* cleanup from previous runs and verify integrity of instances
 
434
     * directory */
 
435
    sem_p (inst_sem);
 
436
    long long instances_bytes = scFSCK (&global_instances);
 
437
    sem_v (inst_sem);
 
438
    if (instances_bytes<0) {
 
439
        logprintfl (EUCAFATAL, "instances store failed integrity check (error=%d)\n", instances_bytes);
 
440
        return ERROR_FATAL;
 
441
    }
 
442
 
 
443
    /* discover resource capacity */
 
444
    { 
 
445
        const char * ipath = scGetInstancePath();
 
446
        char buf [BUFSIZE];
 
447
        char * s = NULL;
 
448
        int len;
 
449
        
 
450
        /* calculate disk_max */
 
451
        { 
 
452
            long long fs_free_blocks = 0;
 
453
            long long fs_block_size  = 0;
 
454
 
 
455
            struct statfs fs;
 
456
            if (statfs(ipath, &fs) == -1) {
 
457
                printf ("error: failed to stat %s\n", ipath);
 
458
            }
 
459
            
 
460
            disk_max = fs.f_bsize * fs.f_bavail + instances_bytes; /* max for Euca, not total */
 
461
            disk_max /= BYTES_PER_DISK_UNIT; /* convert bytes to the right units */
 
462
            if (config_max_disk
 
463
                && disk_max>config_max_disk) 
 
464
                disk_max=config_max_disk; /* reduce if the number exceeds config limits */
 
465
 
 
466
            logprintfl (EUCAINFO, "Maximum disk available = %lld (under %s)\n", disk_max, ipath);
 
467
        }
 
468
 
 
469
        /* xm info will be used for memory and cores */
 
470
        s = system_output (get_xen_info_command_path);
 
471
#define GET_VALUE(name,var) \
 
472
        if (get_value (s, name, &var)) { \
 
473
            logprintfl (EUCAFATAL, "error: did not find %s in output from %s\n", name, get_xen_info_command_path); \
 
474
            free (s); \
 
475
            return ERROR_FATAL; \
 
476
        }
 
477
 
 
478
        /* calculate mem_max */
 
479
        {
 
480
            long long total_memory = 0;
 
481
            long long free_memory  = 0;
 
482
            long long dom0_min_mem = 0;
 
483
            
 
484
            GET_VALUE("total_memory", total_memory);
 
485
            GET_VALUE("free_memory", free_memory);
 
486
            GET_VALUE("dom0-min-mem", dom0_min_mem);
 
487
            
 
488
            mem_max = total_memory - 32 - dom0_min_mem;
 
489
            if (config_max_mem 
 
490
                && mem_max>config_max_mem) 
 
491
                mem_max = config_max_mem; /* reduce if the number exceeds config limits */
 
492
            logprintfl (EUCAINFO, "Maximum memory available = %lld\n", mem_max);
 
493
        }
 
494
 
 
495
        /* calculate cores_max */
 
496
        {
 
497
             long long nr_cpus; 
 
498
             long long nr_nodes; 
 
499
         
 
500
             GET_VALUE("nr_cpus", nr_cpus);
 
501
             GET_VALUE("nr_nodes", nr_nodes);
 
502
            
 
503
             cores_max = (int)nr_cpus * (int)nr_nodes; 
 
504
             /* unlike with disk or memory limits, use the limit as the
 
505
              * number of cores, regardless of whether the actual number
 
506
              * of cores is bigger or smaller */
 
507
             if (config_max_cores) 
 
508
                 cores_max = config_max_cores; 
 
509
             logprintfl (EUCAINFO, "Maximum cores available = %d\n", cores_max);
 
510
        }
 
511
    }
 
512
 
 
513
    pthread_t tcb;
 
514
    if ( pthread_create (&tcb, NULL, monitoring_thread, NULL) ) {
 
515
        logprintfl (EUCAFATAL, "failed to spawn a monitoring thread\n");
 
516
        return ERROR_FATAL;
 
517
    }
 
518
 
 
519
    return OK;
 
520
}
 
521
 
 
522
static int get_instance_xml (char *userId, char *instanceId, int ramdisk, char *disk_path, ncInstParams *params, char *privMac, char *pubMac, char *brname, char **xml)
 
523
{
 
524
    char buf [BUFSIZE];
 
525
 
 
526
    /* TODO: add --ephemeral? */
 
527
    if (ramdisk) {
 
528
        snprintf (buf, BUFSIZE, "%s --ramdisk", gen_libvirt_xml_command_path);
 
529
    } else {
 
530
        snprintf (buf, BUFSIZE, "%s", gen_libvirt_xml_command_path);
 
531
    }
 
532
    * xml = system_output (buf);
 
533
    if ( ( * xml ) == NULL ) {
 
534
        logprintfl (EUCAFATAL, "%s: %s\n", gen_libvirt_xml_command_path, strerror (errno));
 
535
        return ERROR;
 
536
    }
 
537
    
 
538
    /* the tags better be not substring of other tags: BA will substitute
 
539
     * ABABABAB */
 
540
    replace_string (xml, "BASEPATH", disk_path);
 
541
    replace_string (xml, "SWAPPATH", disk_path);
 
542
    replace_string (xml, "NAME", instanceId);
 
543
    replace_string (xml, "PRIVMACADDR", privMac);
 
544
    replace_string (xml, "PUBMACADDR", pubMac);
 
545
    replace_string (xml, "BRIDGEDEV", brname);
 
546
    snprintf(buf, BUFSIZE, "%d", params->memorySize * 1024); /* because libvirt wants memory in Kb, while we use Mb */
 
547
    replace_string (xml, "MEMORY", buf);
 
548
    snprintf(buf, BUFSIZE, "%d", params->numberOfCores);
 
549
    replace_string (xml, "VCPUS", buf);
 
550
    
 
551
    return 0;
 
552
}
 
553
 
 
554
void * startup_thread (void * arg)
 
555
{
 
556
    ncInstance * instance = (ncInstance *)arg;
 
557
    virConnectPtr conn = NULL;
 
558
    virDomainPtr dom = NULL;
 
559
    char * disk_path, * xml;
 
560
    char *brname=NULL;
 
561
    int error;
 
562
    
 
563
    conn = virConnectOpen("xen:///"); /* NULL means local hypervisor */
 
564
    if (conn == NULL) {
 
565
        logprintfl (EUCAFATAL, "failed to connect to hypervisor to start instance %s, abandoning it\n", instance->instanceId);
 
566
        change_state (instance, SHUTOFF);
 
567
        return NULL;
 
568
    }
 
569
    
 
570
    error = vnetStartNetwork (vnetconfig, instance->ncnet.vlan, NULL, NULL, &brname);
 
571
    if ( error ) {
 
572
        logprintfl (EUCAFATAL, "start network failed for instance %s, terminating it\n", instance->instanceId);
 
573
        change_state (instance, SHUTOFF);
 
574
        virConnectClose (conn);
 
575
        return NULL;
 
576
    }
 
577
    logprintfl (EUCAINFO, "network started for instance %s\n", instance->instanceId);
 
578
    
 
579
    error = scMakeInstanceImage (instance->userId, 
 
580
                                 instance->imageId, instance->imageURL, 
 
581
                                 instance->kernelId, instance->kernelURL, 
 
582
                                 instance->ramdiskId, instance->ramdiskURL, 
 
583
                                 instance->instanceId, instance->keyName, 
 
584
                                 &disk_path, xen_sem, 0);
 
585
    if (error) {
 
586
        logprintfl (EUCAFATAL, "Failed to prepare images for instance %s (error=%d)\n", instance->instanceId, error);
 
587
        change_state (instance, SHUTOFF);
 
588
        virConnectClose (conn);
 
589
        return NULL;
 
590
    }
 
591
    if (instance->state!=BOOTING) {
 
592
        logprintfl (EUCAFATAL, "Startup of instance %s was cancelled\n", instance->instanceId);
 
593
        change_state (instance, SHUTOFF);
 
594
        virConnectClose (conn);
 
595
        return NULL;
 
596
    }
 
597
    
 
598
    error = get_instance_xml (instance->userId, instance->instanceId, 
 
599
                              strnlen (instance->ramdiskId, CHAR_BUFFER_SIZE), /* 0 if no ramdisk */
 
600
                              disk_path, 
 
601
                              &(instance->params), 
 
602
                              instance->ncnet.privateMac, instance->ncnet.publicMac, 
 
603
                              brname, &xml);
 
604
    if (xml) logprintfl (EUCADEBUG2, "libvirt XML config:\n%s\n", xml);
 
605
    if (error) {
 
606
        logprintfl (EUCAFATAL, "Failed to create libvirt XML config for instance %s\n", instance->instanceId);
 
607
        change_state (instance, SHUTOFF);
 
608
        virConnectClose(conn);
 
609
        return NULL;
 
610
    }
 
611
    
 
612
    scStoreStringToInstanceFile (instance->userId, instance->instanceId, "libvirt.xml", xml); /* for debugging */
 
613
    scSaveInstanceInfo(instance); /* to enable NC recovery */
 
614
 
 
615
    /* we serialize domain creation as Xen can get confused with
 
616
     * too many simultaneous create requests */
 
617
    logprintfl (EUCADEBUG2, "about to start domain %s\n", instance->instanceId);
 
618
    print_running_domains ();
 
619
    sem_p (xen_sem); 
 
620
    dom = virDomainCreateLinux (conn, xml, 0);
 
621
    sem_v (xen_sem);
 
622
    if (dom == NULL) {
 
623
        logprintfl (EUCAFATAL, "hypervisor failed to start domain\n");
 
624
        change_state (instance, SHUTOFF);
 
625
        virConnectClose(conn);
 
626
        return NULL;
 
627
    }
 
628
    eventlog("NC", instance->userId, "", "instanceBoot", "begin"); /* TODO: bring back correlationId */
 
629
    
 
630
    virDomainFree(dom);
 
631
    virConnectClose(conn);
 
632
    logprintfl (EUCAINFO, "started VM instance %s\n", instance->instanceId);
 
633
    
 
634
    return NULL;
 
635
}
 
636
 
 
637
static int doRunInstance (ncMetadata *meta, char *instanceId, char *reservationId, ncInstParams *params, 
 
638
                   char *imageId, char *imageURL, 
 
639
                   char *kernelId, char *kernelURL, 
 
640
                   char *ramdiskId, char *ramdiskURL, 
 
641
                   char *keyName, 
 
642
                   char *privMac, char *pubMac, int vlan, 
 
643
                   char *userData, char *launchIndex, char **groupNames, int groupNamesSize,
 
644
                   ncInstance **outInst)
 
645
{
 
646
    ncInstance * instance = NULL;
 
647
    * outInst = NULL;
 
648
    pid_t pid;
 
649
    ncNetConf ncnet;
 
650
    int error;
 
651
 
 
652
    logprintfl (EUCAINFO, "doRunInstance() invoked (id=%s cores=%d disk=%d memory=%d\n", 
 
653
                instanceId, params->numberOfCores, params->diskSize, params->memorySize);
 
654
    logprintfl (EUCAINFO, "                         image=%s at %s\n", imageId, imageURL);
 
655
    logprintfl (EUCAINFO, "                         krnel=%s at %s\n", kernelId, kernelURL);
 
656
    if (ramdiskId) {
 
657
        logprintfl (EUCAINFO, "                         rmdsk=%s at %s\n", ramdiskId, ramdiskURL);
 
658
    }
 
659
    logprintfl (EUCAINFO, "                         vlan=%d priMAC=%s pubMAC=%s\n",
 
660
                vlan, privMac, pubMac);
 
661
    
 
662
    strcpy(ncnet.privateMac, privMac);
 
663
    strcpy(ncnet.publicMac, pubMac);
 
664
    ncnet.vlan = vlan;
 
665
 
 
666
    /* check as much as possible before forking off and returning */
 
667
    sem_p (inst_sem);
 
668
    instance = find_instance (&global_instances, instanceId);
 
669
    sem_v (inst_sem);
 
670
    if (instance) {
 
671
        logprintfl (EUCAFATAL, "Error: instance %s already running\n", instanceId);
 
672
        return 1; /* TODO: return meaningful error codes? */
 
673
    }
 
674
    if (!(instance = allocate_instance (instanceId, 
 
675
                                        reservationId,
 
676
                                        params, 
 
677
                                        imageId, imageURL,
 
678
                                        kernelId, kernelURL,
 
679
                                        ramdiskId, ramdiskURL,
 
680
                                        instance_state_names[PENDING], 
 
681
                                        PENDING, 
 
682
                                        meta->userId, 
 
683
                                        &ncnet, keyName,
 
684
                                        userData, launchIndex, groupNames, groupNamesSize))) {
 
685
        logprintfl (EUCAFATAL, "Error: could not allocate instance struct\n");
 
686
        return 2;
 
687
    }
 
688
    instance->state = BOOTING; /* TODO: do this in allocate_instance()? */
 
689
 
 
690
    sem_p (inst_sem); 
 
691
    error = add_instance (&global_instances, instance);
 
692
    sem_v (inst_sem);
 
693
    if ( error ) {
 
694
        free_instance (&instance);
 
695
        logprintfl (EUCAFATAL, "Error: could not save instance struct\n");
 
696
        return error;
 
697
    }
 
698
 
 
699
    instance->launchTime = time (NULL);
 
700
    instance->params.memorySize = params->memorySize;
 
701
    instance->params.numberOfCores = params->numberOfCores;
 
702
    instance->params.diskSize = params->diskSize;
 
703
    strcpy (instance->ncnet.privateIp, "0.0.0.0");
 
704
    strcpy (instance->ncnet.publicIp, "0.0.0.0");
 
705
 
 
706
    /* do the potentially long tasks in a thread */
 
707
 
 
708
    if ( pthread_create (&(instance->tcb), NULL, startup_thread, (void *)instance) ) {
 
709
        logprintfl (EUCAFATAL, "failed to spawn a VM startup thread\n");
 
710
        sem_p (inst_sem);
 
711
        remove_instance (&global_instances, instance);
 
712
        sem_v (inst_sem);
 
713
        free_instance (&instance);
 
714
        return 1;
 
715
    }
 
716
    
 
717
    * outInst = instance;
 
718
    return 0;
 
719
 
 
720
}
 
721
 
 
722
static int doRebootInstance(ncMetadata *meta, char *instanceId) {
 
723
  char cmd[256];
 
724
  int rc;
 
725
 
 
726
  snprintf(cmd, 256, "xm reboot %s", instanceId);
 
727
  rc = system(cmd);
 
728
 
 
729
  return(WEXITSTATUS(rc));
 
730
}
 
731
 
 
732
static int doGetConsoleOutput(ncMetadata *meta, char *instanceId, char **consoleOutput) {
 
733
  char *output;
 
734
  char cmd[256];
 
735
  int pid, status, rc, bufsize, fd;
 
736
  char filename[1024];  
 
737
 
 
738
  fprintf(stderr, "getconsoleoutput called\n");
 
739
 
 
740
  bufsize = sizeof(char) * 1024 * 64;
 
741
  output = malloc(bufsize);
 
742
  bzero(output, bufsize);
 
743
 
 
744
  snprintf(filename, 1024, "/tmp/consoleOutput.%s", instanceId);
 
745
  
 
746
  pid = fork();
 
747
  if (pid == 0) {
 
748
    int fd;
 
749
    fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644);
 
750
    if (fd < 0) {
 
751
      // error
 
752
    } else {
 
753
      dup2(fd, 2);
 
754
      dup2(2, 1);
 
755
      close(0);
 
756
      rc = execl("/usr/sbin/xm", "/usr/sbin/xm", "console", instanceId, NULL);
 
757
      fprintf(stderr, "execl() failed\n");
 
758
      close(fd);
 
759
    }
 
760
    exit(0);
 
761
  } else {
 
762
    int count;
 
763
    fd_set rfds;
 
764
    struct timeval tv;
 
765
    struct stat statbuf;
 
766
    
 
767
    count=0;
 
768
    while(count < 10000 && stat(filename, &statbuf) < 0) {count++;}
 
769
    fd = open(filename, O_RDONLY);
 
770
    if (fd < 0) {
 
771
      logprintfl (EUCAERROR, "ERROR: could not open consoleOutput file %s for reading\n", filename);
 
772
    } else {
 
773
      FD_ZERO(&rfds);
 
774
      FD_SET(fd, &rfds);
 
775
      tv.tv_sec = 0;
 
776
      tv.tv_usec = 500000;
 
777
      rc = select(1, &rfds, NULL, NULL, &tv);
 
778
      bzero(output, bufsize);
 
779
      
 
780
      count = 0;
 
781
      rc = 1;
 
782
      while(rc && count < 1000) {
 
783
        rc = read(fd, output, bufsize-1);
 
784
        count++;
 
785
      }
 
786
      close(fd);
 
787
    }
 
788
    kill(pid, 9);
 
789
    wait(&status);
 
790
  }
 
791
  
 
792
  unlink(filename);
 
793
  
 
794
  if (output[0] == '\0') {
 
795
    snprintf(output, bufsize, "EMPTY");
 
796
  }
 
797
  
 
798
  *consoleOutput = base64_enc((unsigned char *)output, strlen(output));
 
799
  free(output);
 
800
  
 
801
  return(0);
 
802
}
 
803
 
 
804
static int doTerminateInstance (ncMetadata *meta, char *instanceId, int *shutdownState, int *previousState)
 
805
{
 
806
    ncInstance *instance, *vninstance;
 
807
    int left;
 
808
 
 
809
    logprintfl (EUCAINFO, "doTerminateInstance() invoked (id=%s)\n", instanceId);
 
810
    sem_p (inst_sem); 
 
811
    instance = find_instance(&global_instances, instanceId);
 
812
    sem_v (inst_sem);
 
813
    if ( instance == NULL ) return NOT_FOUND;
 
814
 
 
815
    /* try stopping the Xen domain */
 
816
    virConnectPtr conn = virConnectOpen("xen:///"); /* NULL means local hypervisor */
 
817
    if (conn == NULL) {
 
818
        logprintfl (EUCAFATAL, "Failed to connect to hypervisor\n");
 
819
    } else {
 
820
        virDomainPtr dom = virDomainLookupByName(conn, instanceId);
 
821
        if (dom) {
 
822
            /* also protect 'destroy' commands, just in case */
 
823
            sem_p (xen_sem);
 
824
            int err=virDomainDestroy (dom);
 
825
            sem_v (xen_sem);
 
826
            if (err==0) {
 
827
                logprintfl (EUCAINFO, "destroyed Xen domain for instance %s\n", instanceId);
 
828
            }
 
829
            virDomainFree(dom); /* necessary? */
 
830
        } else {
 
831
            if (instance->state != BOOTING) {
 
832
                logprintfl (EUCAWARN, "warning: domain %s to be terminated not running on hypervisor\n", instanceId);
 
833
            }
 
834
        }
 
835
        virConnectClose (conn);
 
836
    }
 
837
 
 
838
    /* change the state and let the monitoring_thread clean up state */
 
839
    change_state (instance, SHUTOFF);
 
840
    * previousState = instance->stateCode;
 
841
    * shutdownState = instance->stateCode;
 
842
 
 
843
    return 0;
 
844
}
 
845
 
 
846
static int doDescribeInstances (ncMetadata *meta, char **instIds, int instIdsLen, ncInstance ***outInsts, int *outInstsLen)
 
847
{
 
848
    logprintfl (EUCAINFO, "doDescribeInstances() invoked\n");
 
849
    * outInstsLen = 0;
 
850
    * outInsts = NULL;
 
851
 
 
852
    sem_p (inst_sem);
 
853
    if (instIdsLen == 0) { /* describe all instances */
 
854
        int total = total_instances (&global_instances);
 
855
        if ( total ) {
 
856
            ncInstance * instance;
 
857
            int i, k = 0;
 
858
            
 
859
            * outInsts = malloc (sizeof(ncInstance *)*total);
 
860
            if ( (* outInsts) == NULL ) goto out_oom;
 
861
            
 
862
            for (i=0; (instance = get_instance (&global_instances))!=NULL; i++) {
 
863
                /* only pick ones the user is allowed to see */
 
864
                if (!strcmp(meta->userId, admin_user_id) || /* admin will see all */
 
865
                    !strcmp(meta->userId, instance->userId)) { /* owner */
 
866
                    (* outInsts)[k++] = instance;
 
867
                }
 
868
            }
 
869
            * outInstsLen = k;
 
870
        }
 
871
        
 
872
    } else { /* describe specific instances */
 
873
        ncInstance * instance;
 
874
        int i, j, k = 0;
 
875
 
 
876
        * outInsts = malloc (sizeof(ncInstance *)*(instIdsLen));
 
877
        if ( (* outInsts) == NULL ) goto out_oom;
 
878
        
 
879
        for (i=0; (instance = get_instance (&global_instances))!=NULL; i++) {        
 
880
            for (j=0; j<instIdsLen; j++) {
 
881
                if ( !strcmp(instance->instanceId, instIds[j]) ) {
 
882
                    /* only pick ones the user is allowed to see */
 
883
                    if (!strcmp(meta->userId, admin_user_id) || /* admin will see all */
 
884
                        !strcmp(meta->userId, instance->userId)) { /* owner */
 
885
                        (* outInsts)[k++] = instance;
 
886
                    }
 
887
                }
 
888
                /* TODO: do we complain about instIds[j] that weren't found? */
 
889
            }
 
890
        }
 
891
        * outInstsLen = k;
 
892
    }
 
893
    sem_v (inst_sem);
 
894
    return 0;
 
895
 
 
896
 out_oom:
 
897
    sem_v (inst_sem);
 
898
    return OUT_OF_MEMORY;
 
899
}
 
900
 
 
901
static int doDescribeResource (ncMetadata *meta, char *resourceType, ncResource **outRes)
 
902
{
 
903
    ncResource * res;
 
904
    ncInstance * inst;
 
905
 
 
906
    /* stats to re-calculate now */
 
907
    long long mem_free;
 
908
    long long disk_free;
 
909
    int cores_free;
 
910
 
 
911
    /* intermediate sums */
 
912
    long long sum_mem = 0;  /* for known domains: sum of requested memory */
 
913
    long long sum_disk = 0; /* for known domains: sum of requested disk sizes */
 
914
    int sum_cores = 0;      /* for known domains: sum of requested cores */
 
915
 
 
916
    logprintfl (EUCAINFO, "doDescribeResource() invoked\n");
 
917
 
 
918
    * outRes = NULL;
 
919
    sem_p (inst_sem); 
 
920
    while ((inst=get_instance(&global_instances))!=NULL) {
 
921
        if (inst->state == TEARDOWN) continue; /* they don't take up resources */
 
922
        sum_mem += inst->params.memorySize;
 
923
        sum_disk += (inst->params.diskSize + SWAP_SIZE);
 
924
        sum_cores += inst->params.numberOfCores;
 
925
    }
 
926
    sem_v (inst_sem);
 
927
    
 
928
    disk_free = disk_max - sum_disk;
 
929
    if ( disk_free < 0 ) disk_free = 0; /* should not happen */
 
930
    
 
931
    mem_free = mem_max - sum_mem;
 
932
    if ( mem_free < 0 ) mem_free = 0; /* should not happen */
 
933
 
 
934
    cores_free = cores_max - sum_cores; /* TODO: should we -1 for dom0? */
 
935
    if ( cores_free < 0 ) cores_free = 0; /* due to timesharing */
 
936
 
 
937
    /* check for potential overflow - should not happen */
 
938
    if (mem_max > INT_MAX ||
 
939
        mem_free > INT_MAX ||
 
940
        disk_max > INT_MAX ||
 
941
        disk_free > INT_MAX) {
 
942
        logprintfl (EUCAERROR, "stats integer overflow error (bump up the units?)\n");
 
943
        logprintfl (EUCAERROR, "   memory: max=%-10lld free=%-10lld\n", mem_max, mem_free);
 
944
        logprintfl (EUCAERROR, "     disk: max=%-10lld free=%-10lld\n", disk_max, disk_free);
 
945
        logprintfl (EUCAERROR, "    cores: max=%-10d free=%-10d\n", cores_max, cores_free);
 
946
        logprintfl (EUCAERROR, "       INT_MAX=%-10d\n", INT_MAX);
 
947
        return 10;
 
948
    }
 
949
    
 
950
    res = allocate_resource ("OK", mem_max, mem_free, disk_max, disk_free, cores_max, cores_free, "none");
 
951
    if (res == NULL) {
 
952
        logprintfl (EUCAERROR, "Out of memory\n");
 
953
        return 1;
 
954
    }
 
955
    * outRes = res;
 
956
    return 0;
 
957
}
 
958
 
 
959
static int doStartNetwork(ncMetadata *ccMeta, char **remoteHosts, int remoteHostsLen, int port, int vlan) {
 
960
  int rc, ret, i, status;
 
961
  char *brname;
 
962
 
 
963
  logprintfl (EUCAINFO, "StartNetwork(): called\n");
 
964
 
 
965
  rc = vnetStartNetwork(vnetconfig, vlan, NULL, NULL, &brname);
 
966
  if (rc) {
 
967
    ret = 1;
 
968
    logprintfl (EUCAERROR, "StartNetwork(): ERROR return from vnetStartNetwork %d\n", rc);
 
969
  } else {
 
970
    logprintfl (EUCAINFO, "StartNetwork(): SUCCESS return from vnetStartNetwork %d\n", rc);
 
971
    ret = 0;
 
972
  }
 
973
  logprintfl (EUCAINFO, "StartNetwork(): done\n");
 
974
  return(ret);
 
975
}
 
976
 
 
977
static int doAttachVolume (ncMetadata *meta, char *instanceId, char *volumeId, char *remoteDev, char *localDev)
 
978
{
 
979
    ncInstance *instance;
 
980
    int ret = OK;
 
981
 
 
982
    logprintfl (EUCAINFO, "doAttachVolume() invoked (id=%s vol=%s remote=%s local=%s)\n", instanceId, volumeId, remoteDev, localDev);
 
983
    sem_p (inst_sem); 
 
984
    instance = find_instance(&global_instances, instanceId);
 
985
    sem_v (inst_sem);
 
986
    if ( instance == NULL ) 
 
987
        return NOT_FOUND;
 
988
 
 
989
    ncVolume * volume;
 
990
    sem_p (inst_sem);
 
991
    volume = add_volume (instance, volumeId, remoteDev, localDev);
 
992
    sem_v (inst_sem);
 
993
    if ( volume == NULL ) {
 
994
        logprintfl (EUCAFATAL, "ERROR: Failed to save the volume record, aborting volume attachment\n");
 
995
        return ERROR;
 
996
    }
 
997
 
 
998
    /* try attaching to the Xen domain */
 
999
    virConnectPtr conn = virConnectOpen("xen:///"); /* NULL means local hypervisor */
 
1000
    if (conn == NULL) {
 
1001
        logprintfl (EUCAFATAL, "Failed to connect to hypervisor\n");
 
1002
        ret = ERROR;
 
1003
 
 
1004
    } else {
 
1005
        virDomainPtr dom = virDomainLookupByName(conn, instanceId);
 
1006
        if (dom) {
 
1007
 
 
1008
            int err = 0;
 
1009
            char xml [1024];
 
1010
            snprintf (xml, 1024, "<disk type='block'><driver name='phy'/><source dev='%s'/><target dev='%s'/></disk>", remoteDev, localDev);
 
1011
 
 
1012
            /* protect Xen calls, just in case */
 
1013
            sem_p (xen_sem);
 
1014
            //            int err = virDomainAttachDevice (dom, xml);
 
1015
            sem_v (xen_sem);
 
1016
            if (err) {
 
1017
                logprintfl (EUCAERROR, "AttachVolume() failed (err=%d) XML=%s\n", err, xml);
 
1018
                ret = ERROR;
 
1019
            } else {
 
1020
                logprintfl (EUCAINFO, "attached %s to %s in domain %s\n", remoteDev, localDev, instanceId);
 
1021
            }
 
1022
            virDomainFree(dom);
 
1023
        } else {
 
1024
            if (instance->state != BOOTING) {
 
1025
                logprintfl (EUCAWARN, "warning: domain %s not running on hypervisor, cannot attach device\n", instanceId);
 
1026
            }
 
1027
            ret = ERROR;
 
1028
        }
 
1029
        virConnectClose (conn);
 
1030
    }
 
1031
    return ret;
 
1032
}
 
1033
 
 
1034
static int doDetachVolume (ncMetadata *meta, char *instanceId, char *volumeId, char *remoteDev, char *localDev, int force)
 
1035
{
 
1036
    ncInstance *instance;
 
1037
    int ret = OK;
 
1038
 
 
1039
    logprintfl (EUCAINFO, "doDetachVolume() invoked (id=%s vol=%s remote=%s local=%s force=%d)\n", instanceId, volumeId, remoteDev, localDev, force);
 
1040
    sem_p (inst_sem); 
 
1041
    instance = find_instance(&global_instances, instanceId);
 
1042
    sem_v (inst_sem);
 
1043
    if ( instance == NULL ) 
 
1044
        return NOT_FOUND;
 
1045
 
 
1046
    ncVolume * volume;
 
1047
    sem_p (inst_sem);
 
1048
    volume = free_volume (instance, volumeId, remoteDev, localDev);
 
1049
    sem_v (inst_sem);
 
1050
    if ( volume == NULL ) {
 
1051
        logprintfl (EUCAFATAL, "ERROR: Failed to find and remove volume record, aborting volume detachment\n");
 
1052
        return ERROR;
 
1053
    }
 
1054
 
 
1055
    /* try attaching to the Xen domain */
 
1056
    virConnectPtr conn = virConnectOpen("xen:///"); /* NULL means local hypervisor */
 
1057
    if (conn == NULL) {
 
1058
        logprintfl (EUCAFATAL, "Failed to connect to hypervisor\n");
 
1059
        ret = ERROR;
 
1060
 
 
1061
    } else {
 
1062
        virDomainPtr dom = virDomainLookupByName(conn, instanceId);
 
1063
        if (dom) {
 
1064
            int err = 0;
 
1065
            char xml [1024];
 
1066
            snprintf (xml, 1024, "<disk type='block'><driver name='phy'/><source dev='%s'/><target dev='%s'/></disk>", remoteDev, localDev);
 
1067
 
 
1068
            /* protect Xen calls, just in case */
 
1069
            sem_p (xen_sem);
 
1070
//            int err = virDomainDetachDevice (dom, xml);
 
1071
            sem_v (xen_sem);
 
1072
            if (err) {
 
1073
                logprintfl (EUCAERROR, "DetachVolume() failed (err=%d) XML=%s\n", err, xml);
 
1074
                ret = ERROR;
 
1075
            } else {
 
1076
                logprintfl (EUCAINFO, "detached %s as %s in domain %s\n", remoteDev, localDev, instanceId);
 
1077
            }
 
1078
            virDomainFree(dom);
 
1079
        } else {
 
1080
            if (instance->state != BOOTING) {
 
1081
                logprintfl (EUCAWARN, "warning: domain %s not running on hypervisor, cannot detach device\n", instanceId);
 
1082
            }
 
1083
            ret = ERROR;
 
1084
        }
 
1085
        virConnectClose (conn);
 
1086
    }
 
1087
    return ret;
 
1088
}
 
1089
 
 
1090
struct handlers xen_libvirt_handlers = {
 
1091
    .name = "xen",
 
1092
    .doInitialize        = doInitialize,
 
1093
    .doDescribeInstances = doDescribeInstances,
 
1094
    .doRunInstance       = doRunInstance,
 
1095
    .doTerminateInstance = doTerminateInstance,
 
1096
    .doRebootInstance    = doRebootInstance,
 
1097
    .doGetConsoleOutput  = doGetConsoleOutput,
 
1098
    .doDescribeResource  = doDescribeResource,
 
1099
    .doStartNetwork      = doStartNetwork,
 
1100
    .doAttachVolume      = doAttachVolume,
 
1101
    .doDetachVolume      = doDetachVolume
 
1102
};
 
1103