Skip to content

Commit a3fbeb9

Browse files
authored
2.0.1 fixes (#12)
* Major rework of networking, to support multi deployment setups HarborManagerContainer.groovy * Now also modifies the supplied docker compose file to move all containers to a custom network Container.groovy * Some renaming of variables and methods needed, because the groovy autogenerated methods led to confusion and inconsistency. * HarborManagerContainer.groovy * Bug in bash setup script Container.groovy * Bug in status() HarborDeployment.groovy * Improved stopAndRemoveDeployment() so it can stop deployment even if manager container is missing pom.xml * Fixed problems with shading * Untested DockerClientDS.groovy * Extendes the default DockerClientImpl with an exec command that allows a ExecConfig to be supplied Container.groovy * Now uses DockerClientDS * runCommandInContainer now alloes user, group and working dir to be supplied pom.xml * Excluded most/all of groovy from standalone jar to not conflict with the hosting groovy version, consider perhaps instead setting groovy with scope provided
1 parent 03531eb commit a3fbeb9

17 files changed

Lines changed: 477 additions & 140 deletions

Environments/Terraform/main.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,9 +288,9 @@ resource "aws_lb" "load-balancer" {
288288

289289
name = "${var.tags.useCase}-${var.tags.owner}-lb"
290290
internal = false
291-
load_balancer_type = "network"
291+
load_balancer_type = "application"
292292
subnets = [aws_subnet.base-stack-public-subnet.id]
293-
293+
enable_deletion_protection = false
294294

295295
}
296296

pom.xml

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.eficode</groupId>
88
<artifactId>devstack</artifactId>
9-
<version>2.0.0-SNAPSHOT-groovy-${groovy.major.version}</version>
9+
<version>2.0.1-SNAPSHOT-groovy-${groovy.major.version}</version>
1010
<packaging>jar</packaging>
1111

1212
<name>DevStack - Parent pom</name>
@@ -157,22 +157,36 @@
157157
<!-- final name of the shaded jar will be ${project.artifactId}-standalone -->
158158
<shadedClassifierName>standalone</shadedClassifierName>
159159

160+
<filters>
161+
<filter>
162+
<artifact>*:*</artifact>
163+
<excludes>
164+
<exclude>META-INF/*.SF</exclude>
165+
<exclude>META-INF/*.DSA</exclude>
166+
<exclude>META-INF/*.RSA</exclude>
167+
</excludes>
168+
</filter>
169+
</filters>
170+
160171
<artifactSet>
161172
<excludes>
162-
<exclude>org.codehaus.groovy:groovy</exclude>
173+
<exclude>org.codehaus.groovy:*</exclude>
174+
<!--exclude>org.codehaus.groovy:groovy</exclude>
175+
<exclude>org.codehaus.groovy:groovy-astbuilder</exclude-->
176+
163177
<exclude>com.google.code.gson:gson</exclude>
164178
<exclude>org.apache.httpcomponents</exclude>
165179
<exclude>commons-*</exclude>
166180

167181
</excludes>
168182

169183
</artifactSet>
170-
<!--relocations>
184+
<relocations>
171185
<relocation>
172-
<pattern>kong.unirest.</pattern>
173-
<shadedPattern>com.eficode.shaded.kong.unirest.</shadedPattern>
186+
<pattern>com.eficode.atlassian</pattern>
187+
<shadedPattern>com.eficode.shaded.atlassian</shadedPattern>
174188
</relocation>
175-
</relocations-->
189+
</relocations>
176190

177191
<!-- NOTE: Any dependencies of the project will not show up in the standalone pom.
178192
This means that if those dependencies are not properly relocated and there is a class-loading conflict,

src/main/groovy/com/eficode/devstack/container/Container.groovy

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.eficode.devstack.container
22

3-
import de.gesellix.docker.client.DockerClientImpl
3+
import com.eficode.devstack.util.DockerClientDS
44
import de.gesellix.docker.client.EngineResponseContent
55
import de.gesellix.docker.client.network.ManageNetworkClient
66
import de.gesellix.docker.engine.DockerClientConfig
@@ -11,6 +11,7 @@ import de.gesellix.docker.remote.api.ContainerInspectResponse
1111
import de.gesellix.docker.remote.api.ContainerState
1212
import de.gesellix.docker.remote.api.ContainerSummary
1313
import de.gesellix.docker.remote.api.EndpointSettings
14+
import de.gesellix.docker.remote.api.ExecConfig
1415
import de.gesellix.docker.remote.api.HostConfig
1516
import de.gesellix.docker.remote.api.IdResponse
1617
import de.gesellix.docker.remote.api.Mount
@@ -40,21 +41,20 @@ import java.util.regex.Pattern
4041
trait Container {
4142

4243
Logger log = LoggerFactory.getLogger(self.class)
43-
DockerClientImpl dockerClient = new DockerClientImpl()
44+
DockerClientDS dockerClient = new DockerClientDS()
4445
ManageNetworkClient networkClient = dockerClient.getManageNetwork() as ManageNetworkClient
4546
abstract String containerName
4647
abstract String containerMainPort
4748
abstract String containerImage
4849
abstract String containerImageTag
50+
ArrayList<String> containerDefaultNetworks = ["bridge"]
4951
ArrayList<String> customEnvVar = []
50-
//String containerNetworkName = "bridge"
5152
String defaultShell = "/bin/bash"
5253
String containerId
5354
ArrayList<Mount> mounts = []
5455

5556

5657
void prepareBindMount(String sourceAbs, String target, boolean readOnly = true) {
57-
assert !isCreated(): "Bind mounts cant be prepared for already created container"
5858

5959
Mount newMount = new Mount().tap { m ->
6060
m.source = sourceAbs
@@ -89,7 +89,6 @@ trait Container {
8989
c.hostname = self.containerName
9090
c.env = self.customEnvVar
9191

92-
9392
}
9493

9594
return containerCreateRequest
@@ -98,11 +97,11 @@ trait Container {
9897

9998
/**
10099
* Create container and override default docker cmd and entrypoint
101-
* @param cmd:
100+
* @param cmd :
102101
* @param entrypoint ex: ["tail", "-f", "/dev/null"]
103102
* @return container id
104103
*/
105-
String createContainer(ArrayList<String> cmd, ArrayList<String> entrypoint) {
104+
String createContainer(ArrayList<String> cmd = [], ArrayList<String> entrypoint = []) {
106105

107106
assert ping(): "Error connecting to docker engine"
108107

@@ -119,14 +118,14 @@ trait Container {
119118
EngineResponseContent response = dockerClient.createContainer(containerCreateRequest, self.containerName)
120119
assert response.content.warnings.isEmpty(): "Error when creating ${self.containerName} container:" + response.content.warnings.join(",")
121120

121+
ArrayList<Network> networks = containerDefaultNetworks.collect { createBridgeNetwork(it) }
122+
assert setContainerNetworks(networks): "Error setting container networks to:" + containerDefaultNetworks
123+
122124
containerId = response.content.id
123125
return containerId
124126

125127
}
126128

127-
String createContainer() {
128-
return createContainer([], [])
129-
}
130129

131130
boolean runOnFirstStartup() {
132131
return true
@@ -145,7 +144,7 @@ trait Container {
145144
dockerEnv.setCertPath(certPath)
146145
dockerEnv.setTlsVerify("1")
147146
dockerConfig.apply(dockerEnv)
148-
dockerClient = new DockerClientImpl(dockerConfig)
147+
dockerClient = new DockerClientDS(dockerConfig)
149148
networkClient = dockerClient.getManageNetwork() as ManageNetworkClient
150149

151150

@@ -248,10 +247,8 @@ trait Container {
248247

249248
if (status == ContainerState.Status.Created) {
250249
return true //Created but not started
251-
} else if (status == null) {
252-
return true //Not even created
253250
} else {
254-
return false
251+
return status == null
255252
}
256253

257254
}
@@ -270,7 +267,7 @@ trait Container {
270267
}
271268

272269
ContainerState.Status status() {
273-
return inspectContainer().state.status
270+
return inspectContainer()?.state?.status
274271
}
275272

276273
boolean stopAndRemoveContainer(Integer timeoutS = 5) {
@@ -469,28 +466,39 @@ trait Container {
469466
* @param networkNameOrId
470467
* @return Network if found, null if not
471468
*/
472-
Network getNetwork(String networkNameOrId) {
469+
Network getDockerNetwork(String networkNameOrId) {
473470

474471

475472
Network network = networkClient.networks().content.find { it.name == networkNameOrId || it.id == networkNameOrId }
476473

477474
return network
478475
}
476+
/**
477+
* Gets networks based on name or id, note there might be multiple networks with the same name
478+
* @param networkNameOrIds
479+
* @return Networks if found, null if not
480+
*/
481+
ArrayList<Network> getDockerNetworks(ArrayList<String> networkNameOrIds) {
482+
483+
ArrayList<Network> networks = networkClient.networks().content.findAll { it.name in networkNameOrIds || it.id in networkNameOrIds }
484+
485+
return networks
486+
}
479487

480488
boolean networkIsValid(Network network) {
481-
return getNetwork(network.id) != null
489+
return getDockerNetwork(network.id) != null
482490
}
483491

484492
/**
485493
* Get the networks that this container is connected too
486494
* @return
487495
*/
488-
ArrayList<Network> getContainerNetworks() {
496+
ArrayList<Network> getConnectedContainerNetworks() {
489497
Map<String, EndpointSettings> rawResponse = inspectContainer().networkSettings.networks
490498

491499
ArrayList<Network> networks = []
492500
rawResponse.keySet().each { networkId ->
493-
Network network = getNetwork(networkId)
501+
Network network = getDockerNetwork(networkId)
494502

495503
if (network != null) {
496504
networks.add(network)
@@ -509,7 +517,7 @@ trait Container {
509517
ArrayList<Network> getContainerBridgeNetworks() {
510518

511519

512-
return getContainerNetworks().findAll { it.driver == "bridge" }
520+
return getConnectedContainerNetworks().findAll { it.driver == "bridge" }
513521

514522
}
515523

@@ -533,7 +541,7 @@ trait Container {
533541
log.trace("\tVerifying container was added to network")
534542

535543

536-
if (containerNetworks.find { it.id == network.id } != null) {
544+
if (connectedContainerNetworks.find { it.id == network.id } != null) {
537545
log.info("\tContainer was successfully added to network")
538546
return true
539547
}
@@ -550,7 +558,7 @@ trait Container {
550558
networkClient.disconnectNetwork(network.id, containerId)
551559
log.trace("\tVerifying container was disconnected from network")
552560

553-
if (!containerNetworks.find { it.id == network.id }) {
561+
if (!connectedContainerNetworks.find { it.id == network.id }) {
554562
log.info("\tContainer was successfully disconnected from network")
555563
return true
556564
}
@@ -569,8 +577,7 @@ trait Container {
569577

570578
log.info("Setting container networks")
571579
log.info("\tBeginning by disconnecting any networks it should no longer be connected to")
572-
ArrayList networks = containerNetworks
573-
containerNetworks.each { connectedNetwork ->
580+
connectedContainerNetworks.each { connectedNetwork ->
574581

575582
if (newNetworks.id.find { newNetworkId -> newNetworkId != connectedNetwork.id }) {
576583
assert disconnectContainerFromNetwork(connectedNetwork): "Error disconnecting container (${containerName}) from network: ${connectedNetwork.name} (${connectedNetwork.id})"
@@ -580,7 +587,7 @@ trait Container {
580587
}
581588
log.info("\tFinished disconnecting container from unwanted networks, now connecting to new networks")
582589

583-
ArrayList<Network> connectedNetworks = containerNetworks
590+
ArrayList<Network> connectedNetworks = connectedContainerNetworks
584591
newNetworks.each { wantedNetwork ->
585592

586593
if (connectedNetworks.id.find { wantedNetwork.id }) {
@@ -644,23 +651,45 @@ trait Container {
644651
}
645652

646653

647-
ArrayList<String> runBashCommandInContainer(String command, long timeoutS = 10) {
654+
//Format is one of: `user`, `user:group`, `uid`, or `uid:gid`
655+
ArrayList<String> runCommandInContainer(String containerId, ArrayList<String> commands, long timeoutS = 10, String userGroup = null, String workingDir = null) {
648656

649657
log.info("Executing bash command in container:")
650658
log.info("\tContainer:" + self.containerName + " (${self.containerId})")
651-
log.info("\tCommand:" + command)
659+
log.info("\tCommand:" + commands)
652660
log.info("\tTimeout:" + timeoutS)
653-
if (log.isTraceEnabled()) {
654-
log.trace("\tDocker ping:" + dockerClient.ping().content as String)
655-
}
656-
657661

658662
long cmdStart = System.currentTimeMillis()
663+
664+
ExecConfig execConfig = new ExecConfig()
665+
execConfig.with { ex ->
666+
ex.attachStdin = false
667+
ex.attachStdout = true
668+
ex.attachStderr = true
669+
ex.detachKeys = null
670+
ex.tty = false
671+
ex.env = null
672+
ex.cmd = commands
673+
ex.privileged = null
674+
ex.user = userGroup ?: null
675+
ex.workingDir = workingDir ?: null
676+
}
677+
659678
ContainerCallback callBack = new ContainerCallback()
660-
EngineResponse<IdResponse> response = dockerClient.exec(self.containerId, [self.defaultShell, "-c", command], callBack, Duration.ofSeconds(timeoutS))
679+
dockerClient.exec(containerId, commands, callBack, Duration.ofSeconds(timeoutS), execConfig)
680+
681+
log.trace("\tCommand finished after:" + ((System.currentTimeMillis() - cmdStart) / 1000).round() + "s")
661682

662-
log.trace("\tCommand finished after:" + ((System.currentTimeMillis()-cmdStart)/1000).round() + "s" )
663683
return callBack.output
684+
685+
}
686+
687+
688+
ArrayList<String> runBashCommandInContainer(String command, long timeoutS = 10, String user = null) {
689+
690+
return runCommandInContainer(self.containerId, [self.defaultShell, "-c", command], timeoutS, user)
691+
692+
664693
}
665694

666695

0 commit comments

Comments
 (0)