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

Support --cgroup-parent flag #1056

Merged
merged 2 commits into from
Mar 8, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def templateBaseParameters = [
// bindPorts: '',
// capabilitiesToAddString: '',
// capabilitiesToDropString: '',
// cgroupParent: '',
// cpus: '',
// cpuPeriod: (Long)null,
// cpuQuota: (Long)null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@
return dockerTemplateBase.getMemorySwap();
}

public String getCgroupParent() {
return dockerTemplateBase.getCgroupParent();

Check warning on line 204 in src/main/java/com/nirima/jenkins/plugins/docker/DockerTemplate.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 204 is not covered by tests
}

public String getCpus() {
return dockerTemplateBase.getCpus();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@

public @CheckForNull Integer memoryLimit;
public @CheckForNull Integer memorySwap;
public @CheckForNull String cgroupParent;
public @CheckForNull String cpus;
public @CheckForNull Long cpuPeriod;
public @CheckForNull Long cpuQuota;
Expand Down Expand Up @@ -460,6 +461,16 @@
this.memorySwap = memorySwap;
}

@CheckForNull
public String getCgroupParent() {
return Util.fixEmpty(cgroupParent);
}

@DataBoundSetter
public void setCgroupParent(String cgroupParent) {
this.cgroupParent = Util.fixEmpty(cgroupParent);
}

@CheckForNull
public String getCpus() {
return Util.fixEmpty(cpus);
Expand Down Expand Up @@ -817,6 +828,11 @@
}
}

final String cgroupParentOrNull = getCgroupParent();
if (cgroupParentOrNull != null && !Strings.isNullOrEmpty(cgroupParentOrNull)) {

Check warning on line 832 in src/main/java/com/nirima/jenkins/plugins/docker/DockerTemplateBase.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 832 is only partially covered, one branch is missing
hostConfig(containerConfig).withCgroupParent(cgroupParentOrNull);
}

final String[] dnsHostsOrNull = getDnsHosts();
if (dnsHostsOrNull != null && dnsHostsOrNull.length > 0) {
hostConfig(containerConfig).withDns(dnsHostsOrNull);
Expand Down Expand Up @@ -1149,6 +1165,9 @@
if (!Objects.equals(memorySwap, that.memorySwap)) {
return false;
}
if (!Objects.equals(cgroupParent, that.cgroupParent)) {
return false;

Check warning on line 1169 in src/main/java/com/nirima/jenkins/plugins/docker/DockerTemplateBase.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 1168-1169 are not covered by tests
}
if (!Objects.equals(cpus, that.cpus)) {
return false;
}
Expand Down Expand Up @@ -1206,6 +1225,7 @@
result = 31 * result + (bindAllPorts ? 1 : 0);
result = 31 * result + (memoryLimit != null ? memoryLimit.hashCode() : 0);
result = 31 * result + (memorySwap != null ? memorySwap.hashCode() : 0);
result = 31 * result + (cgroupParent != null ? cgroupParent.hashCode() : 0);

Check warning on line 1228 in src/main/java/com/nirima/jenkins/plugins/docker/DockerTemplateBase.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 1228 is only partially covered, one branch is missing
result = 31 * result + (cpus != null ? cpus.hashCode() : 0);
result = 31 * result + (cpuPeriod != null ? cpuPeriod.hashCode() : 0);
result = 31 * result + (cpuQuota != null ? cpuQuota.hashCode() : 0);
Expand Down Expand Up @@ -1244,6 +1264,7 @@
bldToString(sb, "bindAllPorts", bindAllPorts);
bldToString(sb, "memoryLimit", memoryLimit);
bldToString(sb, "memorySwap", memorySwap);
bldToString(sb, "cgroupParent", cgroupParent);

Check warning on line 1267 in src/main/java/com/nirima/jenkins/plugins/docker/DockerTemplateBase.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 1267 is not covered by tests
bldToString(sb, "cpus", cpus);
bldToString(sb, "cpuPeriod", cpuPeriod);
bldToString(sb, "cpuQuota", cpuQuota);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
public final String bindPorts;
public final Integer memoryLimit;
public final Integer memorySwap;
public final String cgroupParent;
public final String cpus;
public final Long cpuPeriod;
public final Long cpuQuota;
Expand All @@ -75,6 +76,7 @@
String extraGroupsString,
Integer memoryLimit,
Integer memorySwap,
String cgroupParent,
String cpus,
Long cpuPeriod,
Long cpuQuota,
Expand Down Expand Up @@ -102,109 +104,111 @@
this.bindPorts = bindPorts;
this.memoryLimit = memoryLimit;
this.memorySwap = memorySwap;
this.cgroupParent = cgroupParent;
this.cpus = cpus;
this.cpuPeriod = cpuPeriod;
this.cpuQuota = cpuQuota;
this.cpuShares = cpuShares;
this.shmSize = shmSize;
this.bindAllPorts = bindAllPorts;
this.macAddress = macAddress;
}

public DockerRegistryEndpoint getRegistry() {
if (registry == null) {
registry = new DockerRegistryEndpoint(null, pullCredentialsId);
}
return registry;
}

@Override
public void execute(Run<?, ?> build, Launcher launcher, TaskListener listener) throws DockerException, IOException {
final PrintStream llog = listener.getLogger();

final DockerCloud cloud = getCloud(build, launcher);
final DockerAPI dockerApi = cloud.getDockerApi();

String xImage = expand(build, image);
String xCommand = expand(build, dockerCommand);
String xHostname = expand(build, hostname);
String xUser = expand(build, user);

LOG.info("Pulling image {}", xImage);
llog.println("Pulling image " + xImage);

// need a client that will tolerate lengthy pauses for a docker pull
try (final DockerClient clientWithoutReadTimeout = dockerApi.getClient(0)) {
executePullOnDocker(build, llog, xImage, clientWithoutReadTimeout);
}
// but the remainder can use a normal client with the default timeout
try (final DockerClient client = dockerApi.getClient()) {
executeOnDocker(build, llog, xImage, xCommand, xHostname, xUser, client);
}
}

