fix todos in class Prov & method names refactorings

This commit is contained in:
ansgarz 2022-03-12 18:41:07 +01:00
parent d8ff355893
commit 1836b9efdb
12 changed files with 73 additions and 65 deletions

View file

@ -1,6 +1,5 @@
package org.domaindrivenarchitecture.provs.framework.core package org.domaindrivenarchitecture.provs.framework.core
import org.domaindrivenarchitecture.provs.framework.core.platforms.SHELL
import org.domaindrivenarchitecture.provs.framework.core.platforms.UbuntuProv import org.domaindrivenarchitecture.provs.framework.core.platforms.UbuntuProv
import org.domaindrivenarchitecture.provs.framework.core.processors.LocalProcessor import org.domaindrivenarchitecture.provs.framework.core.processors.LocalProcessor
import org.domaindrivenarchitecture.provs.framework.core.processors.Processor import org.domaindrivenarchitecture.provs.framework.core.processors.Processor
@ -13,11 +12,13 @@ enum class OS { LINUX }
private const val RESULT_PREFIX = "> " private const val RESULT_PREFIX = "> "
private const val NOT_IMPLEMENTED = "Not implemented"
/** /**
* This main class offers methods to execute shell commands. * This main class offers methods to execute shell commands.
* The commands are executed locally, remotely (via ssh) or in a docker container * The commands are executed locally, remotely (via ssh) or in a docker container depending on
* depending on the processor which is passed to the constructor. * the processor which is passed to the constructor.
*/ */
open class Prov protected constructor( open class Prov protected constructor(
private val processor: Processor, private val processor: Processor,
@ -59,14 +60,12 @@ open class Prov protected constructor(
} }
} }
private val internalResults = arrayListOf<ResultLine>() private val internalResults = arrayListOf<ResultLine>()
private var level = 0 private var level = 0
private var previousLevel = 0 private var previousLevel = 0
private var exit = false private var exit = false
private var runInContainerWithName: String? = null private var runInContainerWithName: String? = null
/** /**
* Defines a task with a custom name instead of the name of the calling function. * Defines a task with a custom name instead of the name of the calling function.
* Returns success if all subtasks finished with success (same as requireAll). * Returns success if all subtasks finished with success (same as requireAll).
@ -111,21 +110,23 @@ open class Prov protected constructor(
return handle(ResultMode.FAILEXIT) { a() } return handle(ResultMode.FAILEXIT) { a() }
} }
// todo: add sudo and update test /**
fun inContainer(containerName: String, a: Prov.() -> ProvResult): ProvResult { * Runs the provided task in the specified (running) container
*/
fun taskInContainer(containerName: String, task: Prov.() -> ProvResult): ProvResult {
runInContainerWithName = containerName runInContainerWithName = containerName
val res = handle(ResultMode.ALL) { a() } val res = handle(ResultMode.ALL) { task() }
runInContainerWithName = null runInContainerWithName = null
return res return res
} }
/** /**
* execute program with parameters * Executes a program with (optional) parameters.
* args[0] contains the program name, the other args (if provided) specify the parameters.
*/ */
fun xec(vararg s: String): ProvResult { fun exec(vararg args: String): ProvResult {
val cmd = runInContainerWithName?.let { cmdInContainer(it, *s) } ?: s val cmd = runInContainerWithName?.let { execInContainer(it, *args) } ?: args
val result = processor.x(*cmd) val result = processor.exec(*cmd)
return ProvResult( return ProvResult(
success = (result.exitCode == 0), success = (result.exitCode == 0),
cmd = result.argsToString(), cmd = result.argsToString(),
@ -135,11 +136,12 @@ open class Prov protected constructor(
} }
/** /**
* execute program with parameters without logging (to be used if secrets are involved) * Executes a program with (optional) parameters without logging (e.g. to be used if secrets are involved)
* args[0] contains the program name, the other args (if provided) specify the parameters.
*/ */
fun xecNoLog(vararg s: String): ProvResult { fun execNoLog(vararg s: String): ProvResult {
val cmd = runInContainerWithName?.let { cmdInContainer(it, *s) } ?: s val cmd = runInContainerWithName?.let { execInContainer(it, *s) } ?: s
val result = processor.xNoLog(*cmd) val result = processor.execNoLog(*cmd)
return ProvResult( return ProvResult(
success = (result.exitCode == 0), success = (result.exitCode == 0),
cmd = "***", cmd = "***",
@ -148,8 +150,13 @@ open class Prov protected constructor(
) )
} }
/**
private val NOT_IMPLEMENTED = "Not implemented" * Executes a program with (optional) parameters in the specified container.
* args[0] contains the program name, the other args (if provided) specify the parameters.
*/
protected open fun execInContainer(containerName: String, vararg args: String): Array<String> {
throw Exception(NOT_IMPLEMENTED)
}
/** /**
* Executes a command by using the shell. * Executes a command by using the shell.
@ -233,23 +240,6 @@ open class Prov protected constructor(
ProvResult(success) ProvResult(success)
} }
// todo: put logic in subclasses, such as UbuntuProv
private fun cmdInContainer(containerName: String, vararg args: String): Array<String> {
return arrayOf(SHELL, "-c", "sudo docker exec $containerName " + buildCommand(*args))
}
private fun buildCommand(vararg args: String): String {
return if (args.size == 1)
args[0].escapeAndEncloseByDoubleQuoteForShell()
else
if (args.size == 3 && SHELL.equals(args[0]) && "-c".equals(args[1]))
SHELL + " -c " + args[2].escapeAndEncloseByDoubleQuoteForShell()
else
args.joinToString(separator = " ")
}
/** /**
* Provides result handling, e.g. gather results for result summary * Provides result handling, e.g. gather results for result summary
*/ */

View file

@ -76,7 +76,7 @@ fun UbuntuProv.dockerProvideImagePlatform(image: DockerImage, skipIfExisting: Bo
val path = hostUserHome() + "tmp_docker_img" + fileSeparator() val path = hostUserHome() + "tmp_docker_img" + fileSeparator()
if (!xec("test", "-d", path).success) { if (!exec("test", "-d", path).success) {
cmd("cd ${hostUserHome()} && mkdir tmp_docker_img") cmd("cd ${hostUserHome()} && mkdir tmp_docker_img")
} }

View file

@ -24,15 +24,29 @@ class UbuntuProv internal constructor(
} }
override fun cmd(cmd: String, dir: String?, sudo: Boolean): ProvResult = def { override fun cmd(cmd: String, dir: String?, sudo: Boolean): ProvResult = def {
xec(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo)) exec(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo))
} }
override fun cmdNoLog(cmd: String, dir: String?, sudo: Boolean): ProvResult { override fun cmdNoLog(cmd: String, dir: String?, sudo: Boolean): ProvResult {
return xecNoLog(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo)) return execNoLog(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo))
} }
override fun cmdNoEval(cmd: String, dir: String?, sudo: Boolean): ProvResult { override fun cmdNoEval(cmd: String, dir: String?, sudo: Boolean): ProvResult {
return xec(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo)) return exec(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo))
}
override fun execInContainer(containerName: String, vararg args: String): Array<String> {
return arrayOf(SHELL, "-c", "sudo docker exec $containerName " + buildCommand(*args))
}
private fun buildCommand(vararg args: String): String {
return if (args.size == 1)
args[0].escapeAndEncloseByDoubleQuoteForShell()
else
if (args.size == 3 && SHELL.equals(args[0]) && "-c".equals(args[1]))
SHELL + " -c " + args[2].escapeAndEncloseByDoubleQuoteForShell()
else
args.joinToString(separator = " ")
} }
} }

