// Create a name representing a virtual machine // Usually this name is used in vm config file bool VMType::createVMName(ClassAd *ad, MyString& vmname) { if( !ad ) { return false; } if( create_name_for_VM(ad, vmname) == false ) { vmprintf(D_ALWAYS, "Cannot make the name of VM\n"); return false; } return true; }
void VMUniverseMgr::killVM(VMStarterInfo *info) { if( !info ) { return; } if( !m_vm_type.Length() || !m_vmgahp_server.Length() ) { return; } if( info->m_vm_pid > 0 ) { dprintf( D_ALWAYS, "In VMUniverseMgr::killVM(), " "Sending SIGKILL to Process[%d]\n", (int)info->m_vm_pid); daemonCore->Send_Signal(info->m_vm_pid, SIGKILL); } MyString matchstring; MyString workingdir; workingdir.formatstr("%s%cdir_%ld", info->m_execute_dir.Value(), DIR_DELIM_CHAR, (long)info->m_pid); if( (strcasecmp(m_vm_type.Value(), CONDOR_VM_UNIVERSE_XEN ) == MATCH) || (strcasecmp(m_vm_type.Value(), CONDOR_VM_UNIVERSE_KVM) == 0)) { if( create_name_for_VM(&info->m_job_ad, matchstring) == false ) { dprintf(D_ALWAYS, "VMUniverseMgr::killVM() : " "cannot make the name of VM\n"); return; } }else { // Except Xen, we need the path of working directory of Starter // in order to destroy VM. matchstring = workingdir; } killVM( matchstring.Value() ); }
void VMGahpServer::killVM(void) { if( m_vm_type.IsEmpty() || m_vmgahp_server.IsEmpty() ) { return; } if( m_workingdir.IsEmpty() ) { dprintf(D_ALWAYS, "VMGahpServer::killVM() : no workingdir\n"); return; } MyString matchstring; if( (strcasecmp(m_vm_type.Value(), CONDOR_VM_UNIVERSE_XEN ) == MATCH) || (strcasecmp(m_vm_type.Value(), CONDOR_VM_UNIVERSE_KVM ) == MATCH) ) { if( create_name_for_VM(m_job_ad, matchstring) == false ) { dprintf(D_ALWAYS, "VMGahpServer::killVM() : " "cannot make the name of VM\n"); return; } } else { // Except Xen, we need the path of working directory of Starter // in order to destroy a VM. matchstring = m_workingdir; } if( matchstring.IsEmpty() ) { dprintf(D_ALWAYS, "VMGahpServer::killVM() : empty matchstring\n"); return; } // vmgahp is daemonCore, so we need to add -f -t options of daemonCore. // Then, try to execute vmgahp with // vmtype <vmtype> match <string>" ArgList systemcmd; systemcmd.AppendArg(m_vmgahp_server); systemcmd.AppendArg("-f"); if( m_include_gahp_log ) { systemcmd.AppendArg("-t"); } systemcmd.AppendArg("-M"); systemcmd.AppendArg(VMGAHP_KILL_MODE); systemcmd.AppendArg("vmtype"); systemcmd.AppendArg(m_vm_type); systemcmd.AppendArg("match"); systemcmd.AppendArg(matchstring); #if !defined(WIN32) if( can_switch_ids() ) { MyString tmp_str; tmp_str.sprintf("%d", (int)get_condor_uid()); SetEnv("VMGAHP_USER_UID", tmp_str.Value()); } else if (Starter->condorPrivSepHelper() != NULL) { MyString tmp_str; tmp_str.sprintf("%d", (int)Starter->condorPrivSepHelper()->get_uid()); SetEnv("VMGAHP_USER_UID", tmp_str.Value()); } #endif priv_state oldpriv; if( (strcasecmp(m_vm_type.Value(), CONDOR_VM_UNIVERSE_XEN ) == MATCH) || (strcasecmp(m_vm_type.Value(), CONDOR_VM_UNIVERSE_KVM ) == MATCH) ) { oldpriv = set_root_priv(); } else { oldpriv = set_user_priv(); } int ret = my_system(systemcmd); set_priv(oldpriv); if( ret == 0 ) { dprintf( D_FULLDEBUG, "VMGahpServer::killVM() is called with " "'%s'\n", matchstring.Value()); } else { dprintf( D_FULLDEBUG, "VMGahpServer::killVM() failed!\n"); } return; }
int VMProc::StartJob() { MyString err_msg; dprintf(D_FULLDEBUG,"Inside VMProc::StartJob()\n"); // set up a FamilyInfo structure to register a family // with the ProcD in its call to DaemonCore::Create_Process FamilyInfo fi; // take snapshots at no more than 15 seconds in between, by default fi.max_snapshot_interval = param_integer("PID_SNAPSHOT_INTERVAL", 15); char const *dedicated_account = Starter->jic->getExecuteAccountIsDedicated(); if (dedicated_account) { // using login-based family tracking fi.login = dedicated_account; // The following message is documented in the manual as the // way to tell whether the dedicated execution account // configuration is being used. dprintf(D_ALWAYS, "Tracking process family by login \"%s\"\n", fi.login); } // Find vmgahp server location char* vmgahpfile = param( "VM_GAHP_SERVER" ); if( !vmgahpfile || (access(vmgahpfile,X_OK) < 0) ) { // make certain the vmgahp server program is executable dprintf(D_ALWAYS, "vmgahp server cannot be found/executed\n"); reportErrorToStartd(); if (vmgahpfile) { free(vmgahpfile); vmgahpfile = NULL; } return false; } m_vmgahp_server = vmgahpfile; free(vmgahpfile); if( !JobAd ) { dprintf(D_ALWAYS, "No JobAd in VMProc::StartJob()!\n"); return false; } // // // // // // // Get IWD // // // // // // //const char* job_iwd = Starter->jic->jobRemoteIWD(); //dprintf( D_ALWAYS, "IWD: %s\n", job_iwd ); // // // // // // // Environment // // // // // // // Now, instantiate an Env object so we can manipulate the // environment as needed. Env job_env; char *env_str = param( "STARTER_JOB_ENVIRONMENT" ); MyString env_errors; if( ! job_env.MergeFromV1RawOrV2Quoted(env_str,&env_errors) ) { dprintf( D_ALWAYS, "Aborting VMProc::StartJob: " "%s\nThe full value for STARTER_JOB_ENVIRONMENT: " "%s\n",env_errors.Value(),env_str); if( env_str ) { free(env_str); } return false; } if( env_str ) { free(env_str); } // Now, let the starter publish any env vars it wants to into // the mainjob's env... Starter->PublishToEnv( &job_env ); // // // // // // // Misc + Exec // // // // // // // compute job's renice value by evaluating the machine's // JOB_RENICE_INCREMENT in the context of the job ad... int nice_inc = 0; char* ptmp = param( "JOB_RENICE_INCREMENT" ); if( ptmp ) { // insert renice expr into our copy of the job ad MyString reniceAttr = "Renice = "; reniceAttr += ptmp; if( !JobAd->Insert( reniceAttr.Value() ) ) { dprintf( D_ALWAYS, "ERROR: failed to insert JOB_RENICE_INCREMENT " "into job ad, Aborting OsProc::StartJob...\n" ); free( ptmp ); return 0; } // evaluate if( JobAd->EvalInteger( "Renice", NULL, nice_inc ) ) { dprintf( D_ALWAYS, "Renice expr \"%s\" evaluated to %d\n", ptmp, nice_inc ); } else { dprintf( D_ALWAYS, "WARNING: job renice expr (\"%s\") doesn't " "eval to int! Using default of 10...\n", ptmp ); nice_inc = 10; } // enforce valid ranges for nice_inc if( nice_inc < 0 ) { dprintf( D_FULLDEBUG, "WARNING: job renice value (%d) is too " "low: adjusted to 0\n", nice_inc ); nice_inc = 0; } else if( nice_inc > 19 ) { dprintf( D_FULLDEBUG, "WARNING: job renice value (%d) is too " "high: adjusted to 19\n", nice_inc ); nice_inc = 19; } ASSERT( ptmp ); free( ptmp ); ptmp = NULL; } else { // if JOB_RENICE_INCREMENT is undefined, default to 10 nice_inc = 10; } // Get job name MyString vm_job_name; if( JobAd->LookupString( ATTR_JOB_CMD, vm_job_name) != 1 ) { err_msg.sprintf("%s cannot be found in job classAd.", ATTR_JOB_CMD); dprintf(D_ALWAYS, "%s\n", err_msg.Value()); Starter->jic->notifyStarterError( err_msg.Value(), true, CONDOR_HOLD_CODE_FailedToCreateProcess, 0); return false; } m_job_name = vm_job_name; // vm_type should be from ClassAd MyString vm_type_name; if( JobAd->LookupString( ATTR_JOB_VM_TYPE, vm_type_name) != 1 ) { err_msg.sprintf("%s cannot be found in job classAd.", ATTR_JOB_VM_TYPE); dprintf(D_ALWAYS, "%s\n", err_msg.Value()); Starter->jic->notifyStarterError( err_msg.Value(), true, CONDOR_HOLD_CODE_FailedToCreateProcess, 0); return false; } vm_type_name.lower_case(); m_vm_type = vm_type_name; // get vm checkpoint flag from ClassAd m_vm_checkpoint = false; JobAd->LookupBool(ATTR_JOB_VM_CHECKPOINT, m_vm_checkpoint); // If there exists MAC or IP address for a checkpointed VM, // we use them as initial values. MyString string_value; if( JobAd->LookupString(ATTR_VM_CKPT_MAC, string_value) == 1 ) { m_vm_mac = string_value; } /* string_value = ""; if( JobAd->LookupString(ATTR_VM_CKPT_IP, string_value) == 1 ) { m_vm_ip = string_value; } */ ClassAd recovery_ad = *JobAd; MyString vm_name; if ( strcasecmp( m_vm_type.Value(), CONDOR_VM_UNIVERSE_KVM ) == MATCH || strcasecmp( m_vm_type.Value(), CONDOR_VM_UNIVERSE_XEN ) == MATCH ) { ASSERT( create_name_for_VM( JobAd, vm_name ) ); } else { vm_name = Starter->GetWorkingDir(); } recovery_ad.Assign( "JobVMId", vm_name.Value() ); Starter->WriteRecoveryFile( &recovery_ad ); // // // Now everything is ready to start a vmgahp server // // dprintf( D_ALWAYS, "About to start new VM\n"); Starter->jic->notifyJobPreSpawn(); //create vmgahp server m_vmgahp = new VMGahpServer(m_vmgahp_server.Value(), m_vm_type.Value(), JobAd); ASSERT(m_vmgahp); m_vmgahp->start_err_msg = ""; if( m_vmgahp->startUp(&job_env, Starter->GetWorkingDir(), nice_inc, &fi) == false ) { JobPid = -1; err_msg = "Failed to start vm-gahp server"; dprintf( D_ALWAYS, "%s\n", err_msg.Value()); if( m_vmgahp->start_err_msg.Length() > 0 ) { m_vmgahp->start_err_msg.chomp(); err_msg = m_vmgahp->start_err_msg; } reportErrorToStartd(); Starter->jic->notifyStarterError( err_msg.Value(), true, 0, 0); delete m_vmgahp; m_vmgahp = NULL; return false; } // Set JobPid and num_pids in user_proc.h and os_proc.h JobPid = m_vmgahp->getVMGahpServerPid(); num_pids++; VMGahpRequest *new_req = new VMGahpRequest(m_vmgahp); ASSERT(new_req); new_req->setMode(VMGahpRequest::BLOCKING); // When we call vmStart, vmStart may create an ISO file. // So we need to give some more time to vmgahp. new_req->setTimeout(m_vmoperation_timeout + 120); int p_result; p_result = new_req->vmStart(m_vm_type.Value(), Starter->GetWorkingDir()); // Because req is blocking mode, result should be VMGAHP_REQ_COMMAND_DONE if(p_result != VMGAHP_REQ_COMMAND_DONE) { err_msg = "Failed to create a new VM"; dprintf(D_ALWAYS, "%s\n", err_msg.Value()); m_vmgahp->printSystemErrorMsg(); reportErrorToStartd(); Starter->jic->notifyStarterError( err_msg.Value(), true, 0, 0); delete new_req; delete m_vmgahp; m_vmgahp = NULL; // To make sure that vmgahp server exits //daemonCore->Send_Signal(JobPid, SIGKILL); daemonCore->Kill_Family(JobPid); return false; } if( new_req->checkResult(err_msg) == false ) { dprintf(D_ALWAYS, "%s\n", err_msg.Value()); m_vmgahp->printSystemErrorMsg(); if( !strcmp(err_msg.Value(), VMGAHP_ERR_INTERNAL) || !strcmp(err_msg.Value(), VMGAHP_ERR_CRITICAL) ) { reportErrorToStartd(); } Starter->jic->notifyStarterError( err_msg.Value(), true, CONDOR_HOLD_CODE_FailedToCreateProcess, 0); delete new_req; delete m_vmgahp; m_vmgahp = NULL; // To make sure that vmgahp server exits //daemonCore->Send_Signal(JobPid, SIGKILL); daemonCore->Kill_Family(JobPid); return false; } Gahp_Args *result_args; result_args = new_req->getResult(); // Set virtual machine id m_vm_id = (int)strtol(result_args->argv[2], (char **)NULL, 10); if( m_vm_id <= 0 ) { m_vm_id = 0; dprintf(D_ALWAYS, "Received invalid virtual machine id from vm-gahp\n"); m_vmgahp->printSystemErrorMsg(); reportErrorToStartd(); Starter->jic->notifyStarterError( "VMGahp internal error", true, 0, 0); delete new_req; delete m_vmgahp; m_vmgahp = NULL; // To make sure that vmgahp server exits //daemonCore->Send_Signal(JobPid, SIGKILL); daemonCore->Kill_Family(JobPid); return false; } delete new_req; new_req = NULL; m_vmgahp->setVMid(m_vm_id); // We give considerable time(30 secs) to bring // the just created VM into a fully compliant state sleep(30); // Initialize data structures for VM process m_vm_pid = 0; memset(&m_vm_exited_pinfo, 0, sizeof(m_vm_exited_pinfo)); memset(&m_vm_alive_pinfo, 0, sizeof(m_vm_alive_pinfo)); // Find the actual process dealing with VM // Most virtual machine programs except Xen creates a process // that actually deals with a created VM. The process may be // directly created by a virtual machine program and // the parent pid of the process may be 1. // So our default Procd daemon is unable to include this process. // Here, we don't need to create a new Procd daemon for this process. // In VMware, this process is a single process that has no childs. // So we will just use simple ProcAPI to get usage of this process. // PIDofVM will return the pid of such process. // If there is no such process like in Xen, PIDofVM will return 0. int vm_pid = PIDofVM(); setVMPID(vm_pid); m_vmstatus_tid = daemonCore->Register_Timer(m_vmstatus_interval, m_vmstatus_interval, (TimerHandlercpp)&VMProc::CheckStatus, "VMProc::CheckStatus", this); // Set job_start_time in user_proc.h job_start_time.getTime(); dprintf( D_ALWAYS, "StartJob for VM succeeded\n"); return true; }