diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e90878c --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.classpath +*.project +*.iml +*.settings +.idea/ +work/ +target/ diff --git a/deployment-manager/pom.xml b/deployment-manager/pom.xml index 43c7d37..1b2db8b 100644 --- a/deployment-manager/pom.xml +++ b/deployment-manager/pom.xml @@ -32,16 +32,26 @@ Alexey Khivin akhivin@gmail.com + + Nikolay Mahotkin + nmakhotkin@mirantis.com + 8 2.23 UTF-8 - 3.0.2 + 3.0.3-SNAPSHOT + 3.0.2 + + st-snapshots + sonatype-snapshots + https://oss.sonatype.org/content/repositories/snapshots + repo.jenkins-ci.org Jenkins Repository @@ -103,7 +113,7 @@ org.pacesys.openstack4j.connectors openstack4j-httpclient - ${openstack4jversion} + ${openstack4jConnectorVersion} diff --git a/deployment-manager/src/main/java/org/openstack/murano/jenkins_plugins/muranoci/deploy/MuranoHelper.java b/deployment-manager/src/main/java/org/openstack/murano/jenkins_plugins/muranoci/deploy/MuranoHelper.java index ed8ca58..a0472fb 100644 --- a/deployment-manager/src/main/java/org/openstack/murano/jenkins_plugins/muranoci/deploy/MuranoHelper.java +++ b/deployment-manager/src/main/java/org/openstack/murano/jenkins_plugins/muranoci/deploy/MuranoHelper.java @@ -1,32 +1,21 @@ 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.openstack4j.api.Builders; import org.openstack4j.api.OSClient; import org.openstack4j.api.exceptions.AuthenticationException; -import org.openstack4j.connectors.httpclient.HttpCommand; -import org.openstack4j.core.transport.HttpMethod; -import org.openstack4j.core.transport.HttpRequest; +import org.openstack4j.model.murano.v1.domain.AppCatalogSession; +import org.openstack4j.model.murano.v1.domain.Deployment; +import org.openstack4j.model.murano.v1.domain.Environment; import org.openstack4j.openstack.OSFactory; -import java.io.BufferedReader; -import java.io.InputStreamReader; import java.time.Instant; +import java.util.Date; +import java.util.List; import java.util.concurrent.TimeoutException; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; 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; /** @@ -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 @@ -76,29 +69,28 @@ public class MuranoHelper { * @return new environment id * @throws AuthenticationException in case credentials */ - public String deployNewFromObjectModel(String name, String objectModel) + Environment deployNewFromObjectModel(String name, String objectModel) throws AuthenticationException { - this.authenticate(); - String token = getOSClient().getAccess().getToken().getId(); + Environment env = checkIfDeploymentExists(name); - String envId = checkIfDeploymentExists(token, name); - if (envId == null) { + if (env == null) { // Create Env - envId = this.createEnvironment(token, name); - - // Create Session - String sessionId = this.createEnvironmentSession(token, envId); - - // Add App to Environment - addApplicationToEnvironment(token, envId, sessionId, objectModel); - - // Deploy - deployEnvironment(token, envId, sessionId); + env = getOSClient().murano().environments().create( + Builders.environment().name(name).build() + ); } + // Create Session + AppCatalogSession session = getOSClient().murano().sessions().configure(env.getId()); - return envId; + // Add App to Environment + getOSClient().murano().services().create(env.getId(), session.getId(), objectModel); + + // Deploy + getOSClient().murano().sessions().deploy(env.getId(), session.getId()); + + 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 * 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 * @throws TimeoutException if deployment process still in progress after deadline */ - public boolean waitDeploymentResult(String envId) throws TimeoutException { - String token = getOSClient().getAccess().getToken().getId(); - + boolean waitDeploymentResult(Environment env) throws TimeoutException { boolean status = false; + boolean isTimedOut = false; Instant deadline = Instant.now().plusMillis(timeout); - while(true) { - try { - Thread.sleep(10000); - 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; - } + Deployment deployment; + + while(!isTimedOut) { 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 the Environment id if it exists + * Return the Environment if it exists else null * - * @param token - * @param name - * @return + * @param name Environment name + * @return Environment instance or null */ - private String checkIfDeploymentExists(String token, String name) { - // TODO: remove string manipulation - 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 checkIfDeploymentExists(String name) { + return getEnvByName(name); } - /** - * Deploy the environment given the environment id and Session Token - */ - private void deployEnvironment(String token, String envId, String sessionId) { - String response = getResponseForJson( - getMuranoEnpoint(), - MURANO_DEFAULT_PORT, - "/v1/environments/" + envId + "/sessions/" + sessionId + "/deploy", - HttpMethod.POST, - token, - null, - null); + private Environment getEnvByName(String name) { + List envs = getOSClient().murano().environments().list(); + + return envs.stream().filter(e -> e.getName().equals(name)).findFirst().orElse(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 * @@ -347,13 +164,23 @@ public class MuranoHelper { .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 * @return OSClient V2 */ - public OSClient.OSClientV2 getOSClient() { - return this.os; + private OSClient.OSClientV2 getOSClient() { + if (this.os == null || isTokenExpiring()) { + authenticate(); + } + + return this.os; } public void setTimeout(int timeout) { diff --git a/deployment-manager/src/main/java/org/openstack/murano/jenkins_plugins/muranoci/deploy/MuranoManagerBuildWrapper.java b/deployment-manager/src/main/java/org/openstack/murano/jenkins_plugins/muranoci/deploy/MuranoManagerBuildWrapper.java index 18c7625..f4bc69b 100644 --- a/deployment-manager/src/main/java/org/openstack/murano/jenkins_plugins/muranoci/deploy/MuranoManagerBuildWrapper.java +++ b/deployment-manager/src/main/java/org/openstack/murano/jenkins_plugins/muranoci/deploy/MuranoManagerBuildWrapper.java @@ -81,11 +81,9 @@ public class MuranoManagerBuildWrapper extends BuildWrapper implements Serializa String name = generateEnvName(); - String envId = helper.deployNewFromObjectModel( - name, deployment.getObjectModel()); + boolean result = helper.deployEnvAndWait(name, deployment.getObjectModel()); - boolean result = helper.waitDeploymentResult(envId); - if (!result){ + if (!result) { build.setResult(Result.FAILURE); } } catch (Exception e) { @@ -99,8 +97,8 @@ public class MuranoManagerBuildWrapper extends BuildWrapper implements Serializa private String generateEnvName() { return MURANO_ENV_NAME + new BigInteger( 32, - new SecureRandom()) - .toString(16); + new SecureRandom() + ).toString(16); } private OpenstackCredentials getOpenstackCredentials(String credentialsId) { diff --git a/deployment-manager/src/main/java/org/openstack/murano/jenkins_plugins/muranoci/deploy/credentials/OpenstackCredentialsImpl.java b/deployment-manager/src/main/java/org/openstack/murano/jenkins_plugins/muranoci/deploy/credentials/OpenstackCredentialsImpl.java index ab6150a..ace5b80 100644 --- a/deployment-manager/src/main/java/org/openstack/murano/jenkins_plugins/muranoci/deploy/credentials/OpenstackCredentialsImpl.java +++ b/deployment-manager/src/main/java/org/openstack/murano/jenkins_plugins/muranoci/deploy/credentials/OpenstackCredentialsImpl.java @@ -79,14 +79,14 @@ public class OpenstackCredentialsImpl extends BaseStandardCredentials implements @QueryParameter("password") final String password) throws IOException, ServletException { - MuranoHelper client = new MuranoHelper( + MuranoHelper helper = new MuranoHelper( identityServiceEndpoint, username, password, tenant); try { - client.authenticate(); + helper.authenticate(); } catch (AuthenticationException ae) { return FormValidation.error( "Unable to connect to server. Please check credentials");