Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JENKINS-44796] Robustness improvements #85

Merged
merged 1 commit into from
Aug 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions src/main/java/org/jenkinsci/plugins/vSphereCloudSlaveTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -357,9 +357,19 @@ protected Object readResolve() {
}

public vSphereCloudProvisionedSlave provision(final String cloneName, final TaskListener listener) throws VSphereException, FormException, IOException, InterruptedException {
vSphereCloudProvisionedSlave slave = null;
final PrintStream logger = listener.getLogger();
final Map<String, String> resolvedExtraConfigParameters = calculateExtraConfigParameters(cloneName, listener);
final VSphere vSphere = getParent().vSphereInstance();
final vSphereCloudProvisionedSlave slave;
try {
slave = provision(cloneName, logger, resolvedExtraConfigParameters, vSphere);
} finally {
vSphere.disconnect();
}
return slave;
}

private vSphereCloudProvisionedSlave provision(final String cloneName, final PrintStream logger, final Map<String, String> resolvedExtraConfigParameters, final VSphere vSphere) throws VSphereException, FormException, IOException {
final boolean POWER_ON = true;
final boolean useCurrentSnapshot;
final String snapshotToUse;
Expand All @@ -377,7 +387,7 @@ public vSphereCloudProvisionedSlave provision(final String cloneName, final Task
snapshotToUse = null;
}
try {
vSphere.cloneOrDeployVm(cloneName, this.masterImageName, this.linkedClone, this.resourcePool, this.cluster, this.datastore, this.folder, useCurrentSnapshot, snapshotToUse, POWER_ON, this.customizationSpec, logger);
vSphere.cloneOrDeployVm(cloneName, this.masterImageName, this.linkedClone, this.resourcePool, this.cluster, this.datastore, this.folder, useCurrentSnapshot, snapshotToUse, POWER_ON, resolvedExtraConfigParameters, this.customizationSpec, logger);
LOGGER.log(Level.FINE, "Created new VM {0} from image {1}", new Object[]{ cloneName, this.masterImageName });
} catch (VSphereDuplicateException ex) {
final String vmJenkinsUrl = findWhichJenkinsThisVMBelongsTo(vSphere, cloneName);
Expand All @@ -392,13 +402,21 @@ public vSphereCloudProvisionedSlave provision(final String cloneName, final Task
LOGGER.log(Level.SEVERE, "VM {0} name clashes with one we wanted to use, but it doesn't belong to this Jenkins server: it belongs to {1}. You MUST reconfigure one of these Jenkins servers to use a different naming strategy so that we no longer get clashes within vSphere host {2}. i.e. change the cloneNamePrefix on one/both to ensure uniqueness.", new Object[]{ cloneName, vmJenkinsUrl, this.getParent().getVsHost() } );
throw ex;
}
} catch (VSphereException ex) {
// if anything else went wrong, attempt to tidy up
try {
vSphere.destroyVm(cloneName, false);
} catch (Exception logOnly) {
LOGGER.log(Level.SEVERE,
"Unable to create and power-on new VM " + cloneName + " (cloned from image "
+ this.masterImageName
+ ") and, worse, bits of the VM may still exist as the attempt to delete the remains also failed.",
logOnly);
}
throw ex;
}
vSphereCloudProvisionedSlave slave = null;
try {
final Map<String, String> resolvedExtraConfigParameters = calculateExtraConfigParameters(cloneName, listener);
if( !resolvedExtraConfigParameters.isEmpty() ) {
LOGGER.log(Level.FINE, "Provisioning slave {0} with guestinfo properties {1}", new Object[]{ cloneName, resolvedExtraConfigParameters });
vSphere.setExtraConfigParameters(cloneName, resolvedExtraConfigParameters);
}
final ComputerLauncher configuredLauncher = determineLauncher(vSphere, cloneName);
final RetentionStrategy<?> configuredStrategy = determineRetention();
final String snapshotNameForLauncher = ""; /* we don't make the launcher do anything with snapshots because our clone won't be created with any */
Expand All @@ -410,7 +428,6 @@ public vSphereCloudProvisionedSlave provision(final String cloneName, final Task
vSphere.destroyVm(cloneName, false);
}
}
vSphere.disconnect();
return slave;
}

