forked from lsegal/jenkins-codebuilder-plugin
-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathCodeBuilderLauncher.java
More file actions
156 lines (134 loc) · 5.26 KB
/
CodeBuilderLauncher.java
File metadata and controls
156 lines (134 loc) · 5.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package dev.lsegal.jenkins.codebuilder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.TimeoutException;
import javax.annotation.Nonnull;
import com.amazonaws.services.codebuild.model.SourceType;
import com.amazonaws.services.codebuild.model.StartBuildRequest;
import com.amazonaws.services.codebuild.model.StartBuildResult;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import hudson.model.Node;
import hudson.model.TaskListener;
import hudson.slaves.JNLPLauncher;
import hudson.slaves.SlaveComputer;
import hudson.util.StreamTaskListener;
/**
* CodeBuilderLauncher class.
*
* @author Loren Segal
*/
public class CodeBuilderLauncher extends JNLPLauncher {
private static final int sleepMs = 500;
private static final Logger LOGGER = LoggerFactory.getLogger(CodeBuilderLauncher.class);
private final CodeBuilderCloud cloud;
private boolean launched;
/**
* Constructor for CodeBuilderLauncher.
*
* @param cloud a {@link CodeBuilderCloud} object.
* @param tunnel tunnel URL if configured {@link String}
* @param vmargs a {@link String}
*/
public CodeBuilderLauncher(CodeBuilderCloud cloud, String tunnel, String vmargs) {
super(tunnel, vmargs);
this.cloud = cloud;
this.setWebSocket(this.cloud.isWebSocket());
}
/** {@inheritDoc} */
@Override
public boolean isLaunchSupported() {
return !launched;
}
/** {@inheritDoc} */
@Override
public void launch(@Nonnull SlaveComputer computer, @Nonnull TaskListener listener) {
this.launched = false;
if (!(computer instanceof CodeBuilderComputer)) {
LOGGER.error("[CodeBuilder]: Not launching {} since it is not the correct type ({})", computer,
CodeBuilderComputer.class.getName());
return;
}
Node node = computer.getNode();
if (node == null) {
LOGGER.error("[CodeBuilder]: Not launching {} since it is missing a node.", computer);
return;
}
LOGGER.info("[CodeBuilder]: Launching {} with {}", computer, listener);
CodeBuilderComputer cbcpu = (CodeBuilderComputer) computer;
StartBuildRequest req = new StartBuildRequest().withProjectName(cloud.getProjectName())
.withSourceTypeOverride(SourceType.NO_SOURCE).withBuildspecOverride(buildspec(computer))
.withImageOverride(cloud.getJnlpImage()).withPrivilegedModeOverride(true)
.withComputeTypeOverride(cloud.getComputeType());
try {
StartBuildResult res = cloud.getClient().startBuild(req);
String buildId = res.getBuild().getId();
cbcpu.setBuildId(buildId);
LOGGER.info("[CodeBuilder]: Waiting for agent '{}' to connect to build ID: {}...", computer, buildId);
for (int i = 0; i < cloud.getAgentTimeout() * (1000 / sleepMs); i++) {
if (computer.isOnline() && computer.isAcceptingTasks()) {
LOGGER.info("[CodeBuilder]: Agent '{}' connected to build ID: {}.", computer, buildId);
launched = true;
return;
}
Thread.sleep(sleepMs);
}
throw new TimeoutException("Timed out while waiting for agent " + node + " to start for build ID: " + buildId);
} catch (Exception e) {
cbcpu.setBuildId(null);
LOGGER.error("[CodeBuilder]: Exception while starting build: {}", e.getMessage(), e);
listener.fatalError("Exception while starting build: %s", e.getMessage());
if (node instanceof CodeBuilderAgent) {
try {
CodeBuilderCloud.jenkins().removeNode(node);
} catch (IOException e1) {
LOGGER.error("Failed to terminate agent: {}", node.getDisplayName(), e);
}
}
}
}
/** {@inheritDoc} */
@Override
public void beforeDisconnect(@Nonnull SlaveComputer computer, @Nonnull StreamTaskListener listener) {
if (computer instanceof CodeBuilderComputer) {
((CodeBuilderComputer) computer).setBuildId(null);
}
}
private String buildspec(@Nonnull SlaveComputer computer) {
Node n = computer.getNode();
if (n == null) {
return "";
}
Collection<String> command = new ArrayList<String>(Arrays.asList(
"jenkins-agent",
"-noreconnect",
"-workDir",
"\"$CODEBUILD_SRC_DIR\"",
"-url",
String.format("\"%s\"", cloud.getJenkinsUrl()),
String.format("\"%s\"", computer.getJnlpMac()),
String.format("\"%s\"", n.getDisplayName())
));
if (isWebSocket()) {
command.add("-webSocket");
}
if (StringUtils.isNotBlank(tunnel)) {
command.add("-tunnel");
command.add(cloud.getTunnel());
}
String cmd = String.join(" ", command);
StringBuilder builder = new StringBuilder();
builder.append("version: 0.2\n");
builder.append("phases:\n");
builder.append(" pre_build:\n");
builder.append(" commands:\n");
builder.append(" - which dockerd-entrypoint.sh >/dev/null && dockerd-entrypoint.sh || exit 0\n");
builder.append(" build:\n");
builder.append(" commands:\n");
builder.append(" - " + cmd + " || exit 0\n");
return builder.toString();
}
}