View file

@ -40,17 +40,17 @@ open class ContainerUbuntuHostProcessor(
private val hostShell = "/bin/bash" private val hostShell = "/bin/bash"
override fun x(vararg args: String): ProcessResult { override fun exec(vararg args: String): ProcessResult {
return localExecution.x(hostShell, "-c", dockerCmd + "exec $containerName " + buildCommand(*args)) return localExecution.exec(hostShell, "-c", dockerCmd + "exec $containerName " + buildCommand(*args))
} }
override fun xNoLog(vararg args: String): ProcessResult { override fun execNoLog(vararg args: String): ProcessResult {
return localExecution.xNoLog(hostShell, "-c", dockerCmd + "exec $containerName " + buildCommand(*args)) return localExecution.execNoLog(hostShell, "-c", dockerCmd + "exec $containerName " + buildCommand(*args))
} }
private fun exitAndRm() { private fun exitAndRm() {
localExecution.x(hostShell, "-c", dockerCmd + "stop $containerName") localExecution.exec(hostShell, "-c", dockerCmd + "stop $containerName")
localExecution.x(hostShell, "-c", dockerCmd + "rm $containerName") localExecution.exec(hostShell, "-c", dockerCmd + "rm $containerName")
} }
private fun quoteString(s: String): String { private fun quoteString(s: String): String {

View file

@ -3,12 +3,12 @@ package org.domaindrivenarchitecture.provs.framework.core.processors
class DummyProcessor : Processor { class DummyProcessor : Processor {
override fun x(vararg args: String): ProcessResult override fun exec(vararg args: String): ProcessResult
{ {
return ProcessResult(0, args = args) return ProcessResult(0, args = args)
} }
override fun xNoLog(vararg args: String): ProcessResult override fun execNoLog(vararg args: String): ProcessResult
{ {
return ProcessResult(0, args = args) return ProcessResult(0, args = args)
} }

View file

@ -29,12 +29,12 @@ open class LocalProcessor : Processor {
return System.getProperty("user.home") ?: File.separator return System.getProperty("user.home") ?: File.separator
} }
override fun x(vararg args: String): ProcessResult { override fun exec(vararg args: String): ProcessResult {
return execute(true, *args) return execute(true, *args)
} }
override fun xNoLog(vararg args: String): ProcessResult { override fun execNoLog(vararg args: String): ProcessResult {
return execute(false, *args) return execute(false, *args)
} }

View file

@ -4,7 +4,7 @@ package org.domaindrivenarchitecture.provs.framework.core.processors
@Suppress("unused") // used externally @Suppress("unused") // used externally
class PrintOnlyProcessor : Processor { class PrintOnlyProcessor : Processor {
override fun x(vararg args: String): ProcessResult override fun exec(vararg args: String): ProcessResult
{ {
print("PrintOnlyProcessor >>> ") print("PrintOnlyProcessor >>> ")
for (n in args) print("\"$n\" ") for (n in args) print("\"$n\" ")
@ -12,7 +12,7 @@ class PrintOnlyProcessor : Processor {
return ProcessResult(0, args = args) return ProcessResult(0, args = args)
} }
override fun xNoLog(vararg args: String): ProcessResult override fun execNoLog(vararg args: String): ProcessResult
{ {
print("PrintOnlyProcessor >>> ********") print("PrintOnlyProcessor >>> ********")
return ProcessResult(0, args = args) return ProcessResult(0, args = args)

View file

@ -2,8 +2,8 @@ package org.domaindrivenarchitecture.provs.framework.core.processors
interface Processor { interface Processor {
fun x(vararg args: String): ProcessResult fun exec(vararg args: String): ProcessResult
fun xNoLog(vararg args: String): ProcessResult fun execNoLog(vararg args: String): ProcessResult
fun close() { fun close() {
// no action needed for most processors; if action is needed when closing, this method must be overwritten in the subclass // no action needed for most processors; if action is needed when closing, this method must be overwritten in the subclass
} }

View file

@ -17,7 +17,11 @@ import java.net.InetAddress
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class RemoteProcessor(ip: InetAddress, user: String, password: Secret? = null) : Processor { /**
* Executes task on a remote machine.
* Attention: host key is currently not being verified
*/
class RemoteProcessor(host: InetAddress, user: String, password: Secret? = null) : Processor {
companion object { companion object {
@Suppress("JAVA_CLASS_ON_COMPANION") @Suppress("JAVA_CLASS_ON_COMPANION")
@ -28,13 +32,13 @@ class RemoteProcessor(ip: InetAddress, user: String, password: Secret? = null) :
init { init {
try { try {
log.info("Connecting to $ip with user: $user with " + if (password != null) "password" else "ssh-key") log.info("Connecting to $host with user: $user with " + if (password != null) "password" else "ssh-key")
ssh.loadKnownHosts() ssh.loadKnownHosts()
// todo: replace PromiscuousVerifier by more secure solution // Attention: host key is not verified
ssh.addHostKeyVerifier(PromiscuousVerifier()) ssh.addHostKeyVerifier(PromiscuousVerifier())
ssh.connect(ip) ssh.connect(host)
if (password != null) { if (password != null) {
ssh.authPassword(user, password.plain()) ssh.authPassword(user, password.plain())
@ -52,11 +56,11 @@ class RemoteProcessor(ip: InetAddress, user: String, password: Secret? = null) :
} }
} }
override fun x(vararg args: String): ProcessResult { override fun exec(vararg args: String): ProcessResult {
return execute(true, *args) return execute(true, *args)
} }
override fun xNoLog(vararg args: String): ProcessResult { override fun execNoLog(vararg args: String): ProcessResult {
return execute(false, *args) return execute(false, *args)
} }

View file

@ -477,7 +477,7 @@ internal class ProvTest {
// then // then
fun Prov.outer() = def { fun Prov.outer() = def {
inContainer(containerName) { taskInContainer(containerName) {
inner() inner()
cmd("echo testfile > testfile.txt") cmd("echo testfile > testfile.txt")
} }
@ -503,7 +503,7 @@ internal class ProvTest {
// then // then
val res = remote(host, remoteUser).def { val res = remote(host, remoteUser).def {
inner() // executed on the remote host inner() // executed on the remote host
inContainer("prov_default") { taskInContainer("prov_default") {
inner() // executed in the container on the remote host inner() // executed in the container on the remote host
} }
} }

View file

@ -69,8 +69,8 @@ internal class UbuntuProvTest {
val a = testLocal() val a = testLocal()
// when // when
val res1 = a.xec("/usr/bin/printf", "hi") val res1 = a.exec("/usr/bin/printf", "hi")
val res2 = a.xec("/bin/bash", "-c", "echo echoed") val res2 = a.exec("/bin/bash", "-c", "echo echoed")
// then // then
assert(res1.success) assert(res1.success)

View file

@ -18,7 +18,7 @@ class ContainerUbuntuHostProcessorTest {
ContainerUbuntuHostProcessor("provs_ubuntuhost_test", "ubuntu", DEFAULT_START_MODE_TEST_CONTAINER, sudo = testDockerWithSudo) ContainerUbuntuHostProcessor("provs_ubuntuhost_test", "ubuntu", DEFAULT_START_MODE_TEST_CONTAINER, sudo = testDockerWithSudo)
// when // when
val res = processor.x(SHELL, "-c", "echo -n abc") val res = processor.exec(SHELL, "-c", "echo -n abc")
// then // then
assertEquals(0, res.exitCode) assertEquals(0, res.exitCode)