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

WIP: Add input extension point implement #91

Closed
Closed
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
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# ChangeLog

## 0.2.35 (not released yet)
## 0.2.36 (not released yet)

* Using input extension point implement to record input request list

## 0.2.35

* Bump kubernetes-client version to 0.2.9.
Set the default value of resourceVersion to 0
Expand Down
23 changes: 20 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@
<version>2.18</version>
</dependency>

<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>access-modifier-annotation</artifactId>
<version>1.15</version>
</dependency>

<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>git</artifactId>
Expand Down Expand Up @@ -246,7 +252,13 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>pipeline-input-step</artifactId>
<version>2.8</version>
<version>2.11-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-support</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
Expand All @@ -272,12 +284,17 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>structs</artifactId>
<version>1.14</version>
<version>1.17</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
<version>2.14</version>
<version>2.18</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-api</artifactId>
<version>2.33</version>
</dependency>
<dependency>
<groupId>org.jenkinsci.plugins</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ private Constants(){}

public static final String ALAUDA_DEVOPS_ANNOTATIONS_JENKINS_IDENTITY = "alauda.io/jenkins-instance-identity";

public static final String ALAUDA_DEVOPS_ANNOTATIONS_JENKINS_INPUT_REQUESTS = "alauda.io/jenkins-input-requests";

/** secret keys */
public static final String ALAUDA_DEVOPS_SECRETS_DATA_USERNAME = "username";
public static final String ALAUDA_DEVOPS_SECRETS_DATA_PASSWORD = "password";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package io.alauda.jenkins.devops.sync.input;

import hudson.Extension;
import hudson.model.Job;
import hudson.model.Run;
import io.alauda.devops.client.AlaudaDevOpsClient;
import io.alauda.jenkins.devops.sync.JenkinsPipelineCause;
import io.alauda.jenkins.devops.sync.model.InputRequest;
import io.alauda.jenkins.devops.sync.model.ParamValueParser;
import io.alauda.jenkins.devops.sync.util.AlaudaUtils;
import io.alauda.kubernetes.api.model.Pipeline;
import jenkins.model.Jenkins;
import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.jenkinsci.plugins.workflow.support.steps.input.InputExtension;
import org.jenkinsci.plugins.workflow.support.steps.input.InputStep;

import java.util.Iterator;
import java.util.Map;
import java.util.logging.Logger;

import static io.alauda.jenkins.devops.sync.constants.Constants.ALAUDA_DEVOPS_ANNOTATIONS_JENKINS_INPUT_REQUESTS;

