API de SSH
Os helpers para conexão SSH, execução remota e transferência de arquivos estão
disponíveis em ptool.ssh e p.ssh.
ptool.ssh.connect
v0.1.0- Introduced.
ptool.ssh.connect(target_or_options) prepara um handle de conexão SSH apoiado
no comando ssh do sistema e retorna um objeto Connection.
ssh precisa estar disponível em PATH.
Argumentos:
target_or_options(string|table, obrigatório):- Quando uma string é fornecida, ela é tratada como um destino SSH.
- Quando uma tabela é fornecida, atualmente ela suporta:
target(string, opcional): String de destino SSH, como"[email protected]"ou"[email protected]:2222".host(string, opcional): Hostname ou endereço IP.user(string, opcional): Nome de usuário SSH. O padrão é$USER, ou"root"se$USERnão estiver disponível.port(integer, opcional): Porta SSH. O padrão é22.auth(table, opcional): Configuração de autenticação.host_key(table, opcional): Configuração de verificação de chave de host.connect_timeout_ms(integer, opcional): Timeout em milissegundos. O padrão é10000.keepalive_interval_ms(integer, opcional): Intervalo de keepalive em milissegundos.
Exemplos de strings de destino suportadas:
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): Caminho para um arquivo de chave privada.private_key_passphrase(string, opcional): Senha da chave privada. Atualmente não é suportada.password(string, opcional): Autenticação por senha. Atualmente não é suportada.
Comportamento de autenticação:
- Se
auth.private_key_filefor fornecido,ptoolinvocasshcom essa chave via-ie também defineIdentitiesOnly=yes. - Se
auth.private_key_passphraseouauth.passwordfor fornecido,ptool.ssh.connect(...)falha porque esta API não passa esses segredos para o comandosshdo sistema. - Caso contrário, a autenticação é delegada à configuração local do OpenSSH,
incluindo definições e mecanismos como
IdentityFile,ProxyJump,ProxyCommand,ssh-agente certificados. - Caminhos de chave relativos são resolvidos a partir do diretório de runtime
atual do
ptool, então eles seguemptool.cd(...). ~e~/...são expandidos em caminhos de chave.
Campos de host_key:
verify(string, opcional): Modo de verificação de chave de host. Valores suportados:"known_hosts": Verifica contra um arquivoknown_hosts(padrão)."ignore": Ignora a verificação de chave de host.
known_hosts_file(string, opcional): Caminho para um arquivoknown_hosts. Usado apenas quandoverify = "known_hosts".
Comportamento de chave de host:
- Se
verify = "ignore",ptoolinvocasshcomStrictHostKeyChecking=noeUserKnownHostsFile=/dev/null. - Se
verify = "known_hosts"eknown_hosts_filefor fornecido,ptoolinvocasshcomStrictHostKeyChecking=yese esseUserKnownHostsFile. - Se
verify = "known_hosts"eknown_hosts_filefor omitido, ou quandohost_keyé omitido por completo, o tratamento da chave de host é delegado à configuração local do OpenSSH e aos padrões dele. - Caminhos relativos de
known_hosts_filesão resolvidos a partir do diretório de runtime atual doptool. ~e~/...são expandidos emknown_hosts_file.- Quando
known_hosts_fileé fornecido explicitamente, ele substitui oUserKnownHostsFilepadrão usado pelo comandosshlocal para esta conexão.
Exemplo:
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 um handle de conexão apoiado em OpenSSH retornado por
ptool.ssh.connect().
Ele é implementado como um userdata de Lua.
Campos e métodos:
- Campos:
conn.host(string)conn.user(string)conn.port(integer)conn.target(string)
- Métodos:
conn:run(...)->tableconn:run_capture(...)->tableconn: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(...) executa um comando remoto através da conexão SSH atual.
As seguintes formas de chamada são suportadas:
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"} })
Regras de argumento:
conn:run(cmdline):cmdlineé enviado como a string de comando remoto.conn:run(cmd, argsline):cmdé tratado como o comando, eargslineé dividido usando regras de estilo shell (shlex).conn:run(cmd, args):cmdé uma string eargsé um array de strings. Os argumentos passam por quoting de shell antes da execução remota.conn:run(cmdline, options):optionssobrescreve esta invocação.conn:run(cmd, args, options):optionssobrescreve esta invocação.conn:run(options):optionsé uma tabela.- Quando o segundo argumento é uma tabela: se ela for um array (chaves inteiras
consecutivas
1..n), ela é tratada comoargs; caso contrário, é tratada comooptions.
Quando conn:run(options) é usado, options atualmente suporta:
cmd(string, obrigatório): O nome do comando ou caminho do executável.args(string[], opcional): A lista de argumentos.cwd(string, opcional): Diretório de trabalho remoto. Isso é aplicado ao prefixarcd ... &&ao comando shell remoto gerado.env(table, opcional): Variáveis de ambiente remotas, onde chaves e valores são strings. Isso é aplicado ao prefixarexport ... &&ao comando shell remoto gerado.stdin(string, opcional): String enviada ao stdin do processo remoto.echo(boolean, opcional): Se deve ecoar o comando remoto antes da execução. O padrão étrue.check(boolean, opcional): Se deve gerar erro imediatamente quando o status de saída não for0. O padrão éfalse.stdout(string, opcional): Estratégia de tratamento de stdout. Valores suportados:"inherit": Herda para o terminal atual (padrão)."capture": Captura emres.stdout."null": Descarta a saída.
stderr(string, opcional): Estratégia de tratamento de stderr. Valores suportados:"inherit": Herda para o terminal atual (padrão)."capture": Captura emres.stderr."null": Descarta a saída.
Quando as formas abreviadas são usadas, a tabela options suporta apenas:
stdin(string, opcional): String enviada ao stdin do processo remoto.echo(boolean, opcional): Se deve ecoar o comando remoto antes da execução. O padrão étrue.check(boolean, opcional): Se deve gerar erro imediatamente quando o status de saída não for0. O padrão éfalse.stdout(string, opcional): Estratégia de tratamento de stdout. Valores suportados:"inherit": Herda para o terminal atual (padrão)."capture": Captura emres.stdout."null": Descarta a saída.
stderr(string, opcional): Estratégia de tratamento de stderr. Valores suportados:"inherit": Herda para o terminal atual (padrão)."capture": Captura emres.stderr."null": Descarta a saída.
Regras do valor de retorno:
- Uma tabela sempre é retornada com os seguintes campos:
ok(boolean): Se o status de saída remoto é0.code(integer|nil): O status de saída remoto. Se o processo remoto sair por sinal, este valor seránil.target(string): A string de destino SSH no formatouser@host:port.stdout(string, opcional): Presente quandostdout = "capture".stderr(string, opcional): Presente quandostderr = "capture".assert_ok(self)(function): Gera erro quandook = false.
Exemplo:
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",
},
stdout = "capture",
check = true,
})
print(res2.stdout)
run_capture
Unreleased- Introduced.
Canonical API name: ptool.ssh.Connection:run_capture.
conn:run_capture(...) executa um comando remoto através da conexão SSH atual.
Ele aceita as mesmas formas de chamada, regras de argumento, regras do valor
de retorno e opções de conn:run(...).
A única diferença é o tratamento padrão dos streams:
stdoutusa"capture"por padrão.stderrusa"capture"por padrão.
Você ainda pode sobrescrever qualquer um desses campos explicitamente em
options.
Exemplo:
local ssh = ptool.ssh.connect("[email protected]")
local res = ssh:run_capture("uname -a")
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)
path
v0.1.0- Introduced.
Canonical API name: ptool.ssh.Connection:path.
conn:path(path) cria um objeto RemotePath reutilizável vinculado à conexão
SSH atual.
path(string, obrigatório): O caminho remoto.- Retorna: Um objeto
RemotePathque pode ser passado paraconn:upload(...),conn:download(...)eptool.fs.copy(...).
Exemplo:
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) verifica se um caminho remoto existe.
path(string|remote path, obrigatório): O caminho remoto a verificar. Ele pode ser uma string ou um valor criado porconn:path(...).- Retorna:
truequando o caminho remoto existe; caso contrário,false.
Exemplo:
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) verifica se um caminho remoto existe e é um arquivo
regular.
path(string|remote path, obrigatório): O caminho remoto a verificar. Ele pode ser uma string ou um valor criado porconn:path(...).- Retorna:
truequando o caminho remoto é um arquivo; caso contrário,false.
Exemplo:
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) verifica se um caminho remoto existe e é um diretório.
path(string|remote path, obrigatório): O caminho remoto a verificar. Ele pode ser uma string ou um valor criado porconn:path(...).- Retorna:
truequando o caminho remoto é um diretório; caso contrário,false.
Exemplo:
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]) envia um arquivo ou diretório
local para o host remoto.
local_path(string, obrigatório): O arquivo ou diretório local a enviar.remote_path(string|remote path, obrigatório): O caminho de destino no host remoto. Ele pode ser uma string ou um valor criado porconn:path(...).options(table, opcional): Opções de transferência.- Retorna: Uma tabela com os seguintes campos:
bytes(integer): O número de bytes de arquivos regulares enviados. Quando um diretório é enviado, este valor é a soma dos tamanhos dos arquivos enviados.from(string): O caminho de origem local.to(string): O caminho de destino remoto.
Opções de transferência suportadas:
parents(boolean, opcional): Cria o diretório pai deremote_pathantes do envio. O padrão éfalse.overwrite(boolean, opcional): Se um arquivo de destino existente pode ser substituído. O padrão étrue.echo(boolean, opcional): Se deve imprimir a transferência antes de executá-la. O padrão éfalse.
Comportamento de diretórios:
- Quando
local_pathé um arquivo, o comportamento não muda. - Quando
local_pathé um diretório eremote_pathnão existe,remote_pathse torna a raiz do diretório de destino. - Quando
local_pathé um diretório eremote_pathjá existe como diretório, o diretório de origem é criado dentro dele usando o basename do diretório de origem. overwrite = falserejeita um diretório de destino já existente para a raiz final do diretório.- Envios de diretório exigem que
taresteja disponível no host remoto.
Exemplo:
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)
Exemplo de diretório:
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]) baixa um arquivo ou
diretório remoto para um caminho local.
remote_path(string|remote path, obrigatório): O caminho de origem no host remoto. Ele pode ser uma string ou um valor criado porconn:path(...).local_path(string, obrigatório): O caminho de destino local.options(table, opcional): Opções de transferência.- Retorna: Uma tabela com os seguintes campos:
bytes(integer): O número de bytes de arquivos regulares baixados. Quando um diretório é baixado, este valor é a soma dos tamanhos dos arquivos baixados.from(string): O caminho de origem remoto.to(string): O caminho de destino local.
Opções de transferência suportadas:
parents(boolean, opcional): Cria o diretório pai delocal_pathantes do download. O padrão éfalse.overwrite(boolean, opcional): Se um arquivo de destino existente pode ser substituído. O padrão étrue.echo(boolean, opcional): Se deve imprimir a transferência antes de executá-la. O padrão éfalse.
Comportamento de diretórios:
- Quando
remote_pathé um arquivo, o comportamento não muda. - Quando
remote_pathé um diretório elocal_pathnão existe,local_pathse torna a raiz do diretório de destino. - Quando
remote_pathé um diretório elocal_pathjá existe como diretório, o diretório remoto de origem é criado dentro dele usando o basename do diretório remoto. overwrite = falserejeita um diretório de destino já existente para a raiz final do diretório.- Downloads de diretório exigem que
taresteja disponível no host remoto.
Exemplo:
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)
Exemplo de diretório:
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() fecha o handle de conexão SSH.
Comportamento:
- Depois de fechada, a conexão não pode mais ser usada.
- Fechar uma conexão que já está fechada é permitido e não tem efeito.
Exemplo:
local ssh = ptool.ssh.connect("[email protected]")
ssh:close()
RemotePath
v0.1.0- Introduced.
RemotePath representa um caminho remoto vinculado a um Connection e
retornado por conn:path(path).
Ele é implementado como um userdata de Lua.
Métodos:
remote:exists()->booleanremote:is_file()->booleanremote:is_dir()->boolean
exists
remote:exists() verifica se o caminho remoto existe.
- Retorna:
truequando o caminho remoto existe; caso contrário,false.
Exemplo:
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() verifica se o caminho remoto existe e é um arquivo regular.
- Retorna:
truequando o caminho remoto é um arquivo; caso contrário,false.
Exemplo:
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() verifica se o caminho remoto existe e é um diretório.
- Retorna:
truequando o caminho remoto é um diretório; caso contrário,false.
Exemplo:
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