static int doAttachSystemDisk ( struct nc_state_t *nc, ncMetadata *meta, char *instanceId, char *isoPath) { ncInstance *instance; virConnectPtr *conn; virDomainPtr dom = NULL; char xml[MAX_PATH]={'\0'}; int err; snprintf (xml, sizeof(xml), "<disk type='block' device='cdrom'><source dev='%s'/><target dev='hdc' bus='ide'/><readonly/></disk>", isoPath); //logprintfl(EUCAINFO, "doAttachSystemDisk(): founded %s [%s---%s---%d]\n", instanceId,__FILE__, __FUNCTION__, __LINE__); sem_p(inst_sem); instance = find_instance(&global_instances, instanceId); sem_v(inst_sem); if (instance == NULL || (instance->state != RUNNING&& instance->state != BLOCKED&& instance->state !=PAUSED)) { logprintfl(EUCAINFO, "doAttachSystemDisk(): found %s failed or instance->state!=RUNNING||BLOCKED||PAUSED [file:%s---line:%d]\n", instanceId, __FILE__, __LINE__); return NOT_FOUND; } conn = check_hypervisor_conn(); if (conn) { /* snprintf(cmd, sizeof(cmd), "virsh attach-disk %s %s hdc --type cdrom --mode readonly",instanceId, isoPath); logprintfl(EUCAINFO, "xiongm: cmd=%s [%s---%s---%d]\n",cmd, __FILE__, __FUNCTION__, __LINE__); system(cmd); */ dom = NULL; sem_p(hyp_sem); dom = virDomainLookupByName(*conn, instanceId); sem_v(hyp_sem); if (dom) { sem_p (hyp_sem); err = virDomainAttachDevice (dom, xml); sem_v (hyp_sem); if(err != 0) { logprintfl(EUCAINFO,"virDomainAttachDevice failed. err=%d\n",err); return 1; } } logprintfl(EUCAINFO,"doAttachSystemDisk success.\n"); return 0; } else { logprintfl(EUCAINFO, "doAttachSystemDisk(): no connect hypervisior [file:%s---line:%d]\n",__FILE__, __LINE__); return 1; } }
//! //! Defines the thread that does the actual reboot of an instance. //! //! @param[in] arg a transparent pointer to the argument passed to this thread handler //! //! @return Always return NULL //! static void *rebooting_thread(void *arg) { #define REATTACH_RETRIES 3 int i = 0; int err = 0; int error = 0; int rc = 0; int log_level_for_devstring = EUCATRACE; char *xml = NULL; char *remoteDevStr = NULL; char path[MAX_PATH] = ""; char lpath[MAX_PATH] = ""; char resourceName[1][MAX_SENSOR_NAME_LEN] = { {0} }; char resourceAlias[1][MAX_SENSOR_NAME_LEN] = { {0} }; ncVolume *volume = NULL; ncInstance *instance = ((ncInstance *) arg); virDomainPtr dom = NULL; virConnectPtr *conn = NULL; logprintfl(EUCADEBUG, "[%s] spawning rebooting thread\n", instance->instanceId); if ((xml = file2str(instance->libvirtFilePath)) == NULL) { logprintfl(EUCAERROR, "[%s] cannot obtain instance XML file %s\n", instance->instanceId, instance->libvirtFilePath); return NULL; } if ((conn = check_hypervisor_conn()) == NULL) { logprintfl(EUCAERROR, "[%s] cannot restart instance %s, abandoning it\n", instance->instanceId, instance->instanceId); change_state(instance, SHUTOFF); EUCA_FREE(xml); return NULL; } sem_p(hyp_sem); { dom = virDomainLookupByName(*conn, instance->instanceId); } sem_v(hyp_sem); if (dom == NULL) { EUCA_FREE(xml); return NULL; } sem_p(hyp_sem); { // for KVM, must stop and restart the instance logprintfl(EUCADEBUG, "[%s] destroying domain\n", instance->instanceId); error = virDomainDestroy(dom); // @todo change to Shutdown? is this synchronous? virDomainFree(dom); } sem_v(hyp_sem); if (error) { EUCA_FREE(xml); return NULL; } // Add a shift to values of three of the metrics: ones that // drop back to zero after a reboot. The shift, which is based // on the latest value, ensures that values sent upstream do // not go backwards . sensor_shift_metric(instance->instanceId, "CPUUtilization"); sensor_shift_metric(instance->instanceId, "NetworkIn"); sensor_shift_metric(instance->instanceId, "NetworkOut"); // domain is now shut down, create a new one with the same XML sem_p(hyp_sem); { logprintfl(EUCAINFO, "[%s] rebooting\n", instance->instanceId); dom = virDomainCreateLinux(*conn, xml, 0); } sem_v(hyp_sem); EUCA_FREE(xml); euca_strncpy(resourceName[0], instance->instanceId, MAX_SENSOR_NAME_LEN); sensor_refresh_resources(resourceName, resourceAlias, 1); // refresh stats so we set base value accurately // re-attach each volume previously attached for (i = 0; i < EUCA_MAX_VOLUMES; ++i) { volume = &instance->volumes[i]; if (strcmp(volume->stateName, VOL_STATE_ATTACHED) && strcmp(volume->stateName, VOL_STATE_ATTACHING)) continue; // skip the entry unless attached or attaching logprintfl(EUCADEBUG, "[%s] volumes [%d] = '%s'\n", instance->instanceId, i, volume->stateName); // get credentials, decrypt them remoteDevStr = get_iscsi_target(volume->remoteDev); if (!remoteDevStr || !strstr(remoteDevStr, "/dev")) { logprintfl(EUCAERROR, "[%s] failed to get local name of host iscsi device when re-attaching\n", instance->instanceId); rc = 1; } else { // set the path snprintf(path, sizeof(path), EUCALYPTUS_VOLUME_XML_PATH_FORMAT, instance->instancePath, volume->volumeId); // vol-XXX.xml snprintf(lpath, sizeof(lpath), EUCALYPTUS_VOLUME_LIBVIRT_XML_PATH_FORMAT, instance->instancePath, volume->volumeId); // vol-XXX-libvirt.xml // read in libvirt XML, which may have been modified by the hook above if ((xml = file2str(lpath)) == NULL) { logprintfl(EUCAERROR, "[%s][%s] failed to read volume XML from %s\n", instance->instanceId, volume->volumeId, lpath); rc = 1; } } EUCA_FREE(remoteDevStr); if (!rc) { // zhill - wrap with retry in case libvirt is dumb. err = 0; for (i = 1; i < REATTACH_RETRIES; i++) { // protect libvirt calls because we've seen problems during concurrent libvirt invocations sem_p(hyp_sem); { err = virDomainAttachDevice(dom, xml); } sem_v(hyp_sem); if (err) { logprintfl(EUCAERROR, "[%s][%s] failed to reattach volume (attempt %d of %d)\n", instance->instanceId, volume->volumeId, i, REATTACH_RETRIES); logprintfl(EUCADEBUG, "[%s][%s] error from virDomainAttachDevice: %d xml: %s\n", instance->instanceId, volume->volumeId, err, xml); sleep(3); // sleep a bit and retry } else { logprintfl(EUCAINFO, "[%s][%s] volume reattached as '%s'\n", instance->instanceId, volume->volumeId, volume->localDevReal); break; } } log_level_for_devstring = EUCATRACE; if (err) log_level_for_devstring = EUCADEBUG; logprintfl(log_level_for_devstring, "[%s][%s] remote device string: %s\n", instance->instanceId, volume->volumeId, volume->remoteDev); } EUCA_FREE(xml); } if (dom == NULL) { logprintfl(EUCAERROR, "[%s] failed to restart instance\n", instance->instanceId); change_state(instance, SHUTOFF); return NULL; } sem_p(hyp_sem); { virDomainFree(dom); } sem_v(hyp_sem); return NULL; #undef REATTACH_RETRIES }
static int doAttachVolume ( struct nc_state_t *nc, ncMetadata *meta, char *instanceId, char *volumeId, char *remoteDev, char *localDev) { int ret = OK, rc; ncInstance * instance; char localDevReal[32]; virConnectPtr *conn; struct stat statbuf; // fix up format of incoming local dev name, if we need to ret = convert_dev_names (localDev, localDevReal, NULL); if (ret) return ret; sem_p (inst_sem); instance = find_instance(&global_instances, instanceId); sem_v (inst_sem); if ( instance == NULL ) return NOT_FOUND; /* try attaching to the Xen domain */ conn = check_hypervisor_conn(); if (conn) { sem_p(hyp_sem); virDomainPtr dom = virDomainLookupByName(*conn, instanceId); sem_v(hyp_sem); if (dom) { int err = 0; char xml [1024]; int is_iscsi_target = 0; char *local_iscsi_dev; rc = 0; if(check_iscsi(remoteDev)) { is_iscsi_target = 1; /*get credentials, decrypt them*/ //parse_target(remoteDev); /*login to target*/ local_iscsi_dev = connect_iscsi_target(nc->connect_storage_cmd_path, remoteDev); if (!local_iscsi_dev || !strstr(local_iscsi_dev, "/dev")) { logprintfl(EUCAERROR, "AttachVolume(): failed to connect to iscsi target\n"); rc = 1; } else { snprintf (xml, 1024, "<disk type='block'><driver name='phy'/><source dev='%s'/><target dev='%s'/></disk>", local_iscsi_dev, localDevReal); } } else { snprintf (xml, 1024, "<disk type='block'><driver name='phy'/><source dev='%s'/><target dev='%s'/></disk>", remoteDev, localDevReal); rc = stat(remoteDev, &statbuf); if (rc) { logprintfl(EUCAERROR, "AttachVolume(): cannot locate local block device file '%s'\n", remoteDev); rc = 1; } } if (!rc) { /* protect Xen calls, just in case */ sem_p (hyp_sem); err = virDomainAttachDevice (dom, xml); sem_v (hyp_sem); if (err) { logprintfl (EUCAERROR, "AttachVolume() failed (err=%d) XML=%s\n", err, xml); // rc = doDetachVolume(nc, meta, instanceId, volumeId, remoteDev, localDev, 1); ret = ERROR; } else { logprintfl (EUCAINFO, "attached %s to %s in domain %s\n", remoteDev, localDevReal, instanceId); } } else { ret = ERROR; } sem_p(hyp_sem); virDomainFree(dom); sem_v(hyp_sem); if(is_iscsi_target) { if (local_iscsi_dev) free(local_iscsi_dev); } } else { if (instance->state != BOOTING && instance->state != STAGING) { logprintfl (EUCAWARN, "warning: domain %s not running on hypervisor, cannot attach device\n", instanceId); } ret = ERROR; } } else { ret = ERROR; } if (ret==OK) { ncVolume * volume; sem_p (inst_sem); volume = add_volume (instance, volumeId, remoteDev, localDevReal, localDevReal, "attached"); scSaveInstanceInfo(instance); /* to enable NC recovery */ sem_v (inst_sem); if ( volume == NULL ) { logprintfl (EUCAFATAL, "ERROR: Failed to save the volume record, aborting volume attachment\n"); return ERROR; } } return ret; }
/* thread that does the actual reboot */ static void * rebooting_thread (void *arg) { virConnectPtr *conn; ncInstance * instance = (ncInstance *)arg; struct stat statbuf; int rc = 0; // RESTARTING, // FAILED_RESTART, // SUCCESS_RESTART logprintfl (EUCADEBUG, "{%u} spawning rebooting thread\n", (unsigned int)pthread_self()); char * xml = file2str (instance->libvirtFilePath); if (xml == NULL) { logprintfl (EUCAERROR, "cannot obtain XML file %s\n", instance->libvirtFilePath); return NULL; } conn = check_hypervisor_conn(); if (! conn) { logprintfl (EUCAERROR, "cannot restart instance %s, abandoning it\n", instance->instanceId); change_state (instance, SHUTOFF); free (xml); return NULL; } sem_p(inst_sem); change_task_state (instance, REBOOTING); copy_instances (); sem_v(inst_sem); sem_p (hyp_sem); virDomainPtr dom = virDomainLookupByName(*conn, instance->instanceId); sem_v (hyp_sem); if (dom == NULL) { free (xml); sem_p(inst_sem); change_task_state (instance, FAILED_REBOOT); sem_v(inst_sem); return NULL; } sem_p (hyp_sem); // for KVM, must stop and restart the instance int error = virDomainDestroy (dom); // TODO: change to Shutdown? TODO: is this synchronous? virDomainFree(dom); sem_v (hyp_sem); if (error) { free (xml); sem_p(inst_sem); change_task_state (instance, FAILED_REBOOT); sem_v(inst_sem); return NULL; } #if 0 // domain is now shut down, create a new one with the same XML sem_p (hyp_sem); dom = virDomainCreateLinux (*conn, xml, 0); sem_v (hyp_sem); free (xml); char *remoteDevStr=NULL; // re-attach each volume previously attached for (int i=0; i < EUCA_MAX_VOLUMES; ++i) { ncVolume * volume = &instance->volumes[i]; if (strcmp (volume->stateName, VOL_STATE_ATTACHED) && strcmp (volume->stateName, VOL_STATE_ATTACHING)) continue; // skip the entry unless attached or attaching char attach_xml[1024]; int rc; // get credentials, decrypt them remoteDevStr = get_iscsi_target (volume->remoteDev); if (!remoteDevStr || !strstr(remoteDevStr, "/dev")) { logprintfl(EUCAERROR, "Reattach-volume: failed to get local name of host iscsi device\n"); rc = 1; } else { rc = gen_libvirt_attach_xml (volume->volumeId, instance, volume->localDevReal, remoteDevStr, attach_xml, sizeof(attach_xml)); } if (remoteDevStr) free (remoteDevStr); if (!rc) { int err; sem_p (hyp_sem); err = virDomainAttachDevice (dom, attach_xml); sem_v (hyp_sem); if (err) { logprintfl (EUCAERROR, "virDomainAttachDevice() failed (err=%d) XML=%s\n", err, attach_xml); } else { logprintfl (EUCAINFO, "reattached '%s' to '%s' in domain %s\n", volume->remoteDev, volume->localDevReal, instance->instanceId); } } } #endif int ret=restore_and_volume_instance(instance->instanceId); //20130122-th if (ret==1) { logprintfl (EUCAERROR, "Failed to REBOOT instance %s\n", instance->instanceId); change_state (instance, SHUTOFF); sem_p(inst_sem); change_task_state (instance, FAILED_REBOOT); sem_v(inst_sem); return NULL; } sem_p(inst_sem); change_task_state (instance, SUCCESS_REBOOT); save_instance_struct (instance); copy_instances(); sem_v (inst_sem); return NULL; }