Skip to content

Commit 3bb4d39

Browse files
authored
2.3.4 Release - Adding Time Machine (#24)
* pom.xml Bumped to 2.3.2 Bumped DockerClient to 2023-05-07T23-22-00 * pom.xml * Bumped to 2.3.3 JsmContainer.groovy * Added enableJvmDebug() * AlpineContainer.groovy * Moved the runCmdAndRm() and runCmdAndRm() to the interface class Container Container.groovy * added customizeContainerCreateRequest() that allows implementing methods to easily override parts of the ContainerCreateRequest * added runCmdAndRm() TimeMachine.groovy * A new helper method for traveling in time! pom.xml * Bumped to 2.3.4
1 parent 83285b5 commit 3bb4d39

File tree

4 files changed

+240
-108
lines changed

4 files changed

+240
-108
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
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.3.3-SNAPSHOT</version>
9+
<version>2.3.4-SNAPSHOT</version>
1010
<packaging>jar</packaging>
1111

1212
<name>DevStack</name>

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

Lines changed: 130 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import org.slf4j.LoggerFactory
3535
import java.nio.file.Files
3636
import java.nio.file.Path
3737
import java.time.Duration
38+
import java.util.concurrent.TimeoutException
3839
import java.util.regex.Matcher
3940
import java.util.regex.Pattern
4041

@@ -91,8 +92,17 @@ trait Container {
9192

9293
}
9394

94-
return containerCreateRequest
95+
return customizeContainerCreateRequest(containerCreateRequest)
96+
97+
}
9598

99+
/**
100+
* Helper method that allows you to easily customize the ContainerCreateRequest by overriding just this method
101+
* @param containerCreateRequest
102+
* @return
103+
*/
104+
ContainerCreateRequest customizeContainerCreateRequest(ContainerCreateRequest containerCreateRequest) {
105+
return containerCreateRequest
96106
}
97107

