From e9b5ed107337186cd139a42f3ea0ef8ac4e97af8 Mon Sep 17 00:00:00 2001 From: Damien Biggs Date: Wed, 28 Jan 2015 12:27:33 -0500 Subject: [PATCH 1/2] GuestInfo: Add build step for exposing GuestInfo 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. --- .../vsphere/builders/ExposeGuestInfo.java | 192 ++++++++++++++++++ .../builders/ExposeGuestInfo/config.jelly | 27 +++ .../help-envVariablePrefix.html | 3 + .../builders/ExposeGuestInfo/help-vm.html | 5 + .../vsphere/builders/Messages.properties | 1 + 5 files changed, 228 insertions(+) create mode 100644 src/main/java/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo.java create mode 100644 src/main/resources/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo/config.jelly create mode 100644 src/main/resources/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo/help-envVariablePrefix.html create mode 100644 src/main/resources/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo/help-vm.html diff --git a/src/main/java/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo.java b/src/main/java/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo.java new file mode 100644 index 00000000..7d025f7c --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo.java @@ -0,0 +1,192 @@ +package org.jenkinsci.plugins.vsphere.builders; + +import com.vmware.vim25.GuestInfo; +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, "Exposing 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 exposed 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 data = new HashMap(); + + 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; } + } +} diff --git a/src/main/resources/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo/config.jelly b/src/main/resources/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo/config.jelly new file mode 100644 index 00000000..5443ae26 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo/config.jelly @@ -0,0 +1,27 @@ + + + + + + + + + + + + + diff --git a/src/main/resources/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo/help-envVariablePrefix.html b/src/main/resources/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo/help-envVariablePrefix.html new file mode 100644 index 00000000..6c813c5c --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo/help-envVariablePrefix.html @@ -0,0 +1,3 @@ +
+ Prefix for guest info environmental variables. E.g. for prefix VM1, variables would be VM1_IP, VM1_HostName etc. +
\ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo/help-vm.html b/src/main/resources/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo/help-vm.html new file mode 100644 index 00000000..64f8f39d --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/vsphere/builders/ExposeGuestInfo/help-vm.html @@ -0,0 +1,5 @@ +
+ The name of the VM to expose guest info for.
+ Variables IP, Hostname, ToolsStatus, ToolsRunningStatus, ToolsVersion, ToolsVersionStatus, GuestState, GuestId, + GuestFamily, GuestFullName, AppHeartbeatStatus, GuestOperationsReady, InteractiveGuestOperationsReady are exposed. +
diff --git a/src/main/resources/org/jenkinsci/plugins/vsphere/builders/Messages.properties b/src/main/resources/org/jenkinsci/plugins/vsphere/builders/Messages.properties index 4a2c8c13..bce998f8 100644 --- a/src/main/resources/org/jenkinsci/plugins/vsphere/builders/Messages.properties +++ b/src/main/resources/org/jenkinsci/plugins/vsphere/builders/Messages.properties @@ -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 From b189fa36479487e058499b3e42daccfba0175d9c Mon Sep 17 00:00:00 2001 From: Damien Biggs Date: Thu, 29 Jan 2015 17:21:28 -0500 Subject: [PATCH 2/2] Logging: Log that VSPEHERE_IP variable is exposed We didn't know about this variable until looking at the code. It's quite useful to know about it. --- .../java/org/jenkinsci/plugins/vsphere/builders/PowerOn.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/vsphere/builders/PowerOn.java b/src/main/java/org/jenkinsci/plugins/vsphere/builders/PowerOn.java index d949b4d0..8b6afb7e 100644 --- a/src/main/java/org/jenkinsci/plugins/vsphere/builders/PowerOn.java +++ b/src/main/java/org/jenkinsci/plugins/vsphere/builders/PowerOn.java @@ -84,7 +84,10 @@ private boolean powerOn(final AbstractBuild build, Launcher launcher, fina } VSphereLogger.vsLogger(jLogger, "Successfully retrieved IP for \""+expandedVm+"\" : "+vmIP); - VSphereEnvAction envAction = new VSphereEnvAction(); + + // useful to tell user about the environment variable + VSphereLogger.vsLogger(jLogger, "Exposing " + vmIP + " as environment variable VSPHERE_IP"); + VSphereEnvAction envAction = new VSphereEnvAction(); envAction.add("VSPHERE_IP", vmIP); build.addAction(envAction); return true;