Skip to content

Commit b48a5da

Browse files
authored
Merge pull request #20 from bdpiparva/run-container-in-privileged-mode
Run container in privileged mode to support docker-in-docker and docker-out-of-docker.
2 parents ebb760e + b6cebab commit b48a5da

File tree

9 files changed

+74
-21
lines changed

9 files changed

+74
-21
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ To build the jar, run `./gradlew clean build`
1515
## License
1616

1717
```plain
18-
Copyright 2017 ThoughtWorks, Inc.
18+
Copyright 2018 ThoughtWorks, Inc.
1919
2020
Licensed under the Apache License, Version 2.0 (the "License");
2121
you may not use this file except in compliance with the License.

build.gradle

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017 ThoughtWorks, Inc.
2+
* Copyright 2018 ThoughtWorks, Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ dependencies {
5454
compile group: 'com.google.guava', name: 'guava', version: '19.0'
5555
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.4'
5656
compile group: 'joda-time', name: 'joda-time', version: '2.9.4'
57-
compile group: 'io.fabric8', name: 'kubernetes-client', version: '3.1.6'
57+
compile group: 'io.fabric8', name: 'kubernetes-client', version: '3.1.8'
5858
compile group: 'com.github.spullara.mustache.java', name: 'compiler', version: '0.9.5'
5959
compile group: 'org.freemarker', name: 'freemarker', version: '2.3.23'
6060

@@ -81,9 +81,9 @@ jar {
8181
from(configurations.compile) {
8282
into "lib/"
8383
}
84-
from(sourceSets.main.java) {
85-
into "/"
86-
}
84+
// from(sourceSets.main.java) {
85+
// into "/"
86+
// }
8787
}
8888

8989
tasks.withType(Jar) { jarTask ->

src/main/java/cd/go/contrib/elasticagent/KubernetesInstanceFactory.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017 ThoughtWorks, Inc.
2+
* Copyright 2018 ThoughtWorks, Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,6 +37,7 @@
3737

3838
import static cd.go.contrib.elasticagent.KubernetesPlugin.LOG;
3939
import static cd.go.contrib.elasticagent.executors.GetProfileMetadataExecutor.POD_CONFIGURATION;
40+
import static cd.go.contrib.elasticagent.executors.GetProfileMetadataExecutor.PRIVILEGED;
4041
import static cd.go.contrib.elasticagent.utils.Util.GSON;
4142
import static cd.go.contrib.elasticagent.utils.Util.getSimpleDateFormat;
4243
import static org.apache.commons.lang3.StringUtils.isBlank;
@@ -57,6 +58,7 @@ private KubernetesInstance create(CreateAgentRequest request, PluginSettings set
5758
container.setName(containerName);
5859
container.setImage(image(request.properties()));
5960
container.setImagePullPolicy("IfNotPresent");
61+
container.setSecurityContext(new SecurityContextBuilder().withPrivileged(privileged(request)).build());
6062

6163
container.setResources(getPodResources(request));
6264

@@ -73,6 +75,14 @@ private KubernetesInstance create(CreateAgentRequest request, PluginSettings set
7375
return createKubernetesPod(client, elasticAgentPod);
7476
}
7577

78+
private Boolean privileged(CreateAgentRequest request) {
79+
final String privilegedMode = request.properties().get(PRIVILEGED.getKey());
80+
if (StringUtils.isBlank(privilegedMode)) {
81+
return false;
82+
}
83+
return Boolean.valueOf(privilegedMode);
84+
}
85+
7686
private void setGoCDMetadata(CreateAgentRequest request, PluginSettings settings, PluginRequest pluginRequest, Pod elasticAgentPod) {
7787
elasticAgentPod.getMetadata().setCreationTimestamp(getSimpleDateFormat().format(new Date()));
7888

src/main/java/cd/go/contrib/elasticagent/executors/GetProfileMetadataExecutor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017 ThoughtWorks, Inc.
2+
* Copyright 2018 ThoughtWorks, Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@ public class GetProfileMetadataExecutor implements RequestExecutor {
3434
public static final Metadata ENVIRONMENT = new Metadata("Environment", false, false);
3535
public static final Metadata POD_CONFIGURATION = new Metadata("PodConfiguration", false, false);
3636
public static final Metadata SPECIFIED_USING_POD_CONFIGURATION = new Metadata("SpecifiedUsingPodConfiguration", true, false);
37+
public static final Metadata PRIVILEGED = new Metadata("Privileged", false, false);
3738
public static final List<Metadata> FIELDS = new ArrayList<>();
3839

3940
static {
@@ -43,6 +44,7 @@ public class GetProfileMetadataExecutor implements RequestExecutor {
4344
FIELDS.add(ENVIRONMENT);
4445
FIELDS.add(POD_CONFIGURATION);
4546
FIELDS.add(SPECIFIED_USING_POD_CONFIGURATION);
47+
FIELDS.add(PRIVILEGED);
4648
}
4749

4850
@Override

src/main/resources/profile.template.html

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
~ Copyright 2017 ThoughtWorks, Inc.
2+
~ Copyright 2018 ThoughtWorks, Inc.
33
~
44
~ Licensed under the Apache License, Version 2.0 (the "License");
55
~ you may not use this file except in compliance with the License.
@@ -87,6 +87,14 @@
8787
background-color: #e6e6e6;
8888
border-radius: 3px;
8989
}
90+
91+
[data-plugin-style-id="kubernetes-plugin"] .form-help-content {
92+
color: #666;
93+
font-style: italic;
94+
clear: both;
95+
font-size: 0.82rem;
96+
}
97+
9098
</style>
9199

92100
<div class="row collapse">
@@ -150,6 +158,16 @@
150158
ng-show="GOINPUTNAME[MaxCPU].$error.server">{{GOINPUTNAME[MaxCPU].$error.server}}</span>
151159
</div>
152160
</div>
161+
162+
<div class="form_item_block">
163+
<input ng-class="{'is-invalid-input': GOINPUTNAME[Privileged].$error.server}" type="checkbox" ng-model="Privileged" ng-required="true" ng-true-value="true" ng-false-value="false" id="Privileged"/>
164+
<label ng-class="{'is-invalid-label': GOINPUTNAME[Privileged].$error.server}" for="Privileged">Privileged</label>
165+
<span class="form_error form-error" ng-class="{'is-visible': GOINPUTNAME[Privileged].$error.server}" ng-show="GOINPUTNAME[Privileged].$error.server">{{GOINPUTNAME[Privileged].$error.server}}</span>
166+
<span class="form-help-content">
167+
<strong>Note:</strong> When privileged mode is enabled, the container is given elevated privileges on the host container instance.
168+
</span>
169+
</div>
170+
153171
<div class="form_item_block">
154172
<label ng-class="{'is-invalid-label': GOINPUTNAME[Environment].$error.server}">Environment Variables
155173
<small>(Enter one variable per line)</small>
@@ -200,7 +218,9 @@
200218
spec:
201219
containers:
202220
- name: gocd-agent-container-{{ CONTAINER_POSTFIX }}
203-
image: {{ GOCD_AGENT_IMAGE }}:{{ LATEST_VERSION }}')">
221+
image: {{ GOCD_AGENT_IMAGE }}:{{ LATEST_VERSION }}
222+
securityContext:
223+
privileged: true')">
204224
</textarea>
205225
<span class="form_error form-error" ng-class="{'is-visible': GOINPUTNAME[PodConfiguration].$error.server}"
206226
ng-show="GOINPUTNAME[PodConfiguration].$error.server">{{GOINPUTNAME[PodConfiguration].$error.server}}</span>

src/test/java/cd/go/contrib/elasticagent/CreateAgentRequestMother.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public static CreateAgentRequest defaultCreateAgentRequest() {
3333
"ENV2=VALUE2");
3434
properties.put("PodConfiguration", "");
3535
properties.put("SpecifiedUsingPodConfiguration", "false");
36+
properties.put("Privileged", "false");
3637

3738
String environment = "QA";
3839
JobIdentifier identifier = new JobIdentifier("up_42", 1L, "up_42_label", "up42_stage", "20", "up42_job", 10L);

src/test/java/cd/go/contrib/elasticagent/KubernetesAgentInstancesIntegrationTest.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@
2525
import org.junit.Test;
2626
import org.mockito.ArgumentCaptor;
2727
import org.mockito.Mock;
28-
import org.mockito.invocation.InvocationOnMock;
2928
import org.mockito.stubbing.Answer;
3029

3130
import java.util.ArrayList;
3231
import java.util.HashMap;
3332
import java.util.List;
3433
import java.util.Map;
3534

35+
import static cd.go.contrib.elasticagent.executors.GetProfileMetadataExecutor.PRIVILEGED;
3636
import static org.hamcrest.Matchers.is;
3737
import static org.junit.Assert.*;
3838
import static org.mockito.ArgumentMatchers.any;
@@ -66,12 +66,9 @@ public void setUp() throws Exception {
6666

6767
when(pods.inNamespace(Constants.KUBERNETES_NAMESPACE)).thenReturn(pods);
6868

69-
when(pods.create(any())).thenAnswer(new Answer<Pod>() {
70-
@Override
71-
public Pod answer(InvocationOnMock invocation) throws Throwable {
72-
Object[] args = invocation.getArguments();
73-
return (Pod) args[0];
74-
}
69+
when(pods.create(any())).thenAnswer((Answer<Pod>) invocation -> {
70+
Object[] args = invocation.getArguments();
71+
return (Pod) args[0];
7572
});
7673

7774
when(pods.list()).thenReturn(new PodList());
@@ -104,6 +101,24 @@ public void shouldCreateKubernetesPodWithContainerSpecification() throws Excepti
104101

105102
assertThat(gocdAgentContainer.getImage(), is("gocd/custom-gocd-agent-alpine:latest"));
106103
assertThat(gocdAgentContainer.getImagePullPolicy(), is("IfNotPresent"));
104+
assertThat(gocdAgentContainer.getSecurityContext().getPrivileged(), is(false));
105+
}
106+
107+
@Test
108+
public void shouldCreateKubernetesPodWithPrivilegedMod() throws Exception {
109+
createAgentRequest.properties().put(PRIVILEGED.getKey(), "true");
110+
ArgumentCaptor<Pod> argumentCaptor = ArgumentCaptor.forClass(Pod.class);
111+
KubernetesInstance instance = kubernetesAgentInstances.create(createAgentRequest, settings, mockedPluginRequest);
112+
verify(pods).create(argumentCaptor.capture());
113+
Pod elasticAgentPod = argumentCaptor.getValue();
114+
115+
List<Container> containers = elasticAgentPod.getSpec().getContainers();
116+
assertThat(containers.size(), is(1));
117+
118+
Container gocdAgentContainer = containers.get(0);
119+
120+
assertThat(gocdAgentContainer.getName(), is(instance.name()));
121+
assertThat(gocdAgentContainer.getSecurityContext().getPrivileged(), is(true));
107122
}
108123

109124
@Test

src/test/java/cd/go/contrib/elasticagent/executors/GetProfileMetadataExecutorTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,16 @@ public void assertJsonStructure() throws Exception {
8282
" \"required\": true,\n" +
8383
" \"secure\": false\n" +
8484
" }\n" +
85+
" },\n" +
86+
" {\n" +
87+
" \"key\": \"Privileged\",\n" +
88+
" \"metadata\": {\n" +
89+
" \"required\": false,\n" +
90+
" \"secure\": false\n" +
91+
" }\n" +
8592
" }\n" +
8693
"]";
8794

8895
JSONAssert.assertEquals(expectedJSON, response.responseBody(), true);
8996
}
90-
9197
}

src/test/java/cd/go/contrib/elasticagent/executors/GetProfileViewExecutorTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void shouldRenderTheTemplateInJSON() throws Exception {
4141
}
4242

4343
@Test
44-
public void allFieldsShouldBePresentInView() throws Exception {
44+
public void allFieldsShouldBePresentInView() {
4545
String template = Util.readResource("/profile.template.html");
4646
final Document document = Jsoup.parse(template);
4747

@@ -58,8 +58,7 @@ public void allFieldsShouldBePresentInView() throws Exception {
5858
assertThat(spanToShowError.text(), is("{{GOINPUTNAME[" + field.getKey() + "].$error.server}}"));
5959
}
6060

61-
final Elements inputs = document.select("textarea,input[type=text],select");
61+
final Elements inputs = document.select("textarea,input[type=text],select,input[type=checkbox]");
6262
assertThat(inputs, hasSize(GetProfileMetadataExecutor.FIELDS.size() - 1)); // do not include SPECIFIED_USING_POD_CONFIGURATION key
6363
}
64-
6564
}

0 commit comments

Comments
 (0)