98108
/**
@@ -108,7 +118,7 @@ trait Container {
108118
ContainerCreateRequest containerCreateRequest = setupContainerCreateRequest()
109119

110120
if (cmd.size()) {
111-
containerCreateRequest.cmd = cmd
121+
containerCreateRequest.cmd = cmd.collect {it.toString()}
112122
}
113123

114124
if (entrypoint.size()) {
@@ -180,7 +190,7 @@ trait Container {
180190
return containerId
181191
}
182192

183-
def getSelf() {
193+
Container getSelf() {
184194
return this
185195
}
186196

@@ -625,7 +635,7 @@ trait Container {
625635
}
626636

627637
/**
628-
* Copy files from a container
638+
* Copy files from a container to local machine
629639
* @param containerPath can be a file or a path (ending in /)
630640
* @param destinationPath
631641
* @return
@@ -712,6 +722,121 @@ trait Container {
712722
return runCommandInContainer(self.containerId, [self.defaultShell, "-c", command], timeoutS, user)
713723

714724

725+
}
726+
727+
/**
728+
* Creates an temporary container, runs a command, exits and removes container
729+
* @param cmd A string that will be passed as a command to /bin/sh -c, ex: echo start;sleep 5
730+
* @param timeoutMs
731+
* 0 don't wait, return an array with the container ID immediately,
732+
* timeoutMs > 0 Wait for container to stop, if it takes longer than timeoutMs an exception will be thrown
733+
* @param mounts bind mounts that the container should have:
734+
* readOnly is optional and defaults to true
735+
* ex:[[src: "/tmp/engine/test", target: "/tmp/container/test", readOnly :true]
736+
* @param dockerHost
737+
* @param dockerCertPath
738+
* @return An array of the container logs, or just an array containing container id if timeoutMs == 0
739+
*/
740+
static ArrayList<String> runCmdAndRm(String cmd, long timeoutMs, ArrayList<Map> mounts = [], String dockerHost = "", String dockerCertPath = "") {
741+
742+
743+
return runCmdAndRm(["/bin/sh", "-c", cmd], timeoutMs, mounts, dockerHost, dockerCertPath)
744+
}
745+
746+
747+
748+
/**
749+
* Creates a temporary container, runs a command, exits and removes container
750+
* @param container a container object that hasnt yet been created
751+
* @param cmd An array of commands to run, ex: [ "/bin/sh", "-c", "echo start;sleep 5"]
752+
* @param timeoutMs
753+
* 0 don't wait, return an array with the container ID immediately,
754+
* timeoutMs > 0 Wait for container to stop, if it takes longer than timeoutMs an exception will be thrown
755+
* @param mounts bind mounts that the container should have:
756+
* readOnly is optional and defaults to true
757+
* ex:[[src: "/tmp/engine/test", target: "/tmp/container/test", readOnly :true]
758+
* @param dockerHost
759+
* @param dockerCertPath
760+
* @return An array of the container logs, or just an array containing container id if timeoutMs == 0
761+
*/
762+
static ArrayList<String> runCmdAndRm( ArrayList<String> cmd, long timeoutMs, ArrayList<Map> mounts = [], String dockerHost = "", String dockerCertPath = "") {
763+
764+
765+
Container container = this.getConstructor(String, String).newInstance(dockerHost, dockerCertPath)
766+
767+
Logger log = LoggerFactory.getLogger(this.class)
768+
769+
770+
771+
log.info("Creating a $container.class.simpleName and running:")
772+
log.info("\tCmd:" + cmd)
773+
774+
775+
776+
try {
777+
778+
container.containerName = container.containerName + "-cmd-" + System.currentTimeMillis().toString()[-5..-1]
779+
780+
mounts.each {
781+
log.info("\tPreparing Bind mount:")
782+
container.prepareBindMount(it.src as String, it.target as String, it.containsKey("readOnly") ? it.readOnly as Boolean : true)
783+
}
784+
785+
786+
container.createContainer(cmd)
787+
log.info("\tCreated container: " + container.id)
788+
789+
790+
log.info("\tStarted container: " + container.startContainer())
791+
assert !container.hasNeverBeenStarted(): "Error starting CMD container"
792+
793+
if (timeoutMs == 0) {
794+
log.info("\tNo Timeout set, returning container id")
795+
return [container.id]
796+
}
797+
798+
long start = System.currentTimeMillis()
799+
800+
while (start + timeoutMs > System.currentTimeMillis() && container.running) {
801+
802+
log.info("\tWaited ${System.currentTimeMillis() - start}ms for container to stop")
803+
sleep(1000)
804+
805+
}
806+
log.info("\tContainer finisehd or timed out after ${System.currentTimeMillis() - start}ms")
807+
808+
if (container.running) {
809+
log.info("\t"*2 + "Stopping container forcefully.")
810+
ArrayList<String> containerOut = container.containerLogs
811+
assert container.stopAndRemoveContainer(1): "Error stopping and removing CMD container after it timed out"
812+
813+
throw new TimeoutException("CMD container timed out, was forcefully stopped and removed. Container logs:" + containerOut?.join("\n"))
814+
}
815+
816+
817+
818+
ArrayList<String> containerOut = container.containerLogs
819+
820+
log.info("\tReturning ${containerOut.size()} log lines")
821+
822+
assert container.stopAndRemoveContainer(): "Error removing Container:" + container.id
823+
log.info("\tRemoved container:" + container.id)
824+
825+
return containerOut
826+
} catch (ex) {
827+
828+
829+
try {
830+
container.stopAndRemoveContainer(1)
831+
} catch (ignored){}
832+
833+
834+
835+
throw ex
836+
837+
}
838+
839+
715840
}
716841

717842

