diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/core/Utils.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/core/Utils.kt index ff06374..8093607 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/core/Utils.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/core/Utils.kt @@ -16,7 +16,7 @@ import java.net.InetAddress */ fun getCallingMethodName(): String? { val offsetVal = 1 - val exclude = arrayOf("def", "record", "invoke", "invoke0", "handle", "def\$default", "addResultToEval", "handle\$default") + val exclude = arrayOf("task", "def", "record", "invoke", "invoke0", "handle", "task\$default", "def\$default", "addResultToEval", "handle\$default") // suffixes are also ignored as method names but will be added as suffix in the evaluation results val suffixes = arrayOf("optional", "requireAll", "requireLast", "inContainer") @@ -45,15 +45,25 @@ fun String.escapeControlChars(): String = replace("\r", "\\r").replace("\n", "\\ fun String.escapeBackslash(): String = replace("\\", "\\\\") fun String.escapeDoubleQuote(): String = replace("\"", "\\\"") fun String.escapeSingleQuote(): String = replace("'", "\'") +fun String.escapeBacktick(): String = replace("`", "\\`") +fun String.escapeDollar(): String = replace("$", "\\$") fun String.escapeSingleQuoteForShell(): String = replace("'", "'\"'\"'") fun String.escapeProcentForPrintf(): String = replace("%", "%%") fun String.endingWithFileSeparator(): String = if (length > 0 && (last() != fileSeparatorChar())) this + fileSeparator() else this -// see https://www.shellscript.sh/escape.html fun String.escapeAndEncloseByDoubleQuoteForShell(): String { - return "\"" + this.escapeBackslash().replace("`", "\\`").escapeDoubleQuote().replace("$", "\\$") + "\"" + return "\"" + this.escapeForShell() + "\"" } +fun String.escapeForShell(): String { + // see https://www.shellscript.sh/escape.html + return this.escapeBackslash().escapeBacktick().escapeDoubleQuote().escapeDollar() +} +internal fun echoCommandForText(text: String): String { + return "echo -n ${text.escapeAndEncloseByDoubleQuoteForShell()}" +} + + fun fileSeparator(): String = File.separator fun fileSeparatorChar(): Char = File.separatorChar fun newline(): String = System.getProperty("line.separator") diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/extensions/server_software/k3s/K3s.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/extensions/server_software/k3s/K3s.kt index bce183d..4a817ba 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/extensions/server_software/k3s/K3s.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/extensions/server_software/k3s/K3s.kt @@ -2,7 +2,10 @@ package org.domaindrivenarchitecture.provs.extensions.server_software.k3s import org.domaindrivenarchitecture.provs.core.Prov import org.domaindrivenarchitecture.provs.core.ProvResult +import org.domaindrivenarchitecture.provs.core.echoCommandForText import org.domaindrivenarchitecture.provs.core.remote +import org.domaindrivenarchitecture.provs.extensions.server_software.k3s.apple.appleConfig +import org.domaindrivenarchitecture.provs.extensions.server_software.k3s.apple.checkAppleService import org.domaindrivenarchitecture.provs.ubuntu.install.base.aptInstall import org.domaindrivenarchitecture.provs.ubuntu.secret.secretSources.PromptSecretSource @@ -12,7 +15,7 @@ import org.domaindrivenarchitecture.provs.ubuntu.secret.secretSources.PromptSecr * If docker is true, then k3s will be installed with docker option and also docker will be installed (may conflict if docker is already existing). * If host is specified, then tls (if configured) also applies to host. */ -fun Prov.installK3sServer(docker: Boolean = false, host: String? = null) = def { +fun Prov.installK3sServer(docker: Boolean = false, host: String? = null) = task { val tls = host?.let { "INSTALL_K3S_EXEC=\"--tls-san ${it}\"" } ?: "" aptInstall("curl") if (!chk("k3s -version")) { @@ -31,25 +34,35 @@ fun Prov.installK3sServer(docker: Boolean = false, host: String? = null) = def { } -fun Prov.uninstallK3sServer() = def { +fun Prov.uninstallK3sServer() = task { cmd("sudo /usr/local/bin/k3s-uninstall.sh") } +fun Prov.applyConfig(configAsYaml: String) = task { + cmd(echoCommandForText(configAsYaml) + " | sudo k3s kubectl apply -f -") +} + + fun main() { - val host = "192.168.56.123" - val remoteUser = "remoteUsername" + val host = "192.168.56.141" + val remoteUser = "usr" val passwordK3sUser = PromptSecretSource("Enter Password").secret() remote(host, remoteUser, passwordK3sUser).def { +// local().task { - val result = installK3sServer() + installK3sServer() // print pods for information purpose println(cmd("sudo k3s kubectl get pods --all-namespaces").out) - // return result of installation - result + applyConfig(appleConfig()) + + // print pods for information purpose + println(cmd("sudo k3s kubectl get services").out) + + checkAppleService("sudo k3s kubectl") } } \ No newline at end of file diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/extensions/server_software/k3s/apple/Apple.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/extensions/server_software/k3s/apple/Apple.kt new file mode 100644 index 0000000..ec869c8 --- /dev/null +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/extensions/server_software/k3s/apple/Apple.kt @@ -0,0 +1,48 @@ +package org.domaindrivenarchitecture.provs.extensions.server_software.k3s.apple + +import org.domaindrivenarchitecture.provs.core.Prov +import org.domaindrivenarchitecture.provs.core.ProvResult + + +fun Prov.checkAppleService(kubeCtlCmd: String = "kubectl") = task { + val ip = cmd(kubeCtlCmd + " get svc apple-service -o jsonpath=\"{.spec.clusterIP}\"\n").out + val port = cmd(kubeCtlCmd + " get svc apple-service -o jsonpath=\"{.spec.ports[0].port}\"\n").out + if (ip == null || port == null) { + return@task ProvResult(false) + } + val apple = cmd("curl -m 30 $ip:$port").out + if ("apple" == apple) { + ProvResult(true) + } else { + ProvResult(false, err = "Apple service did not return \"apple\" but instead: " + apple) + } +} + + +fun appleConfig() = + """ +kind: Pod +apiVersion: v1 +metadata: + name: apple-app + labels: + app: apple +spec: + containers: + - name: apple-app + image: hashicorp/http-echo + args: + - "-text=apple" + +--- + +kind: Service +apiVersion: v1 +metadata: + name: apple-service +spec: + selector: + app: apple + ports: + - port: 5678 # Default port for image + """ diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/git/base/Git.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/git/base/Git.kt index 07ca8ec..d93bc8a 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/git/base/Git.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/git/base/Git.kt @@ -4,7 +4,7 @@ import org.domaindrivenarchitecture.provs.core.Prov import org.domaindrivenarchitecture.provs.core.ProvResult import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.* import org.domaindrivenarchitecture.provs.ubuntu.keys.base.isHostKnown -import org.domaindrivenarchitecture.provs.ubuntu.utils.printToShell +import org.domaindrivenarchitecture.provs.core.echoCommandForText import java.io.File val knownHostsFile = "~/.ssh/known_hosts" @@ -93,7 +93,7 @@ private fun Prov.trustHost(host: String, fingerprintsOfKeysToBeAdded: Set> $knownHostsFile") + cmd(echoCommandForText(actualKeys.get(indexOfKeyFound)) + " >> $knownHostsFile") } ProvResult(true) } diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/keys/base/Gpg.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/keys/base/Gpg.kt index 701ffd8..67b49c8 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/keys/base/Gpg.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/keys/base/Gpg.kt @@ -8,7 +8,7 @@ import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.createSecretFil import org.domaindrivenarchitecture.provs.ubuntu.filesystem.base.dirExists import org.domaindrivenarchitecture.provs.ubuntu.install.base.aptInstall import org.domaindrivenarchitecture.provs.ubuntu.keys.KeyPair -import org.domaindrivenarchitecture.provs.ubuntu.utils.printToShell +import org.domaindrivenarchitecture.provs.core.echoCommandForText /** @@ -69,6 +69,6 @@ private fun Prov.gpgKeysInstalled(fingerprint: String): Boolean { fun Prov.gpgFingerprint(pubKey: String): String? { val result = - cmdNoLog(" " + printToShell(pubKey) + " | gpg --with-colons --import-options show-only --import --fingerprint") + cmdNoLog(" " + echoCommandForText(pubKey) + " | gpg --with-colons --import-options show-only --import --fingerprint") return result.out?.let { """^fpr:*([A-Z0-9]*):$""".toRegex(RegexOption.MULTILINE).find(it)?.groupValues?.get(1) } } diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/utils/Utils.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/utils/Utils.kt deleted file mode 100644 index bad65f7..0000000 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/ubuntu/utils/Utils.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.domaindrivenarchitecture.provs.ubuntu.utils - -import org.domaindrivenarchitecture.provs.core.escapeBackslash -import org.domaindrivenarchitecture.provs.core.escapeDoubleQuote - - -// todo: investigate to use .escapeAndEncloseByDoubleQuoteForShell() or similar instead (?) -internal fun printToShell(text: String): String { - return "echo -n \"${text.escapeBackslash().escapeDoubleQuote()}\"" -} - diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/ubuntu/utils/UtilsKtTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/ubuntu/utils/UtilsKtTest.kt index 8c39d98..89e87cf 100644 --- a/src/test/kotlin/org/domaindrivenarchitecture/provs/ubuntu/utils/UtilsKtTest.kt +++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/ubuntu/utils/UtilsKtTest.kt @@ -1,6 +1,7 @@ package org.domaindrivenarchitecture.provs.ubuntu.utils import org.domaindrivenarchitecture.provs.core.Prov +import org.domaindrivenarchitecture.provs.core.echoCommandForText import org.domaindrivenarchitecture.provs.test.tags.ContainerTest import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @@ -14,8 +15,8 @@ internal class UtilsKtTest { val a = Prov.defaultInstance() // when - val testString = "test if newline \n and apostrophe's ' \" and special chars !§$%[]\\ äöüß are handled correctly" - val res = a.cmd(printToShell(testString)).out + val testString = "test if newline \n and apostrophe's ' \" and special chars !§$%[]\\ äöüß \$variable are handled correctly" + val res = a.cmd(echoCommandForText(testString)).out // then assertEquals(testString, res)