add server jar for k3s
This commit is contained in:
parent
6c906118cf
commit
b3bdc26e3f
6 changed files with 262 additions and 27 deletions
17
build.gradle
17
build.gradle
|
@ -101,6 +101,23 @@ task fatJarLatest(type: Jar) {
|
||||||
archiveFileName = 'provs.jar'
|
archiveFileName = 'provs.jar'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task fatJarK3s(type: Jar) {
|
||||||
|
from {
|
||||||
|
configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) }
|
||||||
|
}
|
||||||
|
exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA'
|
||||||
|
|
||||||
|
duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
|
||||||
|
|
||||||
|
manifest {
|
||||||
|
attributes 'Implementation-Title': 'Fatjar of provs k3s',
|
||||||
|
'Implementation-Version': project.version,
|
||||||
|
'Main-Class': 'org.domaindrivenarchitecture.provs.extensions.server_software.k3s.application.CliKt'
|
||||||
|
}
|
||||||
|
with jar
|
||||||
|
archiveFileName = 'provs-server.jar'
|
||||||
|
}
|
||||||
|
|
||||||
task uberjarWorkplace(type: Jar) {
|
task uberjarWorkplace(type: Jar) {
|
||||||
|
|
||||||
from sourceSets.main.output
|
from sourceSets.main.output
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
package org.domaindrivenarchitecture.provs.core.cli
|
||||||
|
|
||||||
|
import kotlinx.cli.ArgParser
|
||||||
|
import kotlinx.cli.ArgType
|
||||||
|
import kotlinx.cli.default
|
||||||
|
import org.domaindrivenarchitecture.provs.core.Prov
|
||||||
|
import org.domaindrivenarchitecture.provs.core.Secret
|
||||||
|
import org.domaindrivenarchitecture.provs.core.local
|
||||||
|
import org.domaindrivenarchitecture.provs.core.remote
|
||||||
|
import org.domaindrivenarchitecture.provs.ubuntu.secret.secretSources.GopassSecretSource
|
||||||
|
import org.domaindrivenarchitecture.provs.ubuntu.secret.secretSources.PromptSecretSource
|
||||||
|
import org.domaindrivenarchitecture.provs.ubuntu.user.base.currentUserCanSudo
|
||||||
|
import org.domaindrivenarchitecture.provs.ubuntu.user.base.makeUserSudoerWithNoSudoPasswordRequired
|
||||||
|
import org.domaindrivenarchitecture.provs.ubuntu.user.base.whoami
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
|
||||||
|
class CliCommand(
|
||||||
|
val localHost: Boolean?,
|
||||||
|
val remoteHost: String?,
|
||||||
|
val userName: String?,
|
||||||
|
val sshWithPasswordPrompt: Boolean,
|
||||||
|
val sshWithGopassPath: String?,
|
||||||
|
val sshWithKey: Boolean
|
||||||
|
) {
|
||||||
|
fun isValidLocalhost(): Boolean {
|
||||||
|
return (localHost ?: false) && remoteHost == null && userName == null && sshWithGopassPath == null &&
|
||||||
|
!sshWithPasswordPrompt && !sshWithKey
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasValidPasswordOption(): Boolean {
|
||||||
|
return (sshWithGopassPath != null) xor sshWithPasswordPrompt xor sshWithKey
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isValidRemote(): Boolean {
|
||||||
|
return remoteHost != null && userName != null && hasValidPasswordOption()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isValid(): Boolean {
|
||||||
|
return (isValidLocalhost() || isValidRemote())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseCli(
|
||||||
|
programName: String = "java -jar provs.jar",
|
||||||
|
args: Array<String>
|
||||||
|
): CliCommand {
|
||||||
|
val parser = ArgParser(programName)
|
||||||
|
|
||||||
|
val remoteHost by parser.option(
|
||||||
|
ArgType.String, shortName =
|
||||||
|
"r", description = "provision to remote host - either localHost or remoteHost must be specified"
|
||||||
|
)
|
||||||
|
val localHost by parser.option(
|
||||||
|
ArgType.Boolean, shortName =
|
||||||
|
"l", description = "provision to local machine - either localHost or remoteHost must be specified"
|
||||||
|
)
|
||||||
|
val userName by parser.option(
|
||||||
|
ArgType.String,
|
||||||
|
shortName = "u",
|
||||||
|
description = "user for remote provisioning."
|
||||||
|
)
|
||||||
|
val sshWithGopassPath by parser.option(
|
||||||
|
ArgType.String,
|
||||||
|
shortName = "p",
|
||||||
|
description = "password stored at gopass path"
|
||||||
|
)
|
||||||
|
val sshWithPasswordPrompt by parser.option(
|
||||||
|
ArgType.Boolean,
|
||||||
|
shortName = "i",
|
||||||
|
description = "prompt for password interactive"
|
||||||
|
).default(false)
|
||||||
|
val sshWithKey by parser.option(
|
||||||
|
ArgType.Boolean,
|
||||||
|
shortName = "k",
|
||||||
|
description = "provision over ssh using user & ssh key"
|
||||||
|
).default(false)
|
||||||
|
parser.parse(args)
|
||||||
|
|
||||||
|
return CliCommand(
|
||||||
|
localHost, remoteHost, userName, sshWithPasswordPrompt, sshWithGopassPath, sshWithKey
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal fun createProvInstance(
|
||||||
|
cliCommand: CliCommand,
|
||||||
|
remoteHostSetSudoWithoutPasswordRequired: Boolean = false
|
||||||
|
): Prov {
|
||||||
|
if (cliCommand.isValid()) {
|
||||||
|
val password: Secret? = if (cliCommand.isValidRemote()) retrievePassword(cliCommand) else null
|
||||||
|
|
||||||
|
if (cliCommand.isValidLocalhost()) {
|
||||||
|
return local()
|
||||||
|
} else if (cliCommand.isValidRemote()) {
|
||||||
|
val host = cliCommand.remoteHost!!
|
||||||
|
val remoteUser = cliCommand.userName!!
|
||||||
|
|
||||||
|
val prov =
|
||||||
|
if (cliCommand.sshWithKey) {
|
||||||
|
remote(host, remoteUser)
|
||||||
|
} else {
|
||||||
|
require(
|
||||||
|
password != null,
|
||||||
|
{ "No password available for provisioning without ssh keys. Either specify provisioning by ssh-keys or provide password." })
|
||||||
|
remote(host, remoteUser, password)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prov.currentUserCanSudo()) {
|
||||||
|
if (remoteHostSetSudoWithoutPasswordRequired) {
|
||||||
|
require(
|
||||||
|
password != null,
|
||||||
|
{ "User ${prov.whoami()} not able to sudo on remote machine without password and no password available for the user." })
|
||||||
|
prov.makeUserSudoerWithNoSudoPasswordRequired(password)
|
||||||
|
} else {
|
||||||
|
throw IllegalStateException("User ${prov.whoami()} not able to sudo on remote machine without password and option not set to enable user to sudo without password.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prov
|
||||||
|
} else {
|
||||||
|
throw IllegalArgumentException("Error: neither a valid localHost nor a valid remoteHost was specified! Use option -h for help.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println("Invalid command line options.\nPlease use option -h for help.")
|
||||||
|
exitProcess(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun retrievePassword(cliCommand: CliCommand): Secret? {
|
||||||
|
var password: Secret? = null
|
||||||
|
if (cliCommand.isValidRemote()) {
|
||||||
|
if (cliCommand.sshWithPasswordPrompt) {
|
||||||
|
password =
|
||||||
|
PromptSecretSource("Password for user $cliCommand.userName!! on $cliCommand.remoteHost!!").secret()
|
||||||
|
} else if (cliCommand.sshWithGopassPath != null) {
|
||||||
|
password = GopassSecretSource(cliCommand.sshWithGopassPath).secret()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return password
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.domaindrivenarchitecture.provs.extensions.server_software.k3s.application
|
||||||
|
|
||||||
|
import org.domaindrivenarchitecture.provs.core.Prov
|
||||||
|
import org.domaindrivenarchitecture.provs.extensions.server_software.k3s.installK3sServer
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs use case of provisioning a k3s server
|
||||||
|
*/
|
||||||
|
fun Prov.provisionK3s() = task {
|
||||||
|
installK3sServer()
|
||||||
|
}
|
||||||
|
|
|
@ -1,31 +1,17 @@
|
||||||
import org.domaindrivenarchitecture.provs.core.remote
|
package org.domaindrivenarchitecture.provs.extensions.server_software.k3s.application
|
||||||
import org.domaindrivenarchitecture.provs.extensions.server_software.k3s.applyK3sConfig
|
|
||||||
import org.domaindrivenarchitecture.provs.extensions.server_software.k3s.infrastructure.apple.appleConfig
|
|
||||||
import org.domaindrivenarchitecture.provs.extensions.server_software.k3s.infrastructure.apple.checkAppleService
|
|
||||||
import org.domaindrivenarchitecture.provs.extensions.server_software.k3s.installK3sServer
|
|
||||||
import org.domaindrivenarchitecture.provs.ubuntu.secret.secretSources.PromptSecretSource
|
|
||||||
|
|
||||||
fun main() {
|
import org.domaindrivenarchitecture.provs.core.cli.createProvInstance
|
||||||
|
import org.domaindrivenarchitecture.provs.core.cli.parseCli
|
||||||
|
|
||||||
val host = "192.168.56.141"
|
|
||||||
val remoteUser = "usr"
|
|
||||||
val passwordK3sUser = PromptSecretSource("Enter Password").secret()
|
|
||||||
|
|
||||||
val prov = remote(host, remoteUser, passwordK3sUser)
|
/**
|
||||||
// alternatively run local: val prov = local()
|
* Provisions a k3s server, either locally or on a remote machine depending on the given arguments.
|
||||||
|
*
|
||||||
|
* Get help with option -h
|
||||||
|
*/
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val cmd = parseCli("java -jar provs-server.jar", args)
|
||||||
|
val prov = createProvInstance(cmd)
|
||||||
|
|
||||||
prov.task {
|
prov.provisionK3s()
|
||||||
|
|
||||||
installK3sServer()
|
|
||||||
|
|
||||||
// print pods for information purpose
|
|
||||||
println(cmd("sudo k3s kubectl get pods --all-namespaces").out)
|
|
||||||
|
|
||||||
applyK3sConfig(appleConfig())
|
|
||||||
|
|
||||||
// print pods for information purpose
|
|
||||||
println(cmd("sudo k3s kubectl get services").out)
|
|
||||||
|
|
||||||
checkAppleService()
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package org.domaindrivenarchitecture.provs.core.cli
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions.*
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
internal class CliCommandTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun parse_localhost_with_default() {
|
||||||
|
val parseCli = parseCli(args = emptyArray())
|
||||||
|
|
||||||
|
assertFalse(parseCli.isValidLocalhost())
|
||||||
|
assertFalse(parseCli.isValidRemote())
|
||||||
|
assertFalse(parseCli.isValid())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun parse_localhost() {
|
||||||
|
val parseCli = parseCli(args = arrayOf("-l"))
|
||||||
|
assertTrue(parseCli.isValidLocalhost())
|
||||||
|
assertFalse(parseCli.isValidRemote())
|
||||||
|
assertTrue(parseCli.isValid())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun parse_remote_with_missing_passwordoption() {
|
||||||
|
val parseCli = parseCli(args = arrayOf("-r", "1.2.3.4", "-u", "user"))
|
||||||
|
|
||||||
|
assertFalse(parseCli.isValidLocalhost())
|
||||||
|
assertEquals("1.2.3.4", parseCli.remoteHost)
|
||||||
|
assertEquals("user", parseCli.userName)
|
||||||
|
assertFalse(parseCli.isValidRemote())
|
||||||
|
assertFalse(parseCli.isValid())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun parse_remote_with_remote_key() {
|
||||||
|
val parseCli = parseCli(args = arrayOf("-r", "1.2.3.4", "-u", "user", "-k"))
|
||||||
|
|
||||||
|
assertFalse(parseCli.isValidLocalhost())
|
||||||
|
assertEquals("1.2.3.4", parseCli.remoteHost)
|
||||||
|
assertEquals("user", parseCli.userName)
|
||||||
|
assertTrue(parseCli.isValid())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun parse_remote_with_remote_password_prompt() {
|
||||||
|
val parseCli = parseCli(args = arrayOf("-r", "1.2.3.4", "-u", "user", "-i"))
|
||||||
|
|
||||||
|
assertEquals("1.2.3.4", parseCli.remoteHost)
|
||||||
|
assertEquals("user", parseCli.userName)
|
||||||
|
assertTrue(parseCli.isValid())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun parse_remote_with_remote_password_gopass_path() {
|
||||||
|
val parseCli = parseCli(args = arrayOf("-r", "1.2.3.4", "-u", "user", "-p", "gopass/path"))
|
||||||
|
|
||||||
|
assertEquals("1.2.3.4", parseCli.remoteHost)
|
||||||
|
assertEquals("user", parseCli.userName)
|
||||||
|
assertEquals("gopass/path", parseCli.sshWithGopassPath)
|
||||||
|
assertTrue(parseCli.isValid())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.domaindrivenarchitecture.provs.extensions.server_software.k3s.application
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Disabled
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
internal class CliKtTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled // run manually -- todo mock execution
|
||||||
|
fun provision_remotely() {
|
||||||
|
|
||||||
|
main(arrayOf("-r", "192.168.56.141", "-u", "user", "-i"))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue