[DM] Changing the deployment implementation to openstack4j
* Use openstack4j library instead of raw HTTP requests * Added latest openstack4j-3.0.3-SNAPSHOT to dependencies * Added re-authentication of openstack4j client * Minor code refactoring Change-Id: I94d7e7d724a117ccfe63fc4aeaf73f1b0ef27870
This commit is contained in:
parent
a40f7fb476
commit
05ae1e9b2f
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
*.classpath
|
||||||
|
*.project
|
||||||
|
*.iml
|
||||||
|
*.settings
|
||||||
|
.idea/
|
||||||
|
work/
|
||||||
|
target/
|
@ -32,16 +32,26 @@
|
|||||||
<name>Alexey Khivin</name>
|
<name>Alexey Khivin</name>
|
||||||
<email>akhivin@gmail.com</email>
|
<email>akhivin@gmail.com</email>
|
||||||
</developer>
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<name>Nikolay Mahotkin</name>
|
||||||
|
<email>nmakhotkin@mirantis.com</email>
|
||||||
|
</developer>
|
||||||
</developers>
|
</developers>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.level>8</java.level>
|
<java.level>8</java.level>
|
||||||
<jenkins.version>2.23</jenkins.version>
|
<jenkins.version>2.23</jenkins.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<openstack4jversion>3.0.2</openstack4jversion>
|
<openstack4jversion>3.0.3-SNAPSHOT</openstack4jversion>
|
||||||
|
<openstack4jConnectorVersion>3.0.2</openstack4jConnectorVersion>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>st-snapshots</id>
|
||||||
|
<name>sonatype-snapshots</name>
|
||||||
|
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
</repository>
|
||||||
<repository>
|
<repository>
|
||||||
<id>repo.jenkins-ci.org</id>
|
<id>repo.jenkins-ci.org</id>
|
||||||
<name>Jenkins Repository</name>
|
<name>Jenkins Repository</name>
|
||||||
@ -103,7 +113,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.pacesys.openstack4j.connectors</groupId>
|
<groupId>org.pacesys.openstack4j.connectors</groupId>
|
||||||
<artifactId>openstack4j-httpclient</artifactId>
|
<artifactId>openstack4j-httpclient</artifactId>
|
||||||
<version>${openstack4jversion}</version>
|
<version>${openstack4jConnectorVersion}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -1,32 +1,21 @@
|
|||||||
package org.openstack.murano.jenkins_plugins.muranoci.deploy;
|
package org.openstack.murano.jenkins_plugins.muranoci.deploy;
|
||||||
|
|
||||||
|
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
|
||||||
import org.json.simple.JSONArray;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
import org.json.simple.parser.JSONParser;
|
|
||||||
import org.json.simple.parser.ParseException;
|
|
||||||
import org.kohsuke.stapler.DataBoundConstructor;
|
import org.kohsuke.stapler.DataBoundConstructor;
|
||||||
|
import org.openstack4j.api.Builders;
|
||||||
import org.openstack4j.api.OSClient;
|
import org.openstack4j.api.OSClient;
|
||||||
import org.openstack4j.api.exceptions.AuthenticationException;
|
import org.openstack4j.api.exceptions.AuthenticationException;
|
||||||
import org.openstack4j.connectors.httpclient.HttpCommand;
|
import org.openstack4j.model.murano.v1.domain.AppCatalogSession;
|
||||||
import org.openstack4j.core.transport.HttpMethod;
|
import org.openstack4j.model.murano.v1.domain.Deployment;
|
||||||
import org.openstack4j.core.transport.HttpRequest;
|
import org.openstack4j.model.murano.v1.domain.Environment;
|
||||||
import org.openstack4j.openstack.OSFactory;
|
import org.openstack4j.openstack.OSFactory;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.LogRecord;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
public class MuranoHelper {
|
public class MuranoHelper {
|
||||||
public static final int MURANO_DEFAULT_PORT = 8082;
|
|
||||||
|
|
||||||
private final static Logger LOG = Logger.getLogger(MuranoHelper.class.getName());
|
|
||||||
|
|
||||||
private OSClient.OSClientV2 os = null;
|
private OSClient.OSClientV2 os = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,6 +58,10 @@ public class MuranoHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean deployEnvAndWait(String envName, String objectModel) throws TimeoutException {
|
||||||
|
Environment env = deployNewFromObjectModel(envName, objectModel);
|
||||||
|
return waitDeploymentResult(env);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param name New environment name
|
* @param name New environment name
|
||||||
@ -76,29 +69,28 @@ public class MuranoHelper {
|
|||||||
* @return new environment id
|
* @return new environment id
|
||||||
* @throws AuthenticationException in case credentials
|
* @throws AuthenticationException in case credentials
|
||||||
*/
|
*/
|
||||||
public String deployNewFromObjectModel(String name, String objectModel)
|
Environment deployNewFromObjectModel(String name, String objectModel)
|
||||||
throws AuthenticationException {
|
throws AuthenticationException {
|
||||||
|
|
||||||
this.authenticate();
|
this.authenticate();
|
||||||
|
|
||||||
String token = getOSClient().getAccess().getToken().getId();
|
Environment env = checkIfDeploymentExists(name);
|
||||||
|
|
||||||
String envId = checkIfDeploymentExists(token, name);
|
if (env == null) {
|
||||||
if (envId == null) {
|
|
||||||
// Create Env
|
// Create Env
|
||||||
envId = this.createEnvironment(token, name);
|
env = getOSClient().murano().environments().create(
|
||||||
|
Builders.environment().name(name).build()
|
||||||
|
);
|
||||||
|
}
|
||||||
// Create Session
|
// Create Session
|
||||||
String sessionId = this.createEnvironmentSession(token, envId);
|
AppCatalogSession session = getOSClient().murano().sessions().configure(env.getId());
|
||||||
|
|
||||||
// Add App to Environment
|
// Add App to Environment
|
||||||
addApplicationToEnvironment(token, envId, sessionId, objectModel);
|
getOSClient().murano().services().create(env.getId(), session.getId(), objectModel);
|
||||||
|
|
||||||
// Deploy
|
// Deploy
|
||||||
deployEnvironment(token, envId, sessionId);
|
getOSClient().murano().sessions().deploy(env.getId(), session.getId());
|
||||||
}
|
|
||||||
|
|
||||||
return envId;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -106,234 +98,59 @@ public class MuranoHelper {
|
|||||||
* Loop around to see if the deployment is a success. This waits for about 10 secs 300 times hoping that
|
* Loop around to see if the deployment is a success. This waits for about 10 secs 300 times hoping that
|
||||||
* it finishes. This all depends on teh number of nodes and the speed of the boxes. But seems sufficient.
|
* it finishes. This all depends on teh number of nodes and the speed of the boxes. But seems sufficient.
|
||||||
*
|
*
|
||||||
* @param envId Environemnt Id
|
* @param env Environemnt instance
|
||||||
* @return whether the deployment is a success
|
* @return whether the deployment is a success
|
||||||
* @throws TimeoutException if deployment process still in progress after deadline
|
* @throws TimeoutException if deployment process still in progress after deadline
|
||||||
*/
|
*/
|
||||||
public boolean waitDeploymentResult(String envId) throws TimeoutException {
|
boolean waitDeploymentResult(Environment env) throws TimeoutException {
|
||||||
String token = getOSClient().getAccess().getToken().getId();
|
|
||||||
|
|
||||||
boolean status = false;
|
boolean status = false;
|
||||||
|
boolean isTimedOut = false;
|
||||||
Instant deadline = Instant.now().plusMillis(timeout);
|
Instant deadline = Instant.now().plusMillis(timeout);
|
||||||
|
|
||||||
while(true) {
|
Deployment deployment;
|
||||||
try {
|
|
||||||
Thread.sleep(10000);
|
while(!isTimedOut) {
|
||||||
String payload = getResponseForJson(
|
|
||||||
getMuranoEnpoint(),
|
|
||||||
MURANO_DEFAULT_PORT,
|
|
||||||
"/v1/environments/" + envId + "/deployments",
|
|
||||||
HttpMethod.GET,
|
|
||||||
token,
|
|
||||||
null,
|
|
||||||
null);
|
|
||||||
JSONParser parser = new JSONParser();
|
|
||||||
try {
|
|
||||||
JSONObject deployments = (JSONObject) parser.parse(payload);
|
|
||||||
JSONArray deploymentList = (JSONArray) deployments.get("deployments");
|
|
||||||
JSONObject thisDeployment = (JSONObject) deploymentList.get(0);
|
|
||||||
if ("success".equals(thisDeployment.get("state"))) {
|
|
||||||
status = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (ParseException pe) {
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
status = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (Instant.now().isAfter(deadline)){
|
if (Instant.now().isAfter(deadline)){
|
||||||
throw new TimeoutException("Environment was not ready in time.");
|
isTimedOut = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deployment = getOSClient().murano().deployments().list(env.getId()).get(0);
|
||||||
|
String state = deployment.getState();
|
||||||
|
|
||||||
|
if (!state.equals("running")) {
|
||||||
|
status = state.equals("success");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(10000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTimedOut) {
|
||||||
|
throw new TimeoutException("Timed out. Environment is not ready in time.");
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the Environment id if it exists
|
* Return the Environment if it exists else null
|
||||||
*
|
*
|
||||||
* @param token
|
* @param name Environment name
|
||||||
* @param name
|
* @return Environment instance or null
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
private String checkIfDeploymentExists(String token, String name) {
|
private Environment checkIfDeploymentExists(String name) {
|
||||||
// TODO: remove string manipulation
|
return getEnvByName(name);
|
||||||
String payload = getResponseForJson(
|
|
||||||
getMuranoEnpoint(),
|
|
||||||
MURANO_DEFAULT_PORT,
|
|
||||||
"/v1/environments",
|
|
||||||
HttpMethod.GET,
|
|
||||||
token,
|
|
||||||
null,
|
|
||||||
null);
|
|
||||||
String envId = null;
|
|
||||||
JSONParser parser = new JSONParser();
|
|
||||||
try{
|
|
||||||
Object obj = parser.parse(payload);
|
|
||||||
JSONObject response = (JSONObject)obj;
|
|
||||||
JSONArray environmentArray = (JSONArray) response.get("environments");
|
|
||||||
for (Object env: environmentArray) {
|
|
||||||
JSONObject thisEnv = (JSONObject) env;
|
|
||||||
String envName = (String) thisEnv.get("name");
|
|
||||||
if (envName.equals(name)) {
|
|
||||||
envId = (String) thisEnv.get("id");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}catch(ParseException pe){
|
|
||||||
LogRecord logRecord = new LogRecord(Level.WARNING, "Parse exception: position: " + pe.getPosition());
|
|
||||||
logRecord.setThrown(pe);
|
|
||||||
LOG.log(logRecord);
|
|
||||||
}
|
|
||||||
return envId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private Environment getEnvByName(String name) {
|
||||||
* Deploy the environment given the environment id and Session Token
|
List<? extends Environment> envs = getOSClient().murano().environments().list();
|
||||||
*/
|
|
||||||
private void deployEnvironment(String token, String envId, String sessionId) {
|
return envs.stream().filter(e -> e.getName().equals(name)).findFirst().orElse(null);
|
||||||
String response = getResponseForJson(
|
|
||||||
getMuranoEnpoint(),
|
|
||||||
MURANO_DEFAULT_PORT,
|
|
||||||
"/v1/environments/" + envId + "/sessions/" + sessionId + "/deploy",
|
|
||||||
HttpMethod.POST,
|
|
||||||
token,
|
|
||||||
null,
|
|
||||||
null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getMuranoEnpoint() {
|
|
||||||
/*
|
|
||||||
* TODO: This is temporary decision. Murano URL should be obtained from Keystone
|
|
||||||
*/
|
|
||||||
String string[] = this.serverUrl.split(":");
|
|
||||||
|
|
||||||
return string[0] + ":" + string[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the app(K8S) to the environment
|
|
||||||
* @param token
|
|
||||||
* @param envId
|
|
||||||
* @param sessionId
|
|
||||||
* @param jsonReq
|
|
||||||
*/
|
|
||||||
private void addApplicationToEnvironment(String token, String envId, String sessionId, String jsonReq) {
|
|
||||||
String response = getResponseForJson(this.getMuranoEnpoint(),
|
|
||||||
MURANO_DEFAULT_PORT,
|
|
||||||
"/v1/environments/" + envId + "/services",
|
|
||||||
HttpMethod.POST,
|
|
||||||
token,
|
|
||||||
jsonReq,
|
|
||||||
sessionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String createEnvironmentSession(String token, String envId) {
|
|
||||||
String payload = getResponseForJson(this.getMuranoEnpoint(),
|
|
||||||
MURANO_DEFAULT_PORT,
|
|
||||||
"/v1/environments/" + envId + "/configure",
|
|
||||||
HttpMethod.POST,
|
|
||||||
token,
|
|
||||||
null,
|
|
||||||
null);
|
|
||||||
|
|
||||||
String sessionId = "";
|
|
||||||
JSONParser parser = new JSONParser();
|
|
||||||
try{
|
|
||||||
Object obj = parser.parse(payload);
|
|
||||||
JSONObject response = (JSONObject)obj;
|
|
||||||
sessionId = (String)response.get("id");
|
|
||||||
}catch(ParseException pe){
|
|
||||||
System.out.println("position: " + pe.getPosition());
|
|
||||||
System.out.println(pe);
|
|
||||||
}
|
|
||||||
return sessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String createEnvironment(String token, String envname) {
|
|
||||||
String reqPayload = "{\"name\":\"" + envname + "\"}";
|
|
||||||
String payload = getResponseForJson(
|
|
||||||
getMuranoEnpoint(),
|
|
||||||
MURANO_DEFAULT_PORT,
|
|
||||||
"/v1/environments",
|
|
||||||
HttpMethod.POST, token, reqPayload, null);
|
|
||||||
|
|
||||||
String envId = "";
|
|
||||||
JSONParser parser = new JSONParser();
|
|
||||||
try{
|
|
||||||
Object obj = parser.parse(payload);
|
|
||||||
JSONObject response = (JSONObject)obj;
|
|
||||||
envId = (String)response.get("id");
|
|
||||||
}catch(ParseException pe){
|
|
||||||
System.out.println("position: " + pe.getPosition());
|
|
||||||
System.out.println(pe);
|
|
||||||
}
|
|
||||||
|
|
||||||
return envId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main helper method to call the Murano API and return the response. Accepts both GET and POST.
|
|
||||||
*
|
|
||||||
* @param url Base URL to connect
|
|
||||||
* @param port Which port is murano listening on
|
|
||||||
* @param requestPath Path on Murano URL
|
|
||||||
* @param method GET or POST
|
|
||||||
* @param token Auth Token
|
|
||||||
* @param jsonPayload Payload for the message
|
|
||||||
* @param muranoSessionId Optional Session Id
|
|
||||||
* @return Response from the Call
|
|
||||||
*/
|
|
||||||
private String getResponseForJson(String url,
|
|
||||||
int port,
|
|
||||||
String requestPath,
|
|
||||||
HttpMethod method,
|
|
||||||
String token,
|
|
||||||
String jsonPayload,
|
|
||||||
String muranoSessionId) {
|
|
||||||
HttpRequest request = HttpRequest.builder().method(method)
|
|
||||||
.endpoint(url + ":" + port)
|
|
||||||
.path(requestPath)
|
|
||||||
.header("X-Auth-Token", token)
|
|
||||||
.json(jsonPayload)
|
|
||||||
.build();
|
|
||||||
if (muranoSessionId != null) {
|
|
||||||
request.getHeaders().put("X-Configuration-Session", muranoSessionId);
|
|
||||||
}
|
|
||||||
if (jsonPayload != null) {
|
|
||||||
request = request.toBuilder().json(jsonPayload).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpCommand command = HttpCommand.create(request);
|
|
||||||
CloseableHttpResponse response = null;
|
|
||||||
try {
|
|
||||||
response = command.execute();
|
|
||||||
} catch(Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuffer jsonString = new StringBuffer();
|
|
||||||
try {
|
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(
|
|
||||||
response.getEntity().getContent()));
|
|
||||||
|
|
||||||
//Print the raw output of murano api from the server
|
|
||||||
String output;
|
|
||||||
|
|
||||||
while ((output = br.readLine()) != null) {
|
|
||||||
jsonString.append(output + "\n");
|
|
||||||
}
|
|
||||||
} catch(Exception ex) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsonString.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticate to the Openstack instance given the credentials in constructor
|
* Authenticate to the Openstack instance given the credentials in constructor
|
||||||
*
|
*
|
||||||
@ -347,12 +164,22 @@ public class MuranoHelper {
|
|||||||
.authenticate();
|
.authenticate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isTokenExpiring() {
|
||||||
|
long oneMinute = 60000;
|
||||||
|
Date muniteInFuture = new Date(Date.from(Instant.now()).getTime() + oneMinute);
|
||||||
|
|
||||||
|
return os.getAccess().getToken().getExpires().before(muniteInFuture);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper object to return the OSClient
|
* Helper object to return the OSClient
|
||||||
* @return OSClient V2
|
* @return OSClient V2
|
||||||
*/
|
*/
|
||||||
public OSClient.OSClientV2 getOSClient() {
|
private OSClient.OSClientV2 getOSClient() {
|
||||||
|
if (this.os == null || isTokenExpiring()) {
|
||||||
|
authenticate();
|
||||||
|
}
|
||||||
|
|
||||||
return this.os;
|
return this.os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,10 +81,8 @@ public class MuranoManagerBuildWrapper extends BuildWrapper implements Serializa
|
|||||||
|
|
||||||
String name = generateEnvName();
|
String name = generateEnvName();
|
||||||
|
|
||||||
String envId = helper.deployNewFromObjectModel(
|
boolean result = helper.deployEnvAndWait(name, deployment.getObjectModel());
|
||||||
name, deployment.getObjectModel());
|
|
||||||
|
|
||||||
boolean result = helper.waitDeploymentResult(envId);
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
build.setResult(Result.FAILURE);
|
build.setResult(Result.FAILURE);
|
||||||
}
|
}
|
||||||
@ -99,8 +97,8 @@ public class MuranoManagerBuildWrapper extends BuildWrapper implements Serializa
|
|||||||
private String generateEnvName() {
|
private String generateEnvName() {
|
||||||
return MURANO_ENV_NAME + new BigInteger(
|
return MURANO_ENV_NAME + new BigInteger(
|
||||||
32,
|
32,
|
||||||
new SecureRandom())
|
new SecureRandom()
|
||||||
.toString(16);
|
).toString(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
private OpenstackCredentials getOpenstackCredentials(String credentialsId) {
|
private OpenstackCredentials getOpenstackCredentials(String credentialsId) {
|
||||||
|
@ -79,14 +79,14 @@ public class OpenstackCredentialsImpl extends BaseStandardCredentials implements
|
|||||||
@QueryParameter("password") final String password)
|
@QueryParameter("password") final String password)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
|
|
||||||
MuranoHelper client = new MuranoHelper(
|
MuranoHelper helper = new MuranoHelper(
|
||||||
identityServiceEndpoint,
|
identityServiceEndpoint,
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
tenant);
|
tenant);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
client.authenticate();
|
helper.authenticate();
|
||||||
} catch (AuthenticationException ae) {
|
} catch (AuthenticationException ae) {
|
||||||
return FormValidation.error(
|
return FormValidation.error(
|
||||||
"Unable to connect to server. Please check credentials");
|
"Unable to connect to server. Please check credentials");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user