Skip to content

Commit

Permalink
- implemented check for already connected networks
Browse files Browse the repository at this point in the history
- implemented retry  loop for resource busy (ICNR)
- implemented disconnection of existing tunnels for delete configuration
  • Loading branch information
ptoma98 committed Jan 11, 2014
1 parent a9ca70c commit 853e229
Show file tree
Hide file tree
Showing 3 changed files with 407 additions and 93 deletions.
242 changes: 203 additions & 39 deletions src/main/java/org/jenkinsci/plugins/skytap/DeleteConfigurationStep.java
Expand Up @@ -22,28 +22,37 @@
package org.jenkinsci.plugins.skytap;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Iterator;

import hudson.Extension;
import hudson.model.AbstractBuild;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPut;
import org.jenkinsci.plugins.skytap.SkytapBuilder.SkytapAction;
import org.jenkinsci.plugins.skytap.SkytapBuilder.SkytapActionDescriptor;
import org.kohsuke.stapler.DataBoundConstructor;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.thoughtworks.xstream.annotations.XStreamOmitField;

public class DeleteConfigurationStep extends SkytapAction {

private final String configurationID;
private final String configurationFile;

// these vars will be initialized when the step is run

@XStreamOmitField
private SkytapGlobalVariables globalVars;

@XStreamOmitField
private String authCredentials;

Expand All @@ -54,7 +63,7 @@ public class DeleteConfigurationStep extends SkytapAction {
// id from the json element
@XStreamOmitField
private String runtimeConfigurationID;

@DataBoundConstructor
public DeleteConfigurationStep(String configurationID,
String configurationFile) {
Expand All @@ -63,46 +72,194 @@ public DeleteConfigurationStep(String configurationID,
this.configurationID = configurationID;
this.configurationFile = configurationFile;
}

public Boolean executeStep(AbstractBuild build, SkytapGlobalVariables globalVars) {

JenkinsLogger.defaultLogMessage("----------------------------------------");
private ArrayList getTunnelList(String configId) throws SkytapException {

ArrayList tunnelIdList = new ArrayList();

// build network listing url
String listNetworksURL = buildNetworkListURL(configId);

JenkinsLogger.log("Getting network list for configuration with id: "
+ configId);

// execute http get
HttpGet hg = SkytapUtils.buildHttpGetRequest(listNetworksURL,
this.authCredentials);

// execute request
String httpRespBody = "";

try {
httpRespBody = SkytapUtils.executeHttpRequest(hg);
} catch (SkytapException e1) {
throw e1;
}

// get JSON Array of networks
JsonParser parser = new JsonParser();
JsonElement je = parser.parse(httpRespBody);
JsonArray ja = je.getAsJsonArray();

Iterator iter = ja.iterator();

// iterate through each network and get tunnels
while (iter.hasNext()) {
JsonElement networkElement = (JsonElement) iter.next();

String networkId = networkElement.getAsJsonObject().get("id")
.getAsString();

JenkinsLogger.log("Getting tunnels for network with id: "
+ networkId);

JsonElement tunnelsElement = networkElement.getAsJsonObject().get(
"tunnels");
JsonArray tunnelArray = tunnelsElement.getAsJsonArray();

// loop through tunnels and retrieve ids
for (int i = 0; i < tunnelArray.size(); i++) {
JsonElement tunnelElement = tunnelArray.get(i);
String id = tunnelElement.getAsJsonObject().get("id")
.getAsString();
JenkinsLogger.log("Adding tunnel: " + id + " to list.");

tunnelIdList.add(id);
}

}

return tunnelIdList;

}

private String buildNetworkListURL(String configId) {

StringBuilder sb = new StringBuilder("https://cloud.skytap.com/");
sb.append("configurations/");
sb.append(configId);
sb.append("/networks");
// https://cloud.skytap.com/configurations/1155792/networks

return sb.toString();
}

private String buildDisconnectTunnelURL(String tunnelId) {

StringBuilder sb = new StringBuilder("https://cloud.skytap.com/");

sb.append("tunnels/");
sb.append(tunnelId);
sb.append("/");

return sb.toString();

// https://cloud.skytap.com/tunnels/tunnel-794010-998866/
}

/**
* Executes API request to disconnect a connection between 2 networks
* (tunnel).
*
* @param tid
* @throws SkytapException
*/
private void disconnectTunnel(String tid) throws SkytapException {

JenkinsLogger.log("Disconnecting tunnel with id: " + tid);

// build request url
String reqUrl = buildDisconnectTunnelURL(tid);

// execute request
String httpRespBody = "";

HttpDelete hd = SkytapUtils.buildHttpDeleteRequest(reqUrl,
authCredentials);

httpRespBody = SkytapUtils.executeHttpDeleteRequest(hd);

if (httpRespBody.equals("")) {
throw new SkytapException(
"An error occurred while attempting to disconnect " + tid);
} else {
JenkinsLogger.log("Tunnel " + tid
+ " was disconnected successfully.");
}
}

public Boolean executeStep(AbstractBuild build,
SkytapGlobalVariables globalVars) {

JenkinsLogger
.defaultLogMessage("----------------------------------------");
JenkinsLogger.defaultLogMessage("Delete Configuration");
JenkinsLogger.defaultLogMessage("----------------------------------------");

if(preFlightSanityChecks()==false){
JenkinsLogger
.defaultLogMessage("----------------------------------------");

if (preFlightSanityChecks() == false) {
return false;
}

this.globalVars = globalVars;
this.authCredentials = SkytapUtils.getAuthCredentials(build);

// reset step parameters with env vars resolved at runtime
String expConfigurationFile = SkytapUtils.expandEnvVars(build,
configurationFile);

// if user has provided just a filename with no path, default to
// place it in their Jenkins workspace

if (!expConfigurationFile.equals("")) {
expConfigurationFile = SkytapUtils.convertFileNameToFullPath(build,
expConfigurationFile);
}

// get runtime config id
try {
this.runtimeConfigurationID = SkytapUtils.getRuntimeId(configurationID, expConfigurationFile);
this.runtimeConfigurationID = SkytapUtils.getRuntimeId(
configurationID, expConfigurationFile);
} catch (FileNotFoundException e) {
JenkinsLogger.error("Error retrieving configuration id: " + e.getMessage());
JenkinsLogger.error("Error retrieving configuration id: "
+ e.getMessage());
return false;
}


// retrieve ids of any tunnels (connected networks) prior to deletion
JenkinsLogger
.log("Checking for any connected networks for configuration id: "
+ runtimeConfigurationID);

ArrayList tunnelIdList = new ArrayList();

try {
tunnelIdList = getTunnelList(runtimeConfigurationID);
} catch (SkytapException e1) {
JenkinsLogger.error(e1.getMessage());
return false;
}

JenkinsLogger.log("Disconnecting connected networks ...");

for (int i = 0; i < tunnelIdList.size(); i++) {

String tunnelId = tunnelIdList.get(i).toString();
try {
disconnectTunnel(tunnelId);
} catch (SkytapException e) {
JenkinsLogger.error(e.getMessage());
return false;
}

}

JenkinsLogger.log("Sending delete request for configuration id "
+ this.runtimeConfigurationID);

// build delete config url
String requestURL = buildRequestURL(this.runtimeConfigurationID);

// create request for Skytap API
HttpDelete hd = SkytapUtils.buildHttpDeleteRequest(requestURL,
this.authCredentials);
Expand All @@ -122,53 +279,60 @@ public Boolean executeStep(AbstractBuild build, SkytapGlobalVariables globalVars
JenkinsLogger.error("Request returned an error: " + ex.getError());
JenkinsLogger.error("Failing build step.");
return false;
} catch (IllegalStateException ex){
// if there are no errors in the response body this exception will result
} catch (IllegalStateException ex) {
// if there are no errors in the response body this exception will
// result
}

JenkinsLogger.log("");
JenkinsLogger.log(httpRespBody);
JenkinsLogger.log("");

JenkinsLogger.defaultLogMessage("Configuration " + runtimeConfigurationID + " was successfully deleted.");
JenkinsLogger.defaultLogMessage("----------------------------------------");

JenkinsLogger.defaultLogMessage("Configuration "
+ runtimeConfigurationID + " was successfully deleted.");
JenkinsLogger
.defaultLogMessage("----------------------------------------");
return true;

}
public String buildRequestURL(String configId) {

private String buildRequestURL(String configId) {

StringBuilder sb = new StringBuilder("https://cloud.skytap.com/");
sb.append("configurations/");
sb.append(configId);

//https://cloud.skytap.com/configurations/1154948
// https://cloud.skytap.com/configurations/1154948

return sb.toString();
}

/**
* This method is a final check to ensure that user inputs are legitimate.
* Any situation where the user has entered both inputs in an either/or scenario
* will fail the build. If the user has left both blank where we need one, it will
* also fail.
* Any situation where the user has entered both inputs in an either/or
* scenario will fail the build. If the user has left both blank where we
* need one, it will also fail.
*
* @return Boolean sanityCheckPassed
*/
private Boolean preFlightSanityChecks(){
private Boolean preFlightSanityChecks() {

// check whether user entered both values for conf id/conf file
if(!this.configurationID.equals("") && !this.configurationFile.equals("")){
JenkinsLogger.error("Values were provided for both configuration ID and file. Please provide just one or the other.");
if (!this.configurationID.equals("")
&& !this.configurationFile.equals("")) {
JenkinsLogger
.error("Values were provided for both configuration ID and file. Please provide just one or the other.");
return false;
}

// check whether we have neither conf id or file
if(this.configurationFile.equals("") && this.configurationID.equals("")){
JenkinsLogger.error("No value was provided for configuration ID or file. Please provide either a valid Skytap configuration ID, or a valid configuration file.");
if (this.configurationFile.equals("")
&& this.configurationID.equals("")) {
JenkinsLogger
.error("No value was provided for configuration ID or file. Please provide either a valid Skytap configuration ID, or a valid configuration file.");
return false;
}

return true;
}

Expand All @@ -179,7 +343,7 @@ public String getConfigurationID() {
public String getConfigurationFile() {
return configurationFile;
}

@Extension
public static final SkytapActionDescriptor D = new SkytapActionDescriptor(
DeleteConfigurationStep.class, "Delete Configuration");
Expand Down

0 comments on commit 853e229

Please sign in to comment.