Expand Down
29 changes: 24 additions & 5 deletions src/main/java/org/jenkinsci/plugins/vsphere/tools/VSphere.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,9 @@ public void disconnect() {
public void deployVm(String cloneName, String sourceName, boolean linkedClone, String resourcePoolName, String cluster, String datastoreName, String folderName, boolean powerOn, String customizationSpec, PrintStream jLogger) throws VSphereException {
final boolean useCurrentSnapshotIsFALSE = false;
final String namedSnapshotIsNULL = null;
final Map<String, String> extraConfigParameters = null;
logMessage(jLogger, "Deploying new vm \""+ cloneName + "\" from template \""+sourceName+"\"");
cloneOrDeployVm(cloneName, sourceName, linkedClone, resourcePoolName, cluster, datastoreName, folderName, useCurrentSnapshotIsFALSE, namedSnapshotIsNULL, powerOn, customizationSpec, jLogger);
cloneOrDeployVm(cloneName, sourceName, linkedClone, resourcePoolName, cluster, datastoreName, folderName, useCurrentSnapshotIsFALSE, namedSnapshotIsNULL, powerOn, extraConfigParameters, customizationSpec, jLogger);
}

/**
Expand All @@ -149,8 +150,9 @@ public void deployVm(String cloneName, String sourceName, boolean linkedClone, S
public void cloneVm(String cloneName, String sourceName, boolean linkedClone, String resourcePoolName, String cluster, String datastoreName, String folderName, boolean powerOn, String customizationSpec, PrintStream jLogger) throws VSphereException {
final boolean useCurrentSnapshotIsTRUE = true;
final String namedSnapshotIsNULL = null;
final Map<String, String> extraConfigParameters = null;
logMessage(jLogger, "Creating a " + (linkedClone?"shallow":"deep") + " clone of \"" + sourceName + "\" to \"" + cloneName + "\"");
cloneOrDeployVm(cloneName, sourceName, linkedClone, resourcePoolName, cluster, datastoreName, folderName, useCurrentSnapshotIsTRUE, namedSnapshotIsNULL, powerOn, customizationSpec, jLogger);
cloneOrDeployVm(cloneName, sourceName, linkedClone, resourcePoolName, cluster, datastoreName, folderName, useCurrentSnapshotIsTRUE, namedSnapshotIsNULL, powerOn, extraConfigParameters, customizationSpec, jLogger);
}

/**
Expand Down Expand Up @@ -183,14 +185,22 @@ public void cloneVm(String cloneName, String sourceName, boolean linkedClone, St
* @param powerOn
* If true then the new VM will be switched on after it has been
* created.
* @param extraConfigParameters
* (Optional) parameters to set in the VM's "extra config"
* object. This data can then be read back at a later stage.In
* the case of parameters whose name starts "guestinfo.", the
* parameter can be read by the VMware Tools on the client OS.
* e.g. a variable named "guestinfo.Foo" with value "Bar" could
* be read on the guest using the command-line
* <tt>vmtoolsd --cmd "info-get guestinfo.Foo"</tt>.
* @param customizationSpec
* (Optional) Customization spec to use for this VM, or null
* @param jLogger
* Where to log to.
* @throws VSphereException
* if anything goes wrong.
*/
public void cloneOrDeployVm(String cloneName, String sourceName, boolean linkedClone, String resourcePoolName, String cluster, String datastoreName, String folderName, boolean useCurrentSnapshot, final String namedSnapshot, boolean powerOn, String customizationSpec, PrintStream jLogger) throws VSphereException {
public void cloneOrDeployVm(String cloneName, String sourceName, boolean linkedClone, String resourcePoolName, String cluster, String datastoreName, String folderName, boolean useCurrentSnapshot, final String namedSnapshot, boolean powerOn, Map<String, String> extraConfigParameters, String customizationSpec, PrintStream jLogger) throws VSphereException {
try {
final VirtualMachine sourceVm = getVmByName(sourceName);
if (sourceVm==null) {
Expand Down Expand Up @@ -227,7 +237,11 @@ public void cloneOrDeployVm(String cloneName, String sourceName, boolean linkedC
logMessage(jLogger, "Clone of " + sourceType + " \"" + sourceName + "\" will be based on current snapshot \"" + currentSnapShot.toString() + "\".");
cloneSpec.setSnapshot(currentSnapShot.getMOR());
}

if (extraConfigParameters != null && !extraConfigParameters.isEmpty()) {
logMessage(jLogger, "Clone of " + sourceType + " \"" + sourceName + "\" will have extra configuration parameters " + extraConfigParameters + ".");
VirtualMachineConfigSpec cs = createVMConfigSpecFromExtraConfigParameters(extraConfigParameters);
cloneSpec.setConfig(cs);
}
if (customizationSpec != null && customizationSpec.length() > 0) {
logMessage(jLogger, "Clone of " + sourceType + " \"" + sourceName + "\" will use customization specification \"" + customizationSpec + "\".");
CustomizationSpecItem spec = getCustomizationSpecByName(customizationSpec);
Expand Down Expand Up @@ -1052,6 +1066,11 @@ public DistributedVirtualSwitch getDistributedVirtualSwitchByPortGroup(
* If an error occurred.
*/
public void setExtraConfigParameters(String vmName, Map<String, String> parameters) throws VSphereException {
VirtualMachineConfigSpec cs = createVMConfigSpecFromExtraConfigParameters(parameters);
reconfigureVm(vmName, cs);
}

private static VirtualMachineConfigSpec createVMConfigSpecFromExtraConfigParameters(Map<String, String> parameters) {
VirtualMachineConfigSpec cs = new VirtualMachineConfigSpec();
OptionValue[] ourOptionValues = new OptionValue[parameters.size()];
List<OptionValue> optionValues = new ArrayList<>();
Expand All @@ -1065,7 +1084,7 @@ public void setExtraConfigParameters(String vmName, Map<String, String> paramete
ourOptionValues[i] = optionValues.get(i);
}
cs.setExtraConfig(ourOptionValues);
reconfigureVm(vmName, cs);
return cs;
}

private void logMessage(PrintStream jLogger, String message) {
Expand Down