private void executePullOnDocker(Run<?, ?> build, PrintStream llog, String xImage, DockerClient client)
throws DockerException {
PullImageResultCallback resultCallback = new PullImageResultCallback() {
@Override
public void onNext(PullResponseItem item) {
if (item.getStatus() != null && item.getProgress() == null) {
llog.print(item.getId() + ":" + item.getStatus());
LOG.info("{} : {}", item.getId(), item.getStatus());
}
super.onNext(item);
}
};

PullImageCmd cmd = client.pullImageCmd(xImage);
DockerCloud.setRegistryAuthentication(
cmd, getRegistry(), build.getParent().getParent());
try {
cmd.exec(resultCallback).awaitCompletion();
} catch (InterruptedException e) {
throw new DockerClientException("Interrupted while pulling image", e);
}
}

private void executeOnDocker(
Run<?, ?> build,
PrintStream llog,
String xImage,
String xCommand,
String xHostname,
String xUser,
DockerClient client)
throws DockerException {
try {
client.inspectImageCmd(xImage).exec();
} catch (NotFoundException e) {
throw new DockerClientException("Failed to pull image: " + image, e);
}

DockerTemplateBase template = new DockerSimpleTemplate(
xImage,
pullCredentialsId,
dnsString,
network,
xCommand,
mountsString,
volumesFrom,
environmentsString,
xHostname,
xUser,
extraGroupsString,
memoryLimit,
memorySwap,
cpuPeriod,
cpuQuota,
cpuShares,
shmSize,
bindPorts,
bindAllPorts,
privileged,
tty,
macAddress,
null);
template.setCgroupParent(cgroupParent);

Check warning on line 211 in src/main/java/com/nirima/jenkins/plugins/docker/builder/DockerBuilderControlOptionRun.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 107-211 are not covered by tests

LOG.info("Starting container for image {}", xImage);
llog.println("Starting container for image " + xImage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
<f:number />
</f:entry>

<f:entry title="${%CGroup Parent}" field="cgroupParent">
<f:textbox/>
</f:entry>

<f:entry title="${%CPU resources}" field="cpus">
<f:textbox />
</f:entry>
Expand Down Expand Up @@ -127,4 +131,4 @@
</f:nested>
</f:advanced>

</j:jelly>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div>
<p>This allows agents to run in a cgroup other than the daemon/system default.</p>
<p>Please check <a href="https://docs.docker.com/reference/cli/docker/container/run/#cgroup-parent">https://docs.docker.com/reference/cli/docker/container/run/#cgroup-parent</a> for further information.</p>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ public void globalConfigRoundtrip() throws Exception {
templateBase.setCapabilitiesToAddString("SYS_ADMIN");
templateBase.setCapabilitiesToDropString("CHOWN");
templateBase.setSecurityOptsString("seccomp=unconfined");
templateBase.setCgroupParent("");
final DockerTemplate template = new DockerTemplate(
templateBase, new DockerComputerAttachConnector("jenkins"), "labelString", "remoteFs", "10");
template.setPullStrategy(DockerImagePullStrategy.PULL_NEVER);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,36 @@ private static void testFillContainerCapabilitiesToDrop(
}
}

@Test
public void fillContainerConfigCgroupParent() {
testFillContainerConfigCgroupParent("not existing", "dummy_cgroup_parent", true);
}

@Test
public void fillContainerConfigNoCgroupParent() {
testFillContainerConfigCgroupParent("not existing", "", false);
}

private static void testFillContainerConfigCgroupParent(
final String imageName, final String cgroupParent, final boolean wasSet) {
// Given
final CreateContainerCmd mockCmd = mock(CreateContainerCmd.class);
final HostConfig mockHostConfig = mock(HostConfig.class);
when(mockCmd.getHostConfig()).thenReturn(mockHostConfig);
final DockerTemplateBase instanceUnderTest = new DockerTemplateBase(imageName);
instanceUnderTest.setCgroupParent(cgroupParent);

// When
instanceUnderTest.fillContainerConfig(mockCmd);

// Then
if (wasSet) {
verify(mockHostConfig, times(1)).withCgroupParent(cgroupParent);
} else {
verify(mockHostConfig, never()).withCgroupParent(cgroupParent);
}
}

@Test
public void fillContainerConfigCpus() {
testFillContainerConfigCpus("not existing", "1.5", 1500000000L);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class DockerTemplateTest {
String javaPath = " javaPath";
Integer memoryLimit = 1024;
Integer memorySwap = 1280;
String cgroupParent = "cgroupParent";
Long cpuPeriod = 0L;
Long cpuQuota = 0L;
Integer cpuShares = 1000;
Expand Down Expand Up @@ -72,6 +73,7 @@ private DockerTemplate getDockerTemplateInstanceWithDNSHost(String dnsString) {
dockerTemplateBase.setCapabilitiesToAddString(capabilitiesToAddString);
dockerTemplateBase.setCapabilitiesToDropString(capabilitiesToDropString);
dockerTemplateBase.setSecurityOptsString(securityOptsString);
dockerTemplateBase.setCgroupParent(cgroupParent);

return new DockerTemplate(dockerTemplateBase, null, labelString, remoteFs, instanceCapStr);
}
Expand Down
Loading