API de SSH
Los helpers para conexión SSH, ejecución remota y transferencia de archivos están disponibles bajo ptool.ssh y p.ssh.
ptool.ssh.connect
v0.1.0- Introduced.
ptool.ssh.connect(target_or_options) prepara un manejador de conexión SSH respaldado por el comando ssh del sistema y devuelve un objeto Connection.
ssh debe estar disponible en PATH.
Argumentos:
target_or_options(string|table, obligatorio):- Cuando se proporciona una cadena, se trata como un destino SSH.
- Cuando se proporciona una tabla, actualmente admite:
target(string, opcional): Cadena de destino SSH, como"[email protected]"o"[email protected]:2222".host(string, opcional): Nombre de host o dirección IP.user(string, opcional): Nombre de usuario SSH. Por defecto usa$USER, o"root"si$USERno está disponible.port(integer, opcional): Puerto SSH. Por defecto es22.auth(table, opcional): Configuración de autenticación.host_key(table, opcional): Configuración de verificación de clave de host.connect_timeout_ms(integer, opcional): Timeout en milisegundos. Por defecto es10000.keepalive_interval_ms(integer, opcional): Intervalo de keepalive en milisegundos.
Ejemplos de cadenas de destino admitidas:
local a = ptool.ssh.connect("[email protected]")
local b = ptool.ssh.connect("[email protected]:2222")
local c = ptool.ssh.connect("[2001:db8::10]:2222")
Campos de auth:
private_key_file(string, opcional): Ruta a un archivo de clave privada.private_key_passphrase(string, opcional): Frase de contraseña de la clave privada. Actualmente no es compatible.password(string, opcional): Autenticación basada en contraseña. Actualmente no es compatible.
Comportamiento de autenticación:
- Si se proporciona
auth.private_key_file,ptoolinvocasshcon esa clave mediante-iy también estableceIdentitiesOnly=yes. - Si se proporciona
auth.private_key_passphraseoauth.password,ptool.ssh.connect(...)falla porque esta API no pasa esos secretos al comandosshdel sistema. - En caso contrario, la autenticación se delega a la configuración local de OpenSSH, incluidas opciones y mecanismos como
IdentityFile,ProxyJump,ProxyCommand,ssh-agenty certificados. - Las rutas de clave relativas se resuelven desde el directorio de runtime actual de
ptool, por lo que siguenptool.cd(...). ~y~/...se expanden en las rutas de clave.
Campos de host_key:
verify(string, opcional): Modo de verificación de la clave de host. Valores admitidos:"known_hosts": Verifica contra un archivoknown_hosts(predeterminado)."ignore": Omite la verificación de la clave de host.
known_hosts_file(string, opcional): Ruta a un archivoknown_hosts. Solo se usa cuandoverify = "known_hosts".
Comportamiento de clave de host:
- Si
verify = "ignore",ptoolinvocasshconStrictHostKeyChecking=noyUserKnownHostsFile=/dev/null. - Si
verify = "known_hosts"y se proporcionaknown_hosts_file,ptoolinvocasshconStrictHostKeyChecking=yesy eseUserKnownHostsFile. - Si
verify = "known_hosts"y se omiteknown_hosts_file, o sihost_keyse omite por completo, el manejo de la clave de host se delega a la configuración local de OpenSSH y a sus valores predeterminados. - Las rutas relativas de
known_hosts_filese resuelven desde el directorio de runtime actual deptool. ~y~/...se expanden enknown_hosts_file.- Cuando
known_hosts_filese proporciona explícitamente, reemplaza el valor predeterminado deUserKnownHostsFileque usa el comandosshlocal para esta conexión.
Ejemplo:
local ssh = ptool.ssh.connect({
host = "example.com",
user = "deploy",
port = 22,
auth = {
private_key_file = "~/.ssh/id_ed25519",
},
host_key = {
verify = "known_hosts",
},
})
Connection
v0.1.0- Introduced.
Connection representa un manejador de conexión respaldado por OpenSSH devuelto por ptool.ssh.connect().
Está implementado como un userdata de Lua.
Campos y métodos:
- Campos:
conn.host(string)conn.user(string)conn.port(integer)conn.target(string)
- Métodos:
conn:run(...)->tableconn:run_capture(...)->tableconn:http_request(options)->Responseconn:path(path)->RemotePathconn:exists(path)->booleanconn:is_file(path)->booleanconn:is_dir(path)->booleanconn:upload(local_path, remote_path[, options])->tableconn:download(remote_path, local_path[, options])->tableconn:close()->nil
run
v0.1.0- Introduced.
Canonical API name: ptool.ssh.Connection:run.
conn:run(...) ejecuta un comando remoto a través de la conexión SSH actual.
Se admiten las siguientes formas de llamada:
conn:run("hostname")
conn:run("echo", "hello world")
conn:run("echo", {"hello", "world"})
conn:run("hostname", { stdout = "capture" })
conn:run("echo", {"hello", "world"}, { stdout = "capture" })
conn:run({ cmd = "git", args = {"rev-parse", "HEAD"} })
Reglas de argumentos:
conn:run(cmdline):cmdlinese envía como la cadena de comando remoto.conn:run(cmd, argsline):cmdse trata como el comando, yargslinese divide usando reglas de estilo shell (shlex).conn:run(cmd, args):cmdes una cadena yargses un arreglo de cadenas. Los argumentos se escapan para shell antes de la ejecución remota.conn:run(cmdline, options):optionssobrescribe esta invocación.conn:run(cmd, args, options):optionssobrescribe esta invocación.conn:run(options):optionses una tabla.- Cuando el segundo argumento es una tabla: si es un arreglo (claves enteras consecutivas
1..n), se trata comoargs; en caso contrario se trata comooptions.
Cuando se usa conn:run(options), options actualmente admite:
cmd(string, obligatorio): Nombre del comando o ruta del ejecutable.args(string[], opcional): Lista de argumentos.cwd(string, opcional): Directorio de trabajo remoto. Se aplica anteponiendocd ... &&al comando shell remoto generado.env(table, opcional): Variables de entorno remotas, donde claves y valores son cadenas. Se aplica anteponiendoexport ... &&al comando shell remoto generado.stdin(string, optional): String sent to the remote process stdin.trim(boolean, optional): Whether to trim leading and trailing whitespace from capturedstdoutand capturedstderrbefore returning them. This only affects streams set to"capture". Defaults tofalse.echo(boolean, optional): Whether to echo the remote command before execution. Defaults totrue.check(boolean, optional): Whether to raise an error immediately when the exit status is not0. Defaults tofalse.stdout(string, optional): Stdout handling strategy. Supported values:"inherit": Hereda el terminal actual (predeterminado)."capture": Capture intores.stdout."null": Descarta la salida.
stderr(string, optional): Stderr handling strategy. Supported values:"inherit": Hereda el terminal actual (predeterminado)."capture": Capture intores.stderr."null": Descarta la salida.
Cuando se usan las formas abreviadas, la tabla options solo admite:
stdin(string, optional): String sent to the remote process stdin.trim(boolean, optional): Whether to trim leading and trailing whitespace from capturedstdoutand capturedstderrbefore returning them. This only affects streams set to"capture". Defaults tofalse.echo(boolean, optional): Whether to echo the remote command before execution. Defaults totrue.check(boolean, optional): Whether to raise an error immediately when the exit status is not0. Defaults tofalse.stdout(string, optional): Stdout handling strategy. Supported values:"inherit": Hereda el terminal actual (predeterminado)."capture": Capture intores.stdout."null": Descarta la salida.
stderr(string, optional): Stderr handling strategy. Supported values:"inherit": Hereda el terminal actual (predeterminado)."capture": Capture intores.stderr."null": Descarta la salida.
Reglas del valor de retorno:
- Siempre se devuelve una tabla con los siguientes campos:
ok(boolean): Si el código de salida remoto es0.code(integer|nil): Código de salida remoto. Si el proceso remoto termina por señal, este valor esnil.target(string): Cadena de destino SSH con el formatouser@host:port.stdout(string, opcional): Presente cuandostdout = "capture".stderr(string, opcional): Presente cuandostderr = "capture".assert_ok(self)(function): Lanza un error cuandook = false.
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
local res = ssh:run("uname -a", { stdout = "capture" })
print(res.target)
print(res.stdout)
local res2 = ssh:run({
cmd = "git",
args = {"rev-parse", "HEAD"},
cwd = "/srv/app",
env = {
FOO = "bar",
},
trim = true,
stdout = "capture",
check = true,
})
print(res2.stdout)
run_capture
Unreleased- Introduced.
Canonical API name: ptool.ssh.Connection:run_capture.
conn:run_capture(...) ejecuta un comando remoto a través de la conexión SSH actual.
Acepta las mismas formas de llamada, reglas de argumentos, reglas del valor de retorno y opciones que conn:run(...).
La única diferencia es el manejo predeterminado de flujos:
stdoutusa"capture"por defecto.stderrusa"capture"por defecto.
trim todavía tiene como valor predeterminado false y aún puede anular cualquiera de estos campos explícitamente en options.
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
local res = ssh:run_capture("uname -a", { trim = true })
print(res.stdout)
local res2 = ssh:run_capture({
cmd = "sh",
args = {"-c", "printf 'out'; printf 'err' >&2"},
cwd = "/srv/app",
})
print(res2.stdout)
print(res2.stderr)
local res3 = ssh:run_capture("echo hello", {
stderr = "inherit",
})
print(res3.stdout)
http_request
Unreleased- Introduced.
Canonical API name: ptool.ssh.Connection:http_request.
conn:http_request(options) envía una solicitud HTTP desde el host SSH remoto y devuelve el mismo tipo de objeto Response que ptool.http.request(...).
options admite los mismos campos y las mismas reglas de validación que ptool.http.request(options).
Esto es útil cuando solo se puede acceder al endpoint de destino desde el host remoto, por ejemplo, un servicio vinculado a 127.0.0.1, una dirección de VPC privada o un endpoint de metadatos.
Notas:
- La solicitud se ejecuta en el host remoto, por lo que la resolución DNS, el acceso de red saliente, la configuración de proxy, la confianza TLS y las reglas del firewall provienen de ese host y no de la máquina local.
- El host remoto debe tener
curldisponible enPATH. - Los cuerpos de solicitud se envían al proceso remoto
curla través de SSH. - Los encabezados y el cuerpo de la respuesta se transmiten de vuelta por SSH y luego se consumen mediante los métodos normales de
Responsedocumentados en la API HTTP. basic_authybearer_tokensiguen siendo mutuamente excluyentes.fail_on_http_error, el manejo de redirecciones, el manejo de tiempos de espera y el almacenamiento en caché del cuerpo de la respuesta se comportan igual que enptool.http.request(...).
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
local resp = ssh:http_request({
url = "http://127.0.0.1:8080/health",
headers = {
accept = "application/json",
},
timeout_ms = 5000,
fail_on_http_error = true,
})
local data = resp:json()
print(resp.status)
print(data.status)
path
v0.1.0- Introduced.
Canonical API name: ptool.ssh.Connection:path.
conn:path(path) crea un objeto RemotePath reutilizable vinculado a la conexión SSH actual.
path(string, obligatorio): La ruta remota.- Devuelve: Un objeto
RemotePathque puede pasarse aconn:upload(...),conn:download(...)yptool.fs.copy(...).
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
local remote_release = ssh:path("/srv/app/releases/current.tar.gz")
ssh:download(remote_release, "./tmp/current.tar.gz")
exists
v0.2.0- Introduced.
Canonical API name: ptool.ssh.Connection:exists.
conn:exists(path) comprueba si existe una ruta remota.
path(string|remote path, required): The remote path to check. It can be a string or a value created byconn:path(...).- Returns:
truewhen the remote path exists, otherwisefalse.
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
print(ssh:exists("/srv/app"))
print(ssh:path("/srv/app/releases/current.tar.gz"):exists())
is_file
v0.2.0- Introduced.
Canonical API name: ptool.ssh.Connection:is_file.
conn:is_file(path) comprueba si una ruta remota existe y es un archivo regular.
path(string|remote path, required): The remote path to check. It can be a string or a value created byconn:path(...).- Returns:
truewhen the remote path is a file, otherwisefalse.
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
local remote_tarball = ssh:path("/srv/app/releases/current.tar.gz")
if ssh:is_file(remote_tarball) then
print("release tarball exists")
end
is_dir
v0.2.0- Introduced.
Canonical API name: ptool.ssh.Connection:is_dir.
conn:is_dir(path) comprueba si una ruta remota existe y es un directorio.
path(string|remote path, required): The remote path to check. It can be a string or a value created byconn:path(...).- Returns:
truewhen the remote path is a directory, otherwisefalse.
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
local releases = ssh:path("/srv/app/releases")
if releases:is_dir() then
print("releases directory is ready")
end
upload
v0.1.0- Introduced.
Canonical API name: ptool.ssh.Connection:upload.
conn:upload(local_path, remote_path[, options]) sube un archivo o directorio local al host remoto.
local_path(string, obligatorio): El archivo o directorio local que se va a subir.remote_path(string|remote path, obligatorio): La ruta de destino en el host remoto. Puede ser una cadena o un valor creado porconn:path(...).options(table, optional): Transfer options.- Returns: A table with the following fields:
bytes(integer): El número de bytes de archivos regulares subidos. Cuando se sube un directorio, es la suma de los tamaños de los archivos subidos.from(string): La ruta local de origen.to(string): La ruta remota de destino.
Supported transfer options:
parents(boolean, opcional): Crea el directorio padre deremote_pathantes de subir. Por defecto esfalse.overwrite(boolean, optional): Whether an existing destination file may be replaced. Defaults totrue.echo(boolean, optional): Whether to print the transfer before executing it. Defaults tofalse.
Directory behavior:
- Cuando
local_pathes un archivo, el comportamiento no cambia. - Cuando
local_pathes un directorio yremote_pathno existe,remote_pathse convierte en la raíz del directorio de destino. - Cuando
local_pathes un directorio yremote_pathya existe como directorio, el directorio de origen se crea dentro de él usando el basename del directorio de origen. overwrite = falserejects an already-existing destination directory for the final directory root.- Las subidas de directorios requieren que
taresté disponible en el host remoto.
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
local remote_tarball = ssh:path("/srv/app/releases/current.tar.gz")
local res = ssh:upload("./dist/app.tar.gz", remote_tarball, {
parents = true,
overwrite = true,
echo = true,
})
print(res.bytes)
print(res.to)
Directory example:
local ssh = ptool.ssh.connect("[email protected]")
local res = ssh:upload("./dist/assets", "/srv/app/releases", {
parents = true,
overwrite = true,
echo = true,
})
print(res.bytes)
print(res.to) -- [email protected]:22:/srv/app/releases
download
v0.1.0- Introduced.
Canonical API name: ptool.ssh.Connection:download.
conn:download(remote_path, local_path[, options]) descarga un archivo o directorio remoto a una ruta local.
remote_path(string|remote path, obligatorio): La ruta de origen en el host remoto. Puede ser una cadena o un valor creado porconn:path(...).local_path(string, obligatorio): La ruta de destino local.options(table, optional): Transfer options.- Returns: A table with the following fields:
bytes(integer): El número de bytes de archivos regulares descargados. Cuando se descarga un directorio, es la suma de los tamaños de los archivos descargados.from(string): La ruta remota de origen.to(string): La ruta local de destino.
Supported transfer options:
parents(boolean, opcional): Crea el directorio padre delocal_pathantes de descargar. Por defecto esfalse.overwrite(boolean, optional): Whether an existing destination file may be replaced. Defaults totrue.echo(boolean, optional): Whether to print the transfer before executing it. Defaults tofalse.
Directory behavior:
- Cuando
remote_pathes un archivo, el comportamiento no cambia. - Cuando
remote_pathes un directorio ylocal_pathno existe,local_pathse convierte en la raíz del directorio de destino. - Cuando
remote_pathes un directorio ylocal_pathya existe como directorio, el directorio remoto de origen se crea dentro de él usando el basename del directorio remoto. overwrite = falserejects an already-existing destination directory for the final directory root.- Las descargas de directorios requieren que
taresté disponible en el host remoto.
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
local res = ssh:download("/srv/app/logs/app.log", "./tmp/app.log", {
parents = true,
overwrite = false,
echo = true,
})
print(res.bytes)
print(res.from)
Directory example:
local ssh = ptool.ssh.connect("[email protected]")
local res = ssh:download("/srv/app/releases/assets", "./tmp/releases", {
parents = true,
overwrite = true,
echo = true,
})
print(res.bytes)
print(res.from)
close
v0.1.0- Introduced.
Canonical API name: ptool.ssh.Connection:close.
conn:close() cierra el manejador de conexión SSH.
Comportamiento:
- Después de cerrarla, la conexión ya no puede usarse.
- Cerrar una conexión que ya está cerrada está permitido y no tiene efecto.
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
ssh:close()
RemotePath
v0.1.0- Introduced.
RemotePath representa una ruta remota vinculada a un Connection y devuelta por conn:path(path).
Está implementado como un userdata de Lua.
Métodos:
remote:exists()->booleanremote:is_file()->booleanremote:is_dir()->boolean
exists
remote:exists() comprueba si existe la ruta remota.
- Returns:
truewhen the remote path exists, otherwisefalse.
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
local remote_release = ssh:path("/srv/app/releases/current.tar.gz")
print(remote_release:exists())
is_file
remote:is_file() comprueba si la ruta remota existe y es un archivo regular.
- Returns:
truewhen the remote path is a file, otherwisefalse.
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
local remote_tarball = ssh:path("/srv/app/releases/current.tar.gz")
if remote_tarball:is_file() then
print("release tarball exists")
end
is_dir
remote:is_dir() comprueba si la ruta remota existe y es un directorio.
- Returns:
truewhen the remote path is a directory, otherwisefalse.
Ejemplo:
local ssh = ptool.ssh.connect("[email protected]")
local releases = ssh:path("/srv/app/releases")
if releases:is_dir() then
print("releases directory is ready")
end