@@ -747,7 +872,7 @@ trait Container {
747872
*/
748873
void prepareCustomEnvVar(ArrayList<String> keyVar) {
749874

750-
assert hasNeverBeenStarted(): "Error, cant set custom enviromental variables after creating container"
875+
assert hasNeverBeenStarted(): "Error, cant set custom environment variables after creating container"
751876

752877
self.customEnvVar = keyVar
753878
}

src/main/groovy/com/eficode/devstack/container/impl/AlpineContainer.groovy

Lines changed: 0 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -34,110 +34,8 @@ class AlpineContainer implements Container {
3434
}
3535

3636

37-
/**
38-
* Creates an Alpine container, runs a command, exits and removes container
39-
* @param cmd A string that will be passed as a command to /bin/sh -c, ex: echo start;sleep 5
40-
* @param timeoutMs
41-
* 0 don't wait, return an array with the container ID immediately,
42-
* timeoutMs > 0 Wait for container to stop, if it takes longer than timeoutMs an exception will be thrown
43-
* @param mounts bind mounts that the container should have:
44-
* readOnly is optional and defaults to true
45-
* ex:[[src: "/tmp/engine/test", target: "/tmp/container/test", readOnly :true]
46-
* @param dockerHost
47-
* @param dockerCertPath
48-
* @return An array of the container logs, or just an array containing container id if timeoutMs == 0
49-
*/
50-
static ArrayList<String> runCmdAndRm(String cmd, long timeoutMs, ArrayList<Map> mounts = [:], String dockerHost = "", String dockerCertPath = "") {
51-
return runCmdAndRm(["/bin/sh", "-c", cmd], timeoutMs, mounts, dockerHost, dockerCertPath)
52-
}
53-
54-
/**
55-
* Creates an Alpine container, runs a command, exits and removes container
56-
* @param cmd An array of commands to run, ex: [ "/bin/sh", "-c", "echo start;sleep 5"]
57-
* @param timeoutMs
58-
* 0 don't wait, return an array with the container ID immediately,
59-
* timeoutMs > 0 Wait for container to stop, if it takes longer than timeoutMs an exception will be thrown
60-
* @param mounts bind mounts that the container should have:
61-
* readOnly is optional and defaults to true
62-
* ex:[[src: "/tmp/engine/test", target: "/tmp/container/test", readOnly :true]
63-
* @param dockerHost
64-
* @param dockerCertPath
65-
* @return An array of the container logs, or just an array containing container id if timeoutMs == 0
66-
*/
67-
static ArrayList<String> runCmdAndRm(ArrayList<String> cmd, long timeoutMs, ArrayList<Map> mounts = [:], String dockerHost = "", String dockerCertPath = "") {
68-
69-
Logger log = LoggerFactory.getLogger(AlpineContainer)
70-
71-
log.info("Running alpine command")
72-
log.info("\tCmd:" + cmd)
73-
AlpineContainer container = null
74-
75-
76-
try {
77-
container = new AlpineContainer(dockerHost, dockerCertPath)
78-
container.containerName = container.containerName + "-cmd-" + System.currentTimeMillis().toString()[-5..-1]
79-
80-
mounts.each {
81-
log.info("\tPreparing Bind mount:")
82-
container.prepareBindMount(it.src as String, it.target as String, it.containsKey("readOnly") ? it.readOnly as Boolean : true)
83-
}
84-
85-
86-
container.createContainer(cmd)
87-
log.info("\tCreated container: " + container.id)
88-
89-
90-
log.info("\tStarted container: " + container.startContainer())
91-
assert !container.hasNeverBeenStarted(): "Error starting Alpine container"
92-
93-
if (timeoutMs == 0) {
94-
log.info("\tNo Timeout set, returning container id")
95-
return [container.id]
96-
}
97-
98-
long start = System.currentTimeMillis()
99-
100-
while (start + timeoutMs > System.currentTimeMillis() && container.running) {
10137

102-
log.info("\tWaited ${System.currentTimeMillis() - start}ms for container to stop")
103-
sleep(1000)
10438

105-
}
106-
log.info("\tContainer finisehd or timed out after ${System.currentTimeMillis() - start}ms")
107-
108-
if (container.running) {
109-
log.info("\t"*2 + "Stopping container forcefully.")
110-
ArrayList<String> containerOut = container.containerLogs
111-
assert container.stopAndRemoveContainer(1): "Error stopping and removing Alpine container after it timed out"
112-
113-
throw new TimeoutException("Alpine container timed out, was forcefully stopped and removed. Container logs:" + containerOut?.join("\n"))
114-
}
115-
116-
117-
118-
ArrayList<String> containerOut = container.containerLogs
119-
120-
log.info("\tReturning ${containerOut.size()} log lines")
121-
122-
assert container.stopAndRemoveContainer(): "Error removing Container:" + container.id
123-
log.info("\tRemoved container:" + container.id)
124-
125-
return containerOut
126-
} catch (ex) {
127-
128-
129-
try {
130-
container.stopAndRemoveContainer(1)
131-
} catch (ignored){}
132-
133-
134-
135-
throw ex
136-
137-
}
138-
139-
140-
}
14139

14240

14341
}

0 commit comments

Comments
 (0)