Esempio n. 1
0
// 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;
}
Esempio n. 2
0
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() );
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}