Skip to content

Commit

Permalink
GuestInfo: Add build step for exposing GuestInfo
Browse files Browse the repository at this point in the history
Variables IP, Hostname, ToolsStatus, ToolsRunningStatus, ToolsVersion,
ToolsVersionStatus,  GuestState, GuestId, GuestFamily, GuestFullName,
AppHeartbeatStatus, GuestOperationsReady, InteractiveGuestOperationsReady are exposed.
These are exposed via reflection.
All primitive types for GuestInfo are added as environmental variables.
  • Loading branch information
damienbiggs committed Jan 28, 2015
1 parent bcf1f52 commit ad50250
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package org.jenkinsci.plugins.vsphere.builders;

import com.vmware.vim25.GuestInfo;
import com.vmware.vim25.VirtualMachineToolsStatus;
import com.vmware.vim25.mo.VirtualMachine;

import hudson.EnvVars;
import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.model.EnvironmentContributingAction;
import hudson.util.FormValidation;
import org.jenkinsci.plugins.vsphere.VSphereBuildStep;
import org.jenkinsci.plugins.vsphere.tools.VSphere;
import org.jenkinsci.plugins.vsphere.tools.VSphereException;
import org.jenkinsci.plugins.vsphere.tools.VSphereLogger;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

import javax.servlet.ServletException;

import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Expose guest info for the named VM as environmental variables.
* Information on variables can be found here.
* https://www.vmware.com/support/developer/converter-sdk/conv55_apireference/vim.vm.GuestInfo.html
*/
public class ExposeGuestInfo extends VSphereBuildStep {

private final String vm;
private final String envVariablePrefix;

@DataBoundConstructor
public ExposeGuestInfo(final String vm, final String envVariablePrefix) throws VSphereException {
this.vm = vm;
this.envVariablePrefix = envVariablePrefix;
}

public String getVm() {
return vm;
}

public String getEnvVariablePrefix() {
return envVariablePrefix;
}

@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws Exception {
PrintStream jLogger = listener.getLogger();
EnvVars env;
try {
env = build.getEnvironment(listener);
} catch (Exception e) {
throw new VSphereException(e);
}
env.overrideAll(build.getBuildVariables()); // Add in matrix axes..
String vmName = env.expand(vm);

VSphereLogger.vsLogger(jLogger, "Injecting guest info for VM \"" + vmName + "\" as environment variables");

VirtualMachine vsphereVm = vsphere.getVmByName(vmName);
VSphereEnvAction envAction = createGuestInfoEnvAction(vsphereVm, jLogger);
build.addAction(envAction);

VSphereLogger.vsLogger(jLogger, "Successfully injected guest info for VM \"" + vmName + "\"");
return true;
}

private VSphereEnvAction createGuestInfoEnvAction(VirtualMachine vsphereVm, PrintStream jLogger) throws InvocationTargetException,
IllegalAccessException {
GuestInfo guestInfo = vsphereVm.getGuest();

VSphereEnvAction envAction = new VSphereEnvAction();

List USABLE_CLASS_TYPES = Arrays.asList(String.class, boolean.class,
Boolean.class, int.class, Integer.class);


for (Method method : GuestInfo.class.getDeclaredMethods()) {
if (!method.getName().startsWith("get") || method.getParameterTypes().length > 0) {
continue;
}

String variableName = method.getName().substring(3);
Class returnType = method.getReturnType();
if (!USABLE_CLASS_TYPES.contains(returnType) && !returnType.isEnum()) {
VSphereLogger.vsLogger(jLogger, "Skipped \"" + variableName
+ "\" as it is of type " + returnType.toString());
continue;
}

Object value = method.invoke(guestInfo);
// don't add variable for null value
if (value == null) {
VSphereLogger.vsLogger(jLogger, "Skipped \"" + variableName + "\" as it is a null value");
continue;
}

String environmentVariableName = envVariablePrefix + "_" + variableName;
String environmentVariableValue = String.valueOf(value);

envAction.add(environmentVariableName, environmentVariableValue);
VSphereLogger.vsLogger(jLogger, "Added environmental variable \"" + environmentVariableName
+ "\" with a value of \"" + environmentVariableValue + "\"");
}

return envAction;
}

@Extension
public static class ExposeGuestInfoDescriptor extends VSphereBuildStepDescriptor {

@Override
public String getDisplayName() {
return Messages.vm_title_ExposeGuestInfo();
}

public FormValidation doCheckVm(@QueryParameter String value)
throws IOException, ServletException {

if (value.length() == 0)
return FormValidation.error(Messages.validation_required("the VM name"));
return FormValidation.ok();
}

public FormValidation doCheckEnvVariablePrefix(@QueryParameter String value)
throws IOException, ServletException {

if (value.length() == 0)
return FormValidation.error(Messages.validation_required("the environment variable prefix"));
return FormValidation.ok();
}

public FormValidation doTestData(@QueryParameter String serverName,
@QueryParameter String vm) {
try {

if (vm.length() == 0 || serverName.length()==0)
return FormValidation.error(Messages.validation_requiredValues());

VSphere vsphere = getVSphereCloudByName(serverName).vSphereInstance();

if (vm.indexOf('$') >= 0)
return FormValidation.warning(Messages.validation_buildParameter("VM"));

VirtualMachine vmObj = vsphere.getVmByName(vm);
if ( vmObj == null)
return FormValidation.error(Messages.validation_notFound("VM"));

if (vmObj.getConfig().template)
return FormValidation.error(Messages.validation_notActually("VM"));

return FormValidation.ok(Messages.validation_success());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

/**
* Copied this private class from PowerOn as a way to add environment variables.
* By rights I should put this somewhere as a public class than can be shared.
* Not apparent though as to where it should go.
*
* @author Lordahl
*/
private static class VSphereEnvAction implements EnvironmentContributingAction {
// Decided not to record this data in build.xml, so marked transient:
private transient Map<String,String> data = new HashMap<String,String>();

private void add(String key, String val) {
if (data==null) return;
data.put(key, val);
}

public void buildEnvVars(AbstractBuild<?,?> build, EnvVars env) {
if (data!=null) env.putAll(data);
}

public String getIconFileName() { return null; }
public String getDisplayName() { return null; }
public String getUrlName() { return null; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!--
Copyright 2013, MANDIANT, Eric Lordahl
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:entry title="${%VM}" field="vm">
<f:textbox />
</f:entry>

<f:entry title="${%EnvVariablePrefix}" field="envVariablePrefix">
<f:textbox default="VSPHERE" />
</f:entry>

<f:validateButton title="${%Check Data}" progress="${%Testing...}" method="testData" with="serverName,vm"/>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Prefix for guest info environmental variables. E.g. for prefix VM1, variables would be VM1_IP, VM1_HostName etc.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div>
The name of the VM to expose guest info for.<br/>
Variables IP, Hostname, ToolsStatus, ToolsRunningStatus, ToolsVersion, ToolsVersionStatus, GuestState, GuestId,
GuestFamily, GuestFullName, AppHeartbeatStatus, GuestOperationsReady, InteractiveGuestOperationsReady are exposed.
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ vm.title.Rename=Rename VM
vm.title.RenameSnapshot=Rename Snapshot
vm.title.TakeSnapshot=Take Snapshot
vm.title.DeleteSnapshot=Delete a Snapshot
vm.title.ExposeGuestInfo=Expose Guest Info

vm.reconfigure.Add=Add
vm.reconfigure.Edit=Edit
Expand Down

0 comments on commit ad50250

Please sign in to comment.