You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
3.9 KiB
Kotlin
128 lines
3.9 KiB
Kotlin
3 years ago
|
package io.provs.processors
|
||
|
|
||
|
import io.provs.Secret
|
||
|
import io.provs.escapeAndEncloseByDoubleQuoteForShell
|
||
|
import io.provs.escapeNewline
|
||
|
import io.provs.platforms.SHELL
|
||
|
import net.schmizz.sshj.SSHClient
|
||
|
import net.schmizz.sshj.connection.channel.direct.Session
|
||
|
import net.schmizz.sshj.connection.channel.direct.Session.Command
|
||
|
import net.schmizz.sshj.transport.verification.PromiscuousVerifier
|
||
|
import org.slf4j.LoggerFactory
|
||
|
import java.io.BufferedReader
|
||
|
import java.io.File
|
||
|
import java.io.IOException
|
||
|
import java.io.InputStreamReader
|
||
|
import java.util.concurrent.TimeUnit
|
||
|
|
||
|
|
||
|
class RemoteProcessor(ip: String, user: String, password: Secret? = null) : Processor {
|
||
|
|
||
|
companion object {
|
||
|
@Suppress("JAVA_CLASS_ON_COMPANION")
|
||
|
private val log = LoggerFactory.getLogger(javaClass.enclosingClass)
|
||
|
}
|
||
|
|
||
|
private val ssh = SSHClient()
|
||
|
|
||
|
init {
|
||
|
try {
|
||
|
log.info("Connecting to $ip with user: $user with " + if (password != null) "password" else "ssh-key")
|
||
|
|
||
|
ssh.loadKnownHosts()
|
||
|
|
||
|
// todo: replace PromiscuousVerifier by more secure solution
|
||
|
ssh.addHostKeyVerifier(PromiscuousVerifier())
|
||
|
ssh.connect(ip)
|
||
|
|
||
|
if (password != null) {
|
||
|
ssh.authPassword(user, password.plain())
|
||
|
} else {
|
||
|
val base = System.getProperty("user.home") + File.separator + ".ssh" + File.separator
|
||
|
ssh.authPublickey(user, base + "id_rsa", base + "id_dsa", base + "id_ed25519", base + "id_ecdsa")
|
||
|
}
|
||
|
} catch (e: Exception) {
|
||
|
try {
|
||
|
ssh.disconnect()
|
||
|
} finally {
|
||
|
log.error("Got exception when initializing ssh: " + e.message)
|
||
|
throw RuntimeException("Error when initializing ssh", e)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
override fun x(vararg args: String): ProcessResult {
|
||
|
return execute(true, *args)
|
||
|
}
|
||
|
|
||
|
override fun xNoLog(vararg args: String): ProcessResult {
|
||
|
return execute(false, *args)
|
||
|
}
|
||
|
|
||
|
private fun execute(logging: Boolean, vararg args: String): ProcessResult {
|
||
|
var prefix = "******************** Prov: "
|
||
|
if (logging) {
|
||
|
for (arg in args) {
|
||
|
prefix += " \"${arg.escapeNewline()}\""
|
||
|
}
|
||
|
} else {
|
||
|
prefix += "\"xxxxxxxx\""
|
||
|
}
|
||
|
log.info(prefix)
|
||
|
|
||
|
val cmdString: String =
|
||
|
if (args.size == 1)
|
||
|
args[0].escapeAndEncloseByDoubleQuoteForShell()
|
||
|
else
|
||
|
if (args.size == 3 && SHELL == args[0] && "-c" == args[1])
|
||
|
SHELL + " -c " + args[2].escapeAndEncloseByDoubleQuoteForShell()
|
||
|
else
|
||
|
args.joinToString(separator = " ")
|
||
|
|
||
|
|
||
|
var session: Session? = null
|
||
|
|
||
|
try {
|
||
|
session = ssh.startSession()
|
||
|
|
||
|
val cmd: Command = session!!.exec(cmdString)
|
||
|
val out = BufferedReader(InputStreamReader(cmd.inputStream)).use { it.readText() }
|
||
|
val err = BufferedReader(InputStreamReader(cmd.errorStream)).use { it.readText() }
|
||
|
cmd.join(100, TimeUnit.SECONDS)
|
||
|
|
||
|
val cmdRes = ProcessResult(cmd.exitStatus, out, err, args = args)
|
||
|
if (logging) {
|
||
|
log.info(cmdRes.toString())
|
||
|
}
|
||
|
session.close()
|
||
|
|
||
|
return cmdRes
|
||
|
|
||
|
} catch (e: Exception) {
|
||
|
try {
|
||
|
session?.close()
|
||
|
} finally {
|
||
|
// nothing to do
|
||
|
}
|
||
|
return ProcessResult(
|
||
|
-1,
|
||
|
err = "Error when opening or executing remote ssh session (Pls check host, user, password resp. ssh key) - ",
|
||
|
ex = e
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
override fun close() {
|
||
|
try {
|
||
|
log.info("Disconnecting ssh.")
|
||
|
ssh.disconnect()
|
||
|
} catch (e: IOException) {
|
||
|
// No prov required
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected fun finalize() {
|
||
|
close()
|
||
|
}
|
||
|
}
|