@Extension
public class AlaudaInputExtension implements InputExtension {
private static final Logger LOGGER = Logger.getLogger(AlaudaInputExtension.class.getName());

@Override
public void notifyInput(InputStep input, Run run, String userID, NotifyEvent event) {
switch (event) {
case START:
addInputRequest(input, run);
break;
case ABORT:
case PROCEED:
updateInputRequest(input, run, userID, event);
break;
}
}

private void addInputRequest(InputStep input, Run run) {
final String message = input.getMessage();
LOGGER.info(String.format("Receive a input request, message is: %s", message));

Pipeline targetPipeline = findPipeline(run);
if(targetPipeline == null) {
// TODO need to consider how to deal with the bad situation with k8s client
return;
}

String namespace = targetPipeline.getMetadata().getNamespace();
String name = targetPipeline.getMetadata().getName();

JSONArray jsonArray = getAndAddRequestJson(targetPipeline, input, run);
updatePipeline(namespace, name, jsonArray.toString());
}

private void updateInputRequest(InputStep input, Run run, String userID, NotifyEvent event) {
Pipeline targetPipeline = findPipeline(run);
if(targetPipeline == null) {
// TODO need to consider how to deal with the bad situation with k8s client
return;
}

String namespace = targetPipeline.getMetadata().getNamespace();
String name = targetPipeline.getMetadata().getName();

JSONArray jsonArray = getRequestJson(targetPipeline);
if(jsonArray == null) {
LOGGER.info(String.format("Cannot update input request: %s", input.getMessage()));
return;
}

boolean found = false;
for(Object request : jsonArray) {
if(!(request instanceof JSONObject)) {
continue;
}

JSONObject jsonObj = (JSONObject) request;

if(input.getId().equals(jsonObj.getString("id"))) {
jsonObj.put("status", event.name());
found = true;
break;
}
}

if(found) {
updatePipeline(namespace, name, jsonArray.toString());
} else {
LOGGER.warning(String.format("Cannot find input request by id: %s", input.getId()));
}
}

private void updatePipeline(String namespace, String name, String requestJson) {
// add annotations to pipeline resource
AlaudaDevOpsClient client = AlaudaUtils.getAuthenticatedAlaudaClient();
client.pipelines().inNamespace(namespace).withName(name).edit()
.editMetadata().addToAnnotations(ALAUDA_DEVOPS_ANNOTATIONS_JENKINS_INPUT_REQUESTS, requestJson)
.endMetadata().done();
}

private Pipeline findPipeline(Run run) {
Job job = run.getParent();
if(job instanceof WorkflowJob && run instanceof WorkflowRun) {
WorkflowJob wfJob = (WorkflowJob) job;
WorkflowRun wfRun = (WorkflowRun) run;

JenkinsPipelineCause cause = wfRun.getCause(JenkinsPipelineCause.class);
if(cause == null) {
LOGGER.info("Current pipeline was not create by Alauda platform, because no JenkinsPipelineCause found.");
return null;
}

String namespace = cause.getNamespace();
String name = cause.getName();

// add annotations to pipeline resource
AlaudaDevOpsClient client = AlaudaUtils.getAuthenticatedAlaudaClient();
if(client == null) {
LOGGER.warning(String.format("Cannot get alauda client when process input request in workflow: %s, build id: %s.",
wfJob.getFullName(), wfRun.getId()));
return null;
}

return client.pipelines().inNamespace(namespace).withName(name).get();
}

return null;
}

private JSONArray getRequestJson(Pipeline targetPipeline) {
String inputRequestJsonText = null;
Map<String, String> annotations = targetPipeline.getMetadata().getAnnotations();
if(annotations != null && annotations.containsKey(ALAUDA_DEVOPS_ANNOTATIONS_JENKINS_INPUT_REQUESTS)) {
inputRequestJsonText = annotations.get(ALAUDA_DEVOPS_ANNOTATIONS_JENKINS_INPUT_REQUESTS);
}

JSONArray jsonArray = new JSONArray();
try {
if(inputRequestJsonText != null) {
jsonArray = JSONArray.fromObject(inputRequestJsonText);
}
} catch (JSONException e) {
LOGGER.warning(String.format("Cannot parse json array text: %s", inputRequestJsonText));
}

return jsonArray;
}

private JSONArray getAndAddRequestJson(Pipeline targetPipeline, InputStep input, Run run) {
JSONArray jsonArray = getRequestJson(targetPipeline);
String buildID = run.getId();
String baseURI = run.getUrl();

Iterator<ParamValueParser> paramValueParserIt = Jenkins.getInstance()
.getExtensionList(ParamValueParser.class).iterator();

InputRequest inputRequest = InputStepConvert.convert(input, paramValueParserIt);
inputRequest.setBuildID(buildID);
inputRequest.setBaseURI(baseURI);
jsonArray.add(inputRequest);

return jsonArray;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package io.alauda.jenkins.devops.sync.input;

import hudson.model.ParameterDefinition;
import io.alauda.jenkins.devops.sync.model.InputRequest;
import io.alauda.jenkins.devops.sync.model.InputRequestParam;
import io.alauda.jenkins.devops.sync.model.ParamValueParser;
import org.jenkinsci.plugins.workflow.support.steps.input.InputStep;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

public final class InputStepConvert {
private static final Logger LOGGER = Logger.getLogger(InputStepConvert.class.getName());

private InputStepConvert(){}

public static InputRequest convert(InputStep input, Iterator<ParamValueParser> parserIt) {
InputRequest inputRequest = new InputRequest();
inputRequest.setId(input.getId());
inputRequest.setMessage(input.getMessage());
inputRequest.setSubmitter(input.getSubmitter());

List<ParameterDefinition> params = input.getParameters();
if(params != null) {
final List<InputRequestParam> inputRequestParams = new ArrayList<>();
inputRequest.setParams(inputRequestParams);

params.forEach(param -> {
InputRequestParam requestParam = toInputRequestParam(parserIt, param);

if(requestParam != null) {
inputRequestParams.add(requestParam);
} else {
LOGGER.warning("Not support for " + param);
}
});
}

return inputRequest;
}

public static InputRequestParam toInputRequestParam(Iterator<ParamValueParser> parserIt, ParameterDefinition param) {
String paramType = param.getType();
InputRequestParam requestParam = null;

while(parserIt.hasNext()) {
ParamValueParser parser = parserIt.next();
if(parser.accept(paramType)) {
requestParam = parser.toInputRequestParam(param);
break;
}
}

return requestParam;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package io.alauda.jenkins.devops.sync.model;

import java.util.List;

public class InputRequest {
private String id;
private String buildID;
private String message;
private String submitter;
private List<InputRequestParam> params;
private String status;
private String baseURI;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getBuildID() {
return buildID;
}

public void setBuildID(String buildID) {
this.buildID = buildID;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public String getSubmitter() {
return submitter;
}

public void setSubmitter(String submitter) {
this.submitter = submitter;
}

public List<InputRequestParam> getParams() {
return params;
}

public void setParams(List<InputRequestParam> params) {
this.params = params;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public String getBaseURI() {
return baseURI;
}

public void setBaseURI(String baseURI) {
this.baseURI = baseURI;
}
}
Loading