File Operations Module¶
O módulo file_ops
fornece operações de gerenciamento de arquivos similares aos módulos do Ansible, permitindo manipular arquivos, templates, archives e muito mais.
Funções Disponíveis¶
copy()¶
Copia um arquivo de origem para destino, preservando ou definindo permissões.
Sintaxe:
Parâmetros: - src
(string): Caminho do arquivo de origem - dst
(string): Caminho do arquivo de destino - options
(table, opcional): Opções adicionais - mode
(string): Permissões do arquivo (formato octal, ex: "0644")
Retorno: - result
(table): Informações sobre a operação - changed
(boolean): Se houve mudança - src
(string): Arquivo de origem - dest
(string): Arquivo de destino - size
(number): Tamanho do arquivo copiado - err
(string): Mensagem de erro, se houver
Exemplos:
Exemplo Básico¶
task("copy_config", function()
local result = file_ops.copy(
"/etc/nginx/nginx.conf",
"/tmp/nginx.conf.backup"
)
if result then
log.info("Config copied successfully")
end
end)
Cópia com Permissões Específicas¶
task("copy_with_permissions", function()
local result = file_ops.copy(
"/app/config.json",
"/backup/config.json",
{mode = "0600"}
)
if result and result.changed then
log.info(string.format("Copied %d bytes", result.size))
end
end)
Cópia com delegate_to¶
task("copy_to_remote", function()
:delegate_to("prod-server")
local result = file_ops.copy(
"/local/app.conf",
"/remote/app.conf",
{mode = "0644"}
)
if result then
log.info("Config deployed to prod-server")
end
end)
fetch()¶
Busca um arquivo do agente remoto para a máquina local.
Sintaxe:
Parâmetros: - src
(string): Caminho do arquivo remoto - dst
(string): Caminho do arquivo local
Retorno: - result
(table): Informações sobre a operação - changed
(boolean): Se houve mudança - src
(string): Arquivo de origem - dest
(string): Arquivo de destino - size
(number): Tamanho do arquivo
Exemplos:
Fetch Básico¶
task("fetch_logs", function()
local result = file_ops.fetch(
"/var/log/app.log",
"/local/logs/app.log"
)
if result then
log.info(string.format("Fetched %d bytes", result.size))
end
end)
Fetch de Múltiplos Servidores¶
local servers = {"web1", "web2", "web3"}
for _, server in ipairs(servers) do
task("fetch_from_" .. server, function()
:delegate_to(server)
local result = file_ops.fetch(
"/var/log/nginx/access.log",
string.format("/logs/%s/access.log", server)
)
if result then
log.info(string.format("%s: fetched log", server))
end
end)
end
template()¶
Renderiza um template com variáveis e salva no destino.
Sintaxe:
Parâmetros: - src
(string): Caminho do arquivo template (formato Go template) - dst
(string): Caminho do arquivo de saída - vars
(table): Variáveis para renderização
Retorno: - result
(table): Informações sobre a operação - changed
(boolean): Se houve mudança - src
(string): Template de origem - dest
(string): Arquivo de destino
Exemplos:
Template Simples¶
task("configure_app", function()
local vars = {
AppName = "MyApp",
Port = 8080,
Environment = "production",
Debug = false
}
local result = file_ops.template(
"/templates/config.json.tmpl",
"/app/config.json",
vars
)
if result and result.changed then
log.info("Configuration updated")
end
end)
Template para Nginx¶
task("configure_nginx", function()
:delegate_to("web-server")
local vars = {
ServerName = "example.com",
Port = 80,
RootDir = "/var/www/html",
AccessLog = "/var/log/nginx/access.log",
ErrorLog = "/var/log/nginx/error.log"
}
local result = file_ops.template(
"/templates/nginx.conf.tmpl",
"/etc/nginx/sites-available/mysite",
vars
)
if result then
-- Reload nginx
cmd.run("nginx -t && systemctl reload nginx")
end
end)
Template Condicional¶
task("configure_database", function()
local db_vars = {
Host = "localhost",
Port = 5432,
Database = "myapp",
User = "appuser",
MaxConnections = 100,
EnableSSL = os.getenv("ENV") == "production"
}
file_ops.template(
"/templates/database.conf.tmpl",
"/etc/myapp/database.conf",
db_vars
)
end)
lineinfile()¶
Garante que uma linha específica existe (ou não existe) em um arquivo.
Sintaxe:
Parâmetros: - path
(string): Caminho do arquivo - line
(string): Linha a ser inserida/removida - options
(table, opcional): Opções - state
(string): "present" ou "absent" (padrão: "present") - regexp
(string): Expressão regular para encontrar linha existente
Retorno: - result
(table): Informações sobre a operação - changed
(boolean): Se houve mudança - path
(string): Caminho do arquivo
Exemplos:
Adicionar Linha¶
task("add_host_entry", function()
local result = file_ops.lineinfile(
"/etc/hosts",
"192.168.1.100 myserver.local"
)
if result.changed then
log.info("Host entry added")
end
end)
Substituir com Regexp¶
task("update_config", function()
-- Atualiza a linha que começa com "port="
local result = file_ops.lineinfile(
"/app/config.ini",
"port=8080",
{regexp = "^port="}
)
if result.changed then
log.info("Port updated to 8080")
end
end)
Remover Linha¶
task("remove_deprecated_config", function()
local result = file_ops.lineinfile(
"/etc/app.conf",
"enable_legacy_mode=true",
{state = "absent"}
)
if result.changed then
log.info("Legacy mode disabled")
end
end)
Configuração de SSH¶
task("secure_ssh", function()
:delegate_to("all-servers")
-- Desabilita autenticação por senha
file_ops.lineinfile(
"/etc/ssh/sshd_config",
"PasswordAuthentication no",
{regexp = "^#?PasswordAuthentication"}
)
-- Desabilita root login
file_ops.lineinfile(
"/etc/ssh/sshd_config",
"PermitRootLogin no",
{regexp = "^#?PermitRootLogin"}
)
-- Restart SSH
systemd.restart("sshd")
end)
blockinfile()¶
Insere, atualiza ou remove um bloco de linhas em um arquivo.
Sintaxe:
Parâmetros: - path
(string): Caminho do arquivo - block
(string): Bloco de texto a ser gerenciado - options
(table, opcional): Opções - state
(string): "present" ou "absent" (padrão: "present") - marker_begin
(string): Marcador inicial (padrão: "# BEGIN MANAGED BLOCK") - marker_end
(string): Marcador final (padrão: "# END MANAGED BLOCK")
Retorno: - result
(table): Informações sobre a operação - changed
(boolean): Se houve mudança - path
(string): Caminho do arquivo
Exemplos:
Adicionar Bloco de Configuração¶
task("add_cron_jobs", function()
local cron_block = [[
0 2 * * * /usr/local/bin/backup.sh
0 3 * * * /usr/local/bin/cleanup.sh
0 4 * * 0 /usr/local/bin/weekly-report.sh]]
local result = file_ops.blockinfile(
"/etc/cron.d/myapp",
cron_block
)
if result.changed then
log.info("Cron jobs configured")
end
end)
Atualizar Bloco Existente¶
task("update_firewall_rules", function()
local rules = [[
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT]]
file_ops.blockinfile(
"/etc/iptables/rules.v4",
rules,
{
marker_begin = "# BEGIN SLOTH RULES",
marker_end = "# END SLOTH RULES"
}
)
end)
Remover Bloco¶
task("cleanup_old_config", function()
local result = file_ops.blockinfile(
"/etc/app.conf",
"",
{state = "absent"}
)
if result.changed then
log.info("Old configuration block removed")
end
end)
Configurar Hosts File¶
task("configure_internal_hosts", function()
local hosts_block = [[
192.168.1.10 db-primary.internal
192.168.1.11 db-replica.internal
192.168.1.20 cache-01.internal
192.168.1.21 cache-02.internal]]
file_ops.blockinfile(
"/etc/hosts",
hosts_block,
{
marker_begin = "# BEGIN INTERNAL HOSTS",
marker_end = "# END INTERNAL HOSTS"
}
)
end)
replace()¶
Substitui todas as ocorrências de um padrão em um arquivo usando expressões regulares.
Sintaxe:
Parâmetros: - path
(string): Caminho do arquivo - pattern
(string): Expressão regular para busca - replacement
(string): Texto de substituição
Retorno: - result
(table): Informações sobre a operação - changed
(boolean): Se houve mudança - path
(string): Caminho do arquivo
Exemplos:
Substituição Simples¶
task("update_version", function()
local result = file_ops.replace(
"/app/version.txt",
"version=1\\.0\\.0",
"version=2.0.0"
)
if result.changed then
log.info("Version updated")
end
end)
Atualizar Múltiplas Ocorrências¶
task("update_api_endpoint", function()
local result = file_ops.replace(
"/app/config.json",
"http://old-api\\.example\\.com",
"https://new-api.example.com"
)
if result.changed then
log.info("API endpoint updated")
end
end)
Replace com Captura de Grupos¶
task("update_database_config", function()
-- Substitui host do banco mantendo o resto da string
file_ops.replace(
"/etc/myapp/db.conf",
"host=(\\w+)\\.old\\.domain",
"host=$1.new.domain"
)
end)
unarchive()¶
Extrai arquivos compactados (.zip, .tar, .tar.gz, .tgz).
Sintaxe:
Parâmetros: - src
(string): Caminho do arquivo compactado - dst
(string): Diretório de destino para extração
Retorno: - result
(table): Informações sobre a operação - changed
(boolean): Se houve mudança - src
(string): Arquivo de origem - dest
(string): Diretório de destino
Exemplos:
Extrair ZIP¶
task("extract_release", function()
local result = file_ops.unarchive(
"/tmp/app-v2.0.0.zip",
"/opt/myapp"
)
if result then
log.info("Release extracted successfully")
end
end)
Extrair TAR.GZ¶
task("deploy_backup", function()
:delegate_to("backup-server")
file_ops.unarchive(
"/backups/data-20240101.tar.gz",
"/var/restore"
)
log.info("Backup extracted")
end)
Deploy de Aplicação¶
task("deploy_application", function()
-- Download release
http.download(
"https://releases.example.com/app-v3.0.0.tar.gz",
"/tmp/app-v3.0.0.tar.gz"
)
-- Extract
file_ops.unarchive(
"/tmp/app-v3.0.0.tar.gz",
"/opt/myapp"
)
-- Restart service
systemd.restart("myapp")
log.info("Application deployed: v3.0.0")
end)
stat()¶
Obtém informações detalhadas sobre um arquivo ou diretório.
Sintaxe:
Parâmetros: - path
(string): Caminho do arquivo ou diretório
Retorno: - result
(table): Informações do arquivo - exists
(boolean): Se o arquivo existe - path
(string): Caminho do arquivo - size
(number): Tamanho em bytes - mode
(string): Permissões (formato octal) - is_dir
(boolean): Se é um diretório - is_file
(boolean): Se é um arquivo regular - mtime
(number): Timestamp de modificação - checksum
(string): Checksum SHA256 - uid
(number): User ID do proprietário (Unix) - gid
(number): Group ID do proprietário (Unix)
Exemplos:
Verificar Existência¶
task("check_config", function()
local info = file_ops.stat("/etc/myapp/config.json")
if not info.exists then
log.error("Configuration file missing!")
return
end
log.info("Config file exists")
end)
Verificar Tamanho¶
task("check_log_size", function()
local info = file_ops.stat("/var/log/app.log")
if info.exists and info.size > 100 * 1024 * 1024 then
log.warn("Log file is over 100MB, rotating...")
cmd.run("logrotate /etc/logrotate.d/myapp")
end
end)
Verificar Permissões¶
task("audit_permissions", function()
local sensitive_files = {
"/etc/ssl/private/server.key",
"/etc/myapp/secrets.conf",
"/root/.ssh/id_rsa"
}
for _, file in ipairs(sensitive_files) do
local info = file_ops.stat(file)
if info.exists then
if info.mode ~= "600" then
log.error(string.format(
"Insecure permissions on %s: %s (expected 600)",
file, info.mode
))
else
log.info(string.format("%s: OK", file))
end
end
end
end)
Comparar Checksums¶
task("verify_deployment", function()
local local_file = file_ops.stat("/local/app.jar")
local remote_file = file_ops.stat("/opt/app/app.jar")
if local_file.checksum == remote_file.checksum then
log.info("Deployment verified: checksums match")
else
log.error("Checksum mismatch! Deployment may be corrupted")
end
end)
Exemplos Avançados¶
Pipeline de Deploy Completo¶
local config = {
version = "v2.5.0",
servers = {"web1", "web2", "web3"},
app_dir = "/opt/myapp",
backup_dir = "/var/backups/myapp"
}
-- Backup da versão atual
task("backup_current", function()
for _, server in ipairs(config.servers) do
:delegate_to(server)
local timestamp = os.date("%Y%m%d_%H%M%S")
local backup_name = string.format("backup_%s.tar.gz", timestamp)
cmd.run(string.format(
"tar czf %s/%s -C %s .",
config.backup_dir,
backup_name,
config.app_dir
))
log.info(string.format("%s: backup created", server))
end
end)
-- Deploy nova versão
task("deploy_new_version", function()
:depends_on("backup_current")
for _, server in ipairs(config.servers) do
:delegate_to(server)
-- Download release
local release_url = string.format(
"https://releases.example.com/app-%s.tar.gz",
config.version
)
local tmp_file = "/tmp/app-release.tar.gz"
http.download(release_url, tmp_file)
-- Extract
file_ops.unarchive(tmp_file, config.app_dir)
-- Update configuration
local vars = {
ServerID = server,
Environment = "production",
Version = config.version
}
file_ops.template(
"/templates/app.conf.tmpl",
config.app_dir .. "/config/app.conf",
vars
)
log.info(string.format("%s: deployed %s", server, config.version))
end
end)
-- Restart services
task("restart_services", function()
:depends_on("deploy_new_version")
for _, server in ipairs(config.servers) do
:delegate_to(server)
systemd.restart("myapp")
-- Wait for healthcheck
local healthy = false
for i = 1, 10 do
sleep(2)
local response = http.get("http://localhost:8080/health")
if response and response.status == 200 then
healthy = true
break
end
end
if healthy then
log.info(string.format("%s: service healthy", server))
else
log.error(string.format("%s: healthcheck failed!", server))
end
end
end)
Configuração Centralizada¶
task("configure_all_servers", function()
local servers = {
{name = "web1", role = "web", ip = "192.168.1.10"},
{name = "web2", role = "web", ip = "192.168.1.11"},
{name = "db1", role = "database", ip = "192.168.1.20"}
}
-- Configure /etc/hosts em todos os servidores
local hosts_block = ""
for _, srv in ipairs(servers) do
hosts_block = hosts_block .. string.format(
"%s %s.internal %s\n",
srv.ip, srv.name, srv.name
)
end
for _, server in ipairs(servers) do
:delegate_to(server.name)
-- Update hosts
file_ops.blockinfile(
"/etc/hosts",
hosts_block,
{
marker_begin = "# BEGIN CLUSTER HOSTS",
marker_end = "# END CLUSTER HOSTS"
}
)
-- Configure based on role
if server.role == "web" then
file_ops.template(
"/templates/nginx.conf.tmpl",
"/etc/nginx/nginx.conf",
{ServerName = server.name, Role = server.role}
)
elseif server.role == "database" then
file_ops.template(
"/templates/postgresql.conf.tmpl",
"/etc/postgresql/postgresql.conf",
{ServerName = server.name, Role = server.role}
)
end
log.info(string.format("%s: configured", server.name))
end
end)
Integração com Outros Módulos¶
Com systemd¶
task("update_and_restart", function()
:delegate_to("app-server")
-- Update configuration
file_ops.lineinfile(
"/etc/myapp/app.conf",
"workers=8",
{regexp = "^workers="}
)
-- Restart if changed
systemd.restart("myapp")
-- Verify
if systemd.is_active("myapp") then
log.info("Service restarted successfully")
end
end)
Com pkg¶
task("install_and_configure", function()
:delegate_to("new-server")
-- Install package
pkg.install("nginx")
-- Configure
file_ops.template(
"/templates/nginx.conf.tmpl",
"/etc/nginx/nginx.conf",
{Port = 80, Workers = 4}
)
-- Enable and start
systemd.enable("nginx")
systemd.start("nginx")
end)
Com user¶
task("setup_application_user", function()
-- Create user
user.create("appuser", {
home = "/home/appuser",
shell = "/bin/bash",
system = true
})
-- Create app directory
cmd.run("mkdir -p /opt/myapp")
cmd.run("chown appuser:appuser /opt/myapp")
-- Copy application files
file_ops.copy(
"/dist/app.jar",
"/opt/myapp/app.jar"
)
-- Set permissions
cmd.run("chown appuser:appuser /opt/myapp/app.jar")
cmd.run("chmod 755 /opt/myapp/app.jar")
end)
Melhores Práticas¶
- Sempre verifique o retorno: Cheque se a operação foi bem-sucedida
- Use idempotência: Os módulos são idempotentes por design
- Faça backup: Sempre faça backup antes de modificações críticas
- Use templates: Para arquivos complexos, prefira templates
- Valide com stat(): Verifique o estado final dos arquivos
- Use delegate_to: Para operações em servidores remotos
- Combine com systemd: Reinicie serviços após mudanças de configuração
Tratamento de Erros¶
task("safe_file_operation", function()
local result, err = file_ops.copy(
"/source/file.txt",
"/dest/file.txt"
)
if not result then
log.error("Failed to copy file: " .. tostring(err))
return
end
if result.changed then
log.info("File copied successfully")
else
log.info("File already up to date")
end
end)