Introdução ao SaltStack
O SaltStack (comumente chamado de Salt), é um software de código aberto baseado em Python para automação de TI orientada a eventos, execução remota de tarefas e gerenciamento de configuração (Semelhante ao Ansible). Para que tudo funcione, existem duas peças que são fundamentais, são elas: Salt Master e Salt Minion. O servidor que atua como Master (Salt Master) é o servidor central que controla os Minions. Ele envia comandos, monitora o estado dos sistemas de forma centralizada. Já o servidor que atua como Minion (Salt Minion) recebem e executam as ordens vindas do Master. Eles reportam de volta o status e os resultados das ações executadas.
A comunicação entre o Master e os Minions usa o protocolo ZeroMQ (por padrão), garantindo alta performance e capacidade de escala.
O Salt permite rodar comandos em um ou vários Minions a partir do Master, sem a necessidade de acessar diretamente cada máquina. Isso é feito de maneira rápida e eficiente graças ao uso do Python e ao protocolo ZeroMQ, que possibilita a comunicação em tempo real. Com isso, você pode executar tarefas complexas como atualizações, instalação de pacotes, reinicialização de serviços, entre outras ações, em uma grande quantidade de sistemas de forma simultânea.
O sistema de gerenciamento de configuração do Salt é baseado nos chamados States. Esses States são arquivos que definem o estado desejado de um sistema, como, por exemplo, "um determinado pacote deve estar instalado" ou "um serviço deve estar rodando". Eles são aplicados de forma repetível e idempotente, ou seja, a mesma configuração pode ser reaplicada sem causar efeitos colaterais, garantindo que os sistemas estejam sempre configurados de acordo com as especificações.
Como existem várias formas de instalar o Salt, em diferentes Sistemas Operacionais Linux, vou deixar abaixo os links para que possa instalar usando a maneira que se sentir mais confortável.
Link para a instalação em vários sistemas Clique aqui;
Link para a instalação usando o script oficial Clique aqui;
Firewall
O Salt Master escuta em duas portas principais, 4505 e 4506 (somente TCP), por padrão em todas as interfaces de rede. A porta 4505 é utilizada para manter uma conexão persistente entre o Salt Minion e o Salt Master. Os comandos do Master são enviados de forma assíncrona (significa que o Salt Master pode enviar comandos para os Minions sem precisar esperar que eles terminem de executar as tarefas antes de continuar com outras ações.) para os Minions conectados a essa porta, permitindo a execução de tarefas simultâneas em múltiplos sistemas de maneira eficiente.
Já a porta 4506 é usada para conexões de retorno, quando os Minions enviam resultados de execução de volta ao Master. As conexões nesta porta são 1:1, ou seja, não assíncronas, estabelecendo um canal direto e seguro entre um Minion específico e o Master. Quando configurar firewalls, seja no host ou na rede, é essencial garantir que essas portas estejam abertas, tanto no Master quanto nos Minions, para assegurar a comunicação adequada e o funcionamento pleno do ambiente Salt.
Instalando o Salt
Vou rodar todos os exemplos em servidores ubuntu 22.04, escolhi instalar tanto o Master como Minion usando o script oficial, assim não teremos métodos diferentes para cada sistema.
Instalar o Master
Vamos instalar o serviço do Salt Master:
root@saltmaster:~# wget -q https://bootstrap.saltstack.com -O install_salt.sh
root@saltmaster:~# sudo sh install_salt.sh -P -M -x python3
Instalar o Minion
Vamos instalar o serviço do Salt Minion:
root@saltminion:~# wget -q https://bootstrap.saltstack.com -O install_salt.sh
root@saltminion:~# sudo sh install_salt.sh -P -x python3
Configurando o Minion
Para que o Salt Minion saiba com qual servidor Salt Master ele deve se comunicar, precisamos configurar o endereço IP do Master no Minion. Isso estabelece a conexão inicial, permitindo que o Minion receba comandos e envie relatórios ao Master. Link oficial de como configurar o Salt Minion!
# Vamos editar o arquivo de configuração do Minion:
root@saltminion:~# vim /etc/salt/minion
# Coloque o IP do master dentro do arquivo,
# A linha 'master:' já existe, então edite ela:
master: 192.168.0.51
# Podemos configurar o ID do nosso Salt Minion também, para isso basta editar a linha:
#id:
# E deixa-lá como abaixo:
id: Minion1
# Outra forma de configurar o ID do minion é no arquivo /etc/salt/minion_id.
# Se for deixado comentado, o id será o nome do host conforme retornado pela chamada
# python: socket.getfqdn()
# Como o salt usa ids separados, é possível executar vários minions na mesma máquina, mas com
# ids diferentes, isso pode ser útil para clusters de computação salt.
# Pelo fato explicado acima, eu geralmente nao configuro o ID, vamos ter 2 solicitações
# do mesmo minion com IDs diferentes.
Seu arquivo de configuração do Salt Minion deve estar igual a saída abaixo, somente com 1 linha ativa (sem comentários):
# O comando abaixo remove as linhas comentadas e as linhas em branco,
# para assim, podermos ver somente as linhas ativa no arquivo de
# configuração!
root@saltminion:~# sed '/^#/d; /^$/d' /etc/salt/minion
master: 192.168.0.51
# Agora reinicie o serviço:
root@saltminion:~# systemctl restart salt-minion
# Agora verifique se o serviço está ativo:
root@saltminion:~# systemctl status salt-minion
Outra forma, mais simples, é colocar o IP do master no /etc/hosts
do minion.
root@saltminion:~# vim /etc/hosts
# Adicione a linha abaixo:
192.158.0.51 salt
Vamos configurar a interface do Master
Essa é uma configuração opcional no Salt Master, por padrão ele vem configuração para aceitar conexões em qualquer interface que o servidor tenha, o que vou fazer é definir uma interface de escuta, assim ele só vai aceitar conexões e enviar requisições para os minions através dessa interface. Link oficial de como configurar o Salt Master!
# A configuração está na linha 15:
root@saltmaster:~# vim +15 /etc/salt/master
# Agora descomente essa linha e coloque o IP do servidor (interface)
# que vai atender ficar ouvindo requisições de minions:
root@saltmaster:~# interface: 192.168.0.51
# Agora reinicie o serviço:
root@saltmaster:~# systemctl restart salt-master
# Agora verifique se o serviço está ativo:
root@saltmaster:~# systemctl status salt-master
Executar o Salt com um usuário sem privilégios root
Para rodar o Salt com outro usuário além do padrão (geralmente root
), você precisa ajustar o parâmetro user
no arquivo de configuração do Salt Master e garantir que esse usuário tenha as permissões adequadas nas pastas usadas pelo Salt. O novo usuário precisa ter permissões de leitura e escrita nos seguintes diretórios e seus subdiretórios:
- /etc/salt: Contém os arquivos de configuração do Salt.
- /var/cache/salt: Armazena os dados de cache.
- /var/log/salt: Guarda os logs de execução do Salt.
- /var/run/salt: Armazena arquivos temporários e PID.
# Para conceder as permissões necessárias, use o seguinte comando:
chown -R USERNAME /etc/salt /var/cache/salt /var/log/salt /var/run/salt
Certifique-se de substituir
USERNAME
com o nome correto do usuário que você deseja usar.
Mais informações sobre como executar o salt como um usuário não privilegiado podem ser encontradas aqui.
Usando ACL para aplicar permissão
Outra forma de permitir que usuários não root possam executar comandos no Salt é usando a ACL, diria que é a melhor forma de fazer isso. Com ACL podemos liberar apenas o que o usuário deva fazer, liberando apenas um comando, um módulo ou uma lista de comandos/módulos. A ACL é aplicada em /etc/salt/master
! Para mais detalhes veja a documentação completa.
A ACL deve ter a seguinte estrutura:
publisher_acl:
USERNAME:
- HOSTNAME (Minion name):
- COMMAND1
- COMMAND2
Nós podemos usar caracteres curinga para abranger vários minions ou módulos/funções, tornando o uso de ACL muito mais fáceis do que ficar criando para cada minion que o usuário deva ter acesso.
# Para executar qualquer coisa (módulo.função) em qualquer host:
publisher_acl:
USERNAME:
- .*
# Para executar todas as funções dos módulos test e pkg:
USERNAME:
- test.*
- pkg.*
# Você também pode especificar o minion onde o usuário pode executar comandos,
# todos os minions (é o padrão, neste caso, podemos omitir a declaração de host abaixo):
USERNAME:
- '*':
- test.*
- pkg.*
# Permitindo apenas 'test.ping':
USERNAME:
- test.ping
# Apenas nos minions que tenham 'aws' no nome (Ex: aws-s1, aws-s2):
USERNAME:
- aws*:
- test.*
- pkg.*
# Usando vários usernames:
USERNAME1|USERNAME2|manager_.*:
- '*':
- test.*
- pkg.*
# Usando vários hosts:
publisher_acl:
USERNAME1:
- HOST1:
- test.ping
- HOST2:
- test.ping
### Usando vários hosts (Usando combinação composta (Usa o grain))!
### Permitindo que 2 usuários possam executar todas as funções do módulo 'test' em apenas 2 hosts (server1 e server2)
publisher_acl:
admin|vagrant:
- 'L@server1,server2':
- test.*
### Permitindo apenas que seja executado o módulo 'test' em servidores 'Debian':
publisher_acl:
admin|vagrant:
- 'G@os:Debian':
- test.*
# Permitindo que apenas alguns argumentos sejam possíveis:
publisher_acl:
admin:
- 'G@os:Debian':
- test.*
- state.apply:
args:
- 'update'
Com autenticação de usuário com Kerberos eu não consegui aplicar múltiplos usuários, tendo que criar uma configuração para cada um.
Habilitando log
Agora que temos vários usuários podendo executar tarefas específicas em nossos minions, vamos habilitar o log no Salt Master para podermos ver o que eles estão fazendo.
# Usando outro arquivo para armazenar os logs do tipo INFO:
log_file: /var/log/salt/master_cmd
# Tipo do nível do log:
log_level_logfile: info
Agora reinicie o Salt-master:
systemctl restart salt-master.service
Com essa primeira parte realizada, vamos criar um grupo, adicionar os usuários nesse grupo e mudar o grupo dono desse arquivo de log, se não fizermos isso o Salt-master vai ficar relatando que o usuário (não root) não tem permissão para escrever no log, consequentemente todos os comando irão funcionar mas não serão gravados em log.
# Crie o grupo:
sudo groupadd GROUPNAME
# Adicione os usuários nesse grupo:
sudo gpasswd -a USERNAME GROUPNAME
# Mude o grupo do arquivo de log:
sudo chown :GROUPNAME /var/log/salt/master_cmd
# Mude a permissão do grupo para poder escrever
# (mas não poderá editar o arquivo, isso impede que esse arquivo seja alterado):
sudo chmod 620 /var/log/salt/master_cmd
Vendo detalhes dos comandos executados
Quando um usuário roda um comando, no log ele ficará assim:
User fulano Published command cmd.run with jid 20210920124744380487
Got return from ubuntu2104 for job 20210920124744380487
Aqui podemos ver quem que executou o comando fulano
, a tarefa que foi executada é cmd.run
, e podemos ver o minion ubuntu2104
onde a tarefa foi executada, mas não sabemos se foi executado com sucesso, nem os argumentos que foram usados no comando cmd.run
. Com isso, vamos ver os detalhes desse job ou jid, para termos mais detalhes do que foi executado:
# Verificando detalhes do job '20210920124744380487':
$ salt-run jobs.list_job 20210920124744380487
Arguments:
- rm -r snap
Function:
cmd.run
Minions:
- ubuntu2104
Result:
----------
ubuntu2104:
----------
retcode:
0
return:
success:
True
StartTime:
2021, Sep 20 12:47:44.380487
Target:
*
Target-type:
glob
User:
sudo_vagrant
jid:
20210920124744380487
Nesse job foi executado um rm -r snap
e o status de retorno do comando é success=true
(rodou sem nenhum problema). Vamos ver outro job, com ID igual a 20210920124735262612
:
$ salt-run jobs.list_job 20210920124735262612
Arguments:
- ls
Function:
cmd.run
Minions:
- ubuntu2104
Result:
----------
ubuntu2104:
----------
retcode:
0
return:
snap
success:
True
StartTime:
2021, Sep 20 12:47:35.262612
Target:
*
Target-type:
glob
User:
sudo_vagrant
jid:
20210920124735262612
Nesse job foi executado um ls
(também usando o módulo.função cmd.run
) e o retorno do comando foi snap
(Veja em return
).
Usando ACL com autenticação Externa
Uma outra forma de aplicar permissões é usando uma ACL para autenticação externa, isso significa que o Salt vai usar outro método para validar se o usuário é válido, e caso seja, permitirá que esse usuário só possa executar comandos que foram previamente liberados para ele. Com o método de publisher_acl
, as permissões só podem ser aplicadas a usuários individuais (não a grupos). A cada comando que um usuário tenta executar, ele precisará se autenticar, a menos que utilize a funcionalidade de token de autenticação.
Para evitar a necessidade de autenticar a cada execução de comando, podemos usar tokens de autenticação. Um token é criado ao autenticar o usuário pela primeira vez e tem validade de 12 horas por padrão. Durante esse período, o usuário pode executar comandos sem precisar autenticar repetidamente. Para usar o Token usamos o parâmetro -T
. Após isso, não precisa mais utilizar o -T
, já que o token foi criado. Exemplo:
salt -a pam 'server1' test.ping -T
Esse token é armazenado em um arquivo chamado salt_token
no diretório Home do usuário que executou o comando. Para invalidar esse Token basta remover ele. No arquivo de configuração podemos definir o tempo do Token (em segundos): token_expire: 43200
. A estrutura para utilização de autenticação externa é a seguinte:
external_auth:
MÉTODO de AUTENTICAÇÃO:
'usuário' ou 'grupo%':
- HOST:
- MODULES.FUNCTION
Vamos ver alguns exemplos de uso para tornar mais fácil de entender como funciona.
### Usando o pam para autenticar os usuários
# Permitindo que todos os membros de group1 possam executar 'test.ping' em todos os hosts:
external_auth:
pam:
group1%:
- '*':
- test.ping
# Permitindo que todos os membros de group1 possam executar 'test.ping' em apenas 2 hosts:
external_auth:
pam:
group1%:
- 'L@debian11,ubuntu2104':
- test.ping
Para que possa ser executado os comandos, deve-se adicionar as opções -a (MÉTODO)
, vejamos alguns exemplos:
# Executando usando o pam (que foi definido no aquivo de configuração):
$ salt -a pam 'debian11' test.ping
username: admin
password:
debian11:
True
# Testando acesso num host que não demos permissão:
salt -a pam 'ubuntu2004' test.ping
username: admin
password:
Authorization error occurred.
# Aplicando o token:
$ salt -T -a pam 'debian11' test.ping
username: admin
password:
debian11:
True
# Agora já podemos executar comandos sem o '-T':
$ salt -a pam 'debian11' test.ping
debian11:
True
O benefício de usar este método é poder usar grupos de usuários para aplicar as permissões sem deixar claro no arquivo de configuração quem são os usuários. Dependendo do método de autenticação como Kerberos, LDAP usando como cliente o sssd
(FreeIPA), você pode usar o primeiro método demonstrado aqui que irá funcionar normalmente.
Criptografia assimétrica
No Salt a comunicação entre o Master e os Minions usa criptografia assimétrica para garantir a segurança da troca de informações. Isso garante que as comunicações sejam autenticadas e seguras. Quando um Salt Minion é iniciado pela primeira vez, ele gera um par de chaves assimétricas (uma chave pública e uma chave privada). A chave privada é mantida no Minion e nunca é compartilhada. A chave pública é enviada ao Salt Master.O Salt Master recebe a chave pública do Minion e a coloca em um estado "não aceito" até que o administrador faça a aceitação manualmente (pode ser configurado para aceitar automaticamente). Uma vez aceito, o Minion pode começar a executar comandos enviados pelo Master.
O Master também possui um par de chaves. O Minion valida a autenticidade do Master, prevenindo ataques como "man-in-the-middle". A comunicação entre Master e Minion é então criptografada usando AES (com chave rotativa), garantido que apenas o Minion e o Master aceitos podem decifrar as mensagens. A chave AES usada para criptografar as mensagens é rotacionada automaticamente a cada 24 horas ou quando o Master é reiniciado, reforçando a segurança e garantindo que Minions antigos ou não autorizados não possam continuar se comunicando.
Antes de aceitar uma chave de um Minion, é recomendado verificar se a chave que está sendo aceita é a chave pública real que reside no minion. O comando salt-key
pode imprimir a chave pública para que ela possa ser verificada facilmente em relação ao minion:
# Verifique a chave pública do servidor 'zion'. Consulta realizada no Master.
$ salt-key -p zion
Unaccepted Keys:
zion: -----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuvLGCeNGu9h0B2WEO0RD
LQXDtzYxEeO3o9w5kbxcMXDlU4RlrrG6C/F6Ho3ZFifhC08mb1oY5cNb5KIVzZ7s
BhjHlrdvdi0fDuuHNrZt3ecMQL5IgCt95aG3gHeooHY5LBcqPGhOumTb3g0g8z1z
FX50KzQLoOI0sIhHYiHInET8ui//FW72gHNE/GBGbNX7aloDEos7fZ0btKSv5JMh
Xw4lkSnJgl6mPeiWdgvh7c0tzd5TCSQqUpBkzMUBuayGlCVmN49WqjDWxjXVYxKI
e1knsNOnxXeGkxRIVwg+VjrdKYRlD9g4FnEcnIPNDjfrV+QZfRQ5VjDP0ymjw4/X
RwIDAQAB
-----END PUBLIC KEY-----
# Podemos verificar a assinaturas da chave. Consulta realizada no Master:
$ salt-key -f zion
Unaccepted Keys:
zion: 65:e9:4d:ff:87:6e:62:b7:ce:5e:cf:66:d3:02:cc:46:40:ef:35:f8:1f:62:ec:cf:2b:a2:4e:a7:eb:e6:15:ef
# No minion podemos ver o fingerprint dessa forma:
$ salt-call --local key.finger
local:
65:e9:4d:ff:87:6e:62:b7:ce:5e:cf:66:d3:02:cc:46:40:ef:35:f8:1f:62:ec:cf:2b:a2:4e:a7:eb:e6:15:ef
Uma vez que a chave pública do Minion é aceita pelo Master, as duas partes podem se comunicar de forma segura utilizando criptografia assimétrica combinada com criptografia simétrica. Quando o Salt Master envia um comando para o Minion, ele utiliza uma chave simétrica temporária (AES) para criptografar os dados do comando. Essa chave AES é então criptografada com a chave pública do Minion, garantindo que apenas o Minion, com sua chave privada, possa descriptografar a chave AES e, em seguida, usá-la para decifrar o conteúdo do comando enviado.
Quando o Minion responde ao Master, ele utiliza essa mesma chave AES para criptografar a resposta. O Master já tem a chave AES (que ele mesmo gerou no início da comunicação) e pode, portanto, descriptografar a resposta do Minion sem precisar usar sua chave privada. A criptografia assimétrica é utilizada principalmente para a troca inicial das chaves AES, enquanto a comunicação real de dados (tanto o envio quanto a resposta) é protegida por AES devido à sua eficiência.
# Podemos ver as chaves usadas no Master:
root@saltmaster:~# salt-key -F master
Local Keys:
master.pem: 7a:21:b3:8a:05:3d:23:1d:9d:81:8d:ce:9b:17:b2:dc:6a:68:a8:e5:5c:43:4d:45:a7:0c:c6:79:d2:d4:0a:b8
master.pub: e6:f5:46:37:cc:f1:12:e7:34:25:85:dd:59:61:49:e7:a3:79:88:47:a9:d5:64:b0:a2:39:81:66:9d:2b:64:25
As chaves públicas e privadas do Salt Minion são armazenadas no próprio Minion, em arquivos específicos. Por padrão, os arquivos estão localizados em:
- Chave privada:
/etc/salt/pki/minion/minion.pem
- Chave pública:
/etc/salt/pki/minion/minion.pub
No Master, a chave pública do Minion é armazenada no diretório /etc/salt/pki/master/minions_pre
. Nesse diretório, a chave é armazenada com o nome do Minion que a apresentou, aguardando aceitação manual (ou automática, caso configurado) pelo administrador. Uma vez aceita, a chave do Minion é movida para o diretório /etc/salt/pki/master/minions
, permitindo que o Minion e o Master se comuniquem de forma segura. Se o administrador rejeitar a chave, ela será colocada no diretório /etc/salt/pki/master/minions_rejected
.
Como já foi dito, a chave AES será alterada para todos os minions diariamente. Se a chave pública de um Minion for excluída ou rejeitada no Master (por exemplo, por causa de uma reinicialização do Minion, regeneração de chave, ou reinstalação), a chave AES também é rotacionada. Isso é feito para garantir que Minions não autorizados ou Minions antigos que tiveram suas chaves removidas não possam mais se comunicar com o Master.
Em certos casos, as chaves públicas e privadas do Salt Minion podem ser geradas novamente. Isso pode ocorrer, por exemplo, após uma atualização ou reinstalação do pacote salt-minion
ou quando o Minion é reconfigurado de forma significativa. Quando isso acontece, o Minion gera um novo par de chaves RSA (pública e privada), e a nova chave pública precisa ser aceita novamente pelo Salt Master para que a comunicação entre o Master e o Minion seja restabelecida.
Aceitando a chave do Minion no servidor Salt
A seguir vemos algumas opções mais utilizadas do comando salt-key
. Ele é o comando usado para gerenciar chaves de autenticação Salt Master.
Opções | Descrição |
---|---|
--version | Exibe a versão do Salt. |
-V, --versions-report | Exibe as dependencias do Salt, mais o numero da versão. |
-h, --help | Exibe a ajuda. |
-u USER, --user=USER | Especifica um usuário para rodar o salt-key. |
-y, --yes | Responde "Yes" para todas as perguntas. Padrão: False. |
-l ARG, --list=ARG | Lista as chaves publicas. Os argumentos 'pre', 'un', e 'unaccepted' vão listar as chaves unaccepted/unsigned. 'acc' ou 'accepted' vai listar as chaves accepted/signed. 'rej' ou 'rejected' vai listar chaves rejeitadas. 'den' ou 'denied' vai listar as chaves negadas. Finalmente, 'all' vai listar todas as chaves. |
-L, --list-all | Lista todas as chaves publicas. Descontinuado: use "--list all". |
-a ACCEPT, --accept=ACCEPT | Aceita uma chave publica especifica. Use --include-rejected e --include-denied para corresponder a chaves rejeitadas e negadas, além das chaves pendentes. Globs são suportados. |
-A, --accept-all | Aceita todas as chaves pendentes. |
-r REJECT, --reject=REJECT | Rejeita uma chave publica especifica. Use --include-accepted e --include-denied para corresponder a chaves aceitadas e negadas, além das chaves pendentes. Globs são suportados. |
-R, --reject-all | Rejeita todas as chaves. |
-p PRINT, --print=PRINT | Exibe uma chave especifica. |
-P, --print-all | Exibe todas as chaves publicas. |
-d DELETE, --delete=DELETE | Deleta uma chave publica especifica. Globs são suportados. |
-D, --delete-all | Deleta todas as chaves publicas. |
-f FINGER, --finger=FINGER | Exibe a impressão digital da chave especificada. |
-F, --finger-all | Exibe a impressão digital de todas as chave. |
Execute o comando salt-key --list-all
(sem o --list-all
exibe o mesmo resultado) para listar as chaves conhecidas pelo Salt Master:
# Listando todos os pedidos de conexão:
root@saltmaster:~# salt-key --list-all
Accepted Keys:
Denied Keys:
Unaccepted Keys:
saltminion
Rejected Keys:
Este exemplo mostra que o Salt Master está ciente de 1 minion, mas nenhuma chave foi aceita (Veja em Unaccepted Keys). Para aceitar uma chave e permitir que os minion seja controlado pelo Mestre, use novamente o comando salt-key
:
# Aceitar um minion:
root@saltmaster:~# salt-key -a saltminion
The following keys are going to be accepted:
Unaccepted Keys:
saltminion
Proceed? [n/Y] y
Key for minion saltminion accepted.
# Veja se o minion foi aceito:
root@saltmaster:~# salt-key --list-all
Accepted Keys:
saltminion
Denied Keys:
Unaccepted Keys:
Rejected Keys:
Primeiro comando remoto
Vamos fazer um teste de ping para verificar qual minion está "vivo", para isso vamos rodar o comando salt '*' test.ping
:
root@saltmaster:~# salt '*' test.ping
saltminion:
True
Nós podemos usar cmd.run
para rodar comandos livres no shell dos minions:
# Rodando um 'ls -lh':
root@saltmaster:~# salt '*' cmd.run 'ls -lh'
saltminion:
total 352K
-rw------- 1 root root 2.8K Aug 31 11:47 calc.sh
-rw------- 1 root root 50K Aug 31 16:15 dirs.tar
-rw-r--r-- 1 root root 294K Oct 21 09:01 install_salt.sh
# Rodando 'echo "123" '
root@saltmaster:~# salt '*' cmd.run 'echo "123"'
saltminion:
123
Módulos e Funções
O Salt fornece diversas funções prontas para a execução de comandos remotos, e essas funções são organizadas em módulos. Cada módulo agrupa funções específicas para diferentes tipos de tarefas de administração e automação. Essas funções estão agrupadas em módulos como file
, test
, pkg
, entre outros. Ao executar um comando no Salt, a sintaxe segue o formato modulo.função
. Por exemplo, o comando que fizemos acima salt '*' test.ping
, chama o módulo test e dentro dele usa a função ping.
Para listar todas as funções de um módulo, nós usamos a função list_function
que fica dentro do módulo sys
, execute o comando abaixo para ver as funções do módulo test
:
root@saltmaster:~# salt 'saltminion' sys.list_functions test
saltminion:
- test.arg
- test.arg_clean
- test.arg_repr
- test.arg_type
- test.assertion
- test.attr_call
- test.collatz
- test.conf_test
- test.cross_test
- test.echo
- test.exception
- test.false
- test.fib
- test.get_opts
- test.kwarg
- test.module_report
- test.not_loaded
- test.opts_pkg
- test.outputter
- test.ping
- test.provider
- test.providers
- test.raise_exception
- test.rand_sleep
- test.rand_str
- test.random_hash
- test.retcode
- test.sleep
- test.stack
- test.true
- test.try
- test.tty
- test.version
- test.versions
- test.versions_information
- test.versions_report
# Para ver todos os módulos podemos usar o comando abaixo:
root@saltmaster:~# salt '*' sys.list_modules
Para ver o menu de ajuda de uma função, seja ela qual for, use a função doc
que fica dentro do módulo sys
, passando para eles o modulo.função
como argumento (esse modulo.função é o que você quer consultar o menu de ajuda).
# Vamos fazer um exemplo exibindo o menu de ajuda da função Fibonacci,
# liste seu menu de ajuda:
root@saltmaster:~# salt 'saltminion' sys.doc test.fib
test.fib:
Return the num-th Fibonacci number, and the time it took to compute in
seconds. Used for performance tests.
This function is designed to have terrible performance.
CLI Example:
salt '*' test.fib 3
# Agora podemos ver como essa função trabaha, e tem até exemplo!
# Execute essa função 'fib' passando o valor 20:
root@saltmaster:~# salt 'saltminion' test.fib 20
saltminion:
- 6765
- 1.430511474609375e-06
Para ver todos os menus de ajuda do módulo test basta omitir a parte da função, como: salt '*' sys.doc test
.
salt '*'
e salt 'saltminion'
:Quando usamos o simbolo do asterisco *
, mais conhecido no Linux como um dos coringas, sua funcionalidade é dar match com todo conteúdo de uma lista, por exemplo, quando usamos ele no salt, ele quer dizer rode esse comando em todos os minions conhecidos. A outra alternativa é especificar o minion em que vamos executar o comando ou criar um grupo e rodar o comando para esse grupo.
Executando funções localmente com Salt-call
O comando salt-call
é utilizado para executar funções localmente em um Salt Minion, especialmente quando o Minion está rodando no mesmo servidor onde o Salt Master está instalado. Isso significa que, com salt-call
, você pode executar funções do Salt diretamente no próprio Minion, sem precisar de uma conexão ao Master. Por outro lado, o comando salt
é usado para enviar comandos remotamente do Master para outros Minions em hosts diferentes.
Esse comando foi concebido para que se possa executar comandos em um minion sem a necessidade de um master, dessa forma, ao invés de enviar comandos remotamente para os minions, pode ser que você esteja na cli de um dos minions e necessite executar algum comando, com salt-call
isso será possível.
Grains
O Salt oferece uma interface poderosa chamada grains para coletar informações detalhadas sobre os sistemas gerenciados (Minions). Os grains são basicamente dados que descrevem características específicas do sistema operacional, como nome de domínio, endereço IP, kernel, tipo de sistema operacional, memória, entre outras propriedades do hardware e software. Esses dados de grains são disponibilizados para os módulos e componentes do Salt, garantindo que os comandos executados nos Minions sejam adaptados ao ambiente correto, sem a necessidade de especificar detalhes manuais para cada sistema.
Embora os grains sejam considerados relativamente estáveis, eles podem ser atualizados se houver mudanças no sistema, como alterações de rede, ou caso grains personalizados sejam definidos. Um exemplo de grain importante é o os_family
, que define a família de sistemas operacionais a que o Minion pertence. Por exemplo, um servidor Ubuntu pertence à família Debian
, enquanto Fedora ou CentOS pertencem à família RedHat
.
Você pode consultar os grains de um Minion facilmente pela linha de comando. Veja um exemplo para recuperar a família de sistemas operacionais (os_family
):
root@saltmaster:~# salt '*' grains.item os_family
saltminion:
----------
os_family:
Debian
Para verificar o sistema operacional específico de um Minion, você pode usar os grains os
ou osfinger
.
root@saltmaster:~# salt '*' grains.item os
saltminion:
----------
os:
Debian
root@saltmaster:~# salt '*' grains.item osfinger
saltminion:
----------
osfinger:
Debian-9
# Usando o get:
root@saltmaster:~# salt '*' grains.get 'osfinger'
dedsec:
Ubuntu-22.04
zion:
Ubuntu-22.04
# Em outro servidor Salt:
salt '*' grains.item osfinger
zion:
----------
osfinger:
Ubuntu-22.04
dedsec:
----------
osfinger:
Ubuntu-22.04
salt '*' grains.item os
dedsec:
----------
os:
Ubuntu
zion:
----------
os:
Ubuntu
Sabendo qual sistema operacional seus Minions estão executando, você pode filtrar a execução de comandos apenas para sistemas específicos. Por exemplo, para enviar um ping somente para sistemas da família Debian, utilize o seguinte comando:
root@saltmaster:~# salt --grain 'os_family:Debian' test.ping
zion:
True
dedsec:
True
# Troque Debian pelo tipo de sistemas desejado!
Uma forma simplificada de escrever esse comando é usando a opção curta -G
:
root@saltmaster:~# salt -G 'os_family:Debian' test.ping
zion:
True
dedsec:
True
Se você deseja ver todos os grains de um Minion, pode usar o seguinte comando:
root@saltmaster:~# salt '*' grains.items
Além dos grains automáticos coletados pelo Salt, você pode definir grains personalizados para adicionar dados específicos ao sistema. Veja como criar e consultar um grain personalizado:
# Criando uma entrada no Grain:
root@saltmaster:~# salt '*' grains.setval teste funcionou
# Listando nossa entrada:
root@saltmaster:~# salt '*' grains.item teste
saltminion:
----------
teste:
funcionou
# Podemos usar JSON para criar uma estrutura de dados
# mais complexa e organizada!
Para deletar um grain personalizado, utilize a função grains.delval
. Após deletar o grain, você pode verificar se ele foi realmente removido também.
# Apagando a informação do Grain:
root@saltmaster:~# salt '*' grains.delval teste destructive=True
saltminion:
----------
changes:
----------
teste:
None
comment:
result:
True
# Consultando para ver se a informação existe:
root@saltmaster:~# salt '*' grains.item teste
saltminion:
----------
teste:
Os grains personalizados são armazenados localmente nos Minions no arquivo /etc/salt/grains
. Dessa forma, você pode criar, modificar e remover grains conforme necessário para personalizar as informações que o Salt coleta sobre cada Minion.
Combinação composta
A correspondência composta permite que você crie filtros mais granulares e complexos para selecionar os Minions com base em diversas condições. Isso possibilita a combinação de diferentes tipos de filtros usando operadores lógicos, como and
, or
, e not
. Veja um exemplo de uso de correspondência composta para enviar um comando de ping
, excluindo um Minion específico:
root@saltmaster:~# salt -C '* and G@os:Debian and not L@minion1' test.ping
saltminion:
True
# O exemplo abaixo remove 1 minion da lista de execução:
root@saltmaster:~# salt -C '* and G@os:Debian and not saltminion' test.ping
No minions matched the target. No command was sent, no jid was assigned.
ERROR: No return received
Aqui, o erro ocorre porque o Minion
saltminion
era o único na lista de execução, e foi removido.
Após ativado o salt minion no servidor master, vamos rodar de novamente o comando acima. Eu desativei para algumas documentações aqui, mas ele deve estar sempre ativado para que se possa rodar o comando salt-call
localmente no master.
root@saltmaster:~# salt -C '* and G@os:Debian and not saltminion' test.ping
saltmaster:
True
Perceba que ele executou em todos os minions *
, exceto o que nós pedimos para excluir and not saltminion
. Vamos dissecar um pouco mais a string enviada pelo comando salt:
'* and G@os:Debian and not L@yourminion,theirminion'
*
: Seleciona todos os Minions que foram aceitos pelo Master.G@os:Debian
: Filtra os Minions com o sistema operacional Debian, usando grains.and not L@yourminion,theirminion
: Exclui os Minions especificados.
Os operadores booleanos como and
, or
e not
permitem combinar condições complexas para a seleção de Minions. Além disso, é possível utilizar diferentes tipos de correspondência, como grains (G@
), lista de Minions (L@
), e até mesmo dados de Pillar (I@
).
Por padrão, as strings de correspondência são correspondidas usando a correspondência glob padrão. Assim, a parte com o *
especifica todos os minions.
Quanto ao resto dos tipos de correspondência, aqui está uma tabela, diretamente da documentação oficial do Salt, que enumera os possíveis tipos de correspondência e sua letra associada:
Letra | Tipo de partida | Exemplo |
---|---|---|
G | Grains glob | G@os:Ubuntu |
E | ID de minion PCRE | E@web\d+.(dev|qa|prod).loc |
P | Grains PCRE | P@os:(RedHat|Fedora|CentOS) |
L | Lista de minions | L@minion1.example.com,minion3.domain.com |
I | Pillar Glob | I@pdata:foobar |
S | Endereço de Rede/IP | S@192.168.1.0/24 or S@192.168.1.100 |
R | Range Cluster | R@%foo.bar |
Vamos lá:
* and G@os:Debian and not saltminion
`*`: Seleciona todos os Minions.
`and`: Combina a próxima condição com a anterior.
`G@os:Debian`: Filtra apenas os Minions que rodam Debian.
`and not saltminion`: Exclui o Minion chamado `saltminion`.
Colocando em palavras: Selecione todos os Minions aceitos, filtre aqueles que executam Debian, e exclua o Minion `saltminion` da lista.
Adicionando usuário
Vamos ver como funciona o módulo/função para criar um usuário:
root@saltmaster:~# salt '*' sys.doc user.add
user.add:
Add a user to the minion
name
Username LOGIN to add
uid
User ID of the new account
gid
Name or ID of the primary group of the new account
groups
List of supplementary groups of the new account
home
Home directory of the new account
shell
Login shell of the new account
unique
If not True, the user account can have a non-unique UID
system
Create a system account
fullname
GECOS field for the full name
roomnumber
GECOS field for the room number
workphone
GECOS field for the work phone
homephone
GECOS field for the home phone
other
GECOS field for other information
createhome
Create the user's home directory
loginclass
Login class for the new account (OpenBSD)
nologinit
Do not add the user to the lastlog and faillog databases
root
Directory to chroot into
usergroup
Create and add the user to a new primary group of the same name
CLI Example:
salt '*' user.add name <uid> <gid> <groups> <home> <shell>
# Podemos ver que somente o argumento nome é obrigatório!
Agora vamos criar um usuário chamado marcos:
root@saltmaster:~# salt 'saltminion' user.add marcos
saltminion:
True
# Agora vamos pegar informações dele no sistema:
root@saltmaster:~# salt 'saltminion' user.info marcos
saltminion:
----------
fullname:
gid:
1001
groups:
- marcos
home:
/home/marcos
homephone:
name:
marcos
other:
passwd:
x
roomnumber:
shell:
/bin/bash
uid:
1001
workphone:
# Vamos definir uma senha para nosso usuário:
root@saltmaster:~/openssl# salt '*' shadow.set_password marcos "$(openssl passwd -6 123)"
# Caso voce rode "openssl passwd -6 123" e de erro, você precisa atualizar o pacote do openssl ou compilar um pacote mais recente caso o seu seja o mais atual do seu repositorio.
# Esse comando vai criar um hash SHA256/SHA512, que é usado pelo linux atualmente.
Instalando pacotes
Como o gerenciamento de pacotes num sistema é muito importante e uma das tarefas mais comuns em ambientes Linux/Unix, o Salt possui um módulo chamado pkg, ele possui várias funções para se trabalhar com pacotes.
# Vamos ver as funções disponível para o módulo pkg:
root@SaltMaster:~\# salt 'slave1' sys.list_functions pkg
slave1:
- pkg.add_repo_key
- pkg.autoremove
- pkg.available_version
- pkg.del_repo
- pkg.del_repo_key
- pkg.expand_repo_def
- pkg.file_dict
- pkg.file_list
- pkg.get_repo
- pkg.get_repo_keys
- pkg.get_selections
- pkg.hold
- pkg.info_installed
- pkg.install
- pkg.latest_version
- pkg.list_downloaded
- pkg.list_pkgs
- pkg.list_repo_pkgs
- pkg.list_repos
- pkg.list_upgrades
- pkg.mod_repo
- pkg.normalize_name
- pkg.owner
- pkg.parse_arch
- pkg.purge
- pkg.refresh_db
- pkg.remove
- pkg.services_need_restart
- pkg.set_selections
- pkg.show
- pkg.unhold
- pkg.upgrade
- pkg.upgrade_available
- pkg.version
- pkg.version_cmp
# Para ver "help" da função install, use o comando abaixo:
salt 'slave1' sys.doc pkg.install
# Vamos instalar o unscd:
root@SaltMaster:~# salt '*' pkg.install unscd
slave1:
----------
unscd:
----------
new:
0.53-1build4
old:
slave2:
----------
unscd:
----------
new:
0.53-1build4
old:
Para ver os pacotes instalados, podemos usar a função list_pkgs.
# vou minimizar a saida por ser muito grande:
root@SaltMaster:~\# salt 'slave1' pkg.list_pkgs
slave1:
----------
accountsservice:
0.6.55-0ubuntu12~20.04.4
adduser:
3.118ubuntu2
alsa-topology-conf:
1.2.2-1
alsa-ucm-conf:
1.2.2-1ubuntu0.6
amd64-microcode:
3.20191218.1ubuntu1
apparmor:
2.13.3-7ubuntu5.1
apport:
2.20.11-0ubuntu27.16
apport-symptoms:
0.23
apt:
2.0.5
apt-utils:
2.0.5
Par remover, atualizar, consultar e marcar pacotes, podemos usar os comandos abaixo.
# Para remover um pacote e deixar os arquivos de configuração, usamos:
root@SaltMaster:~\# salt 'slave2' pkg.remove unscd
# Para remover um pacote e apagar também os arquivos de configuração, usamos:
root@SaltMaster:~\# salt 'slave2' pkg.purge
# Para ver informações sobre os pacotes instalados:
root@SaltMaster:~\# salt 'slave2' pkg.info_installed
# Similar a apt-cache, retorna a ultima versão disponível de um pacote, consultando os repositórios:
root@SaltMaster:~\# salt 'slave2' pkg.latest_version tmux
# Para listar todos os pacotes disponíveis para atualização, use:
root@SaltMaster:~\# salt 'slave2' pkg.list_upgrades
# Verificar se existe uma atualização para um pacote:
root@SaltMaster:~\# salt 'slave2' pkg.upgrade_available <pacote_nome>
# Lista os pacotes atualmente instalados, mostrando a versão:
root@SaltMaster:~\# salt 'slave2' pkg.list_pkgs
## Marcar um pacote como hold (impedir que esse pacote seja atualizado).
# No Linux:
root@slave2:~\# sudo apt-mark hold <pacote_nome>
alsa-ucm-conf set on hold.
# No SaltStack:
root@SaltMaster:~\# salt 'slave2' pkg.hold <pacote_nome>
## Desmarcar um pacote como hold (impedir que esse pacote seja atualizado).
# No Linux:
root@slave2:~\# sudo apt-mark unhold <pacote_nome>
# No SaltStack:
root@SaltMaster:~\# salt 'slave2' pkg.unhold <pacote_nome>
# Similar a apt-get update, Atualiza a base de dados do APT:
root@SaltMaster:~\# salt '*' pkg.refresh_db
# Similar a apt-get upgrade:
root@SaltMaster:~\# salt '*' pkg.upgrade
Gerenciando serviços
Para gerenciar serviços, inclusive baseado no Systemd, usamos o módulos service.
# Vamos ver se o serviço está rodando:
root@SaltMaster:~\# salt 'slave2' service.status sshd
slave2:
True
# Verificar se está ativo no boot:
root@SaltMaster:~\# salt 'slave2' service.enabled sshd
slave2:
True
# Para pegar uma lista com todos os serviços, use:
root@SaltMaster:~\# salt 'slave2' service.get_all
# Para pegar uma lista com todos os serviços desabilitados, use:
root@SaltMaster:~\# salt 'slave2' service.get_disabled
# Funciona como o systemd no quisito (start, stop, reload, restart).
Consultando o estado do Minion
Existem alguns módulos/funções que podemos consultar o estados dos minions, como: uso de disco, load average, consumo de memória, e uptime.
# Vamos consultar o uso de disco:
root@SaltMaster:~\# salt 'slave2' status.diskusage
slave2:
----------
/:
----------
available:
7869648896
total:
14725160960
/boot:
----------
available:
843243520
total:
1023303680
/dev:
----------
available:
996642816
total:
996642816
# Saída total ocultada devido ser muito grande.
# Vamos consultar o load average:
root@SaltMaster:~# salt 'slave2' status.loadavg
slave2:
----------
1-min:
0.0
15-min:
0.0
5-min:
0.0
# Vamos consultar o consusmo de memória ram:
root@SaltMaster:~\# salt 'slave2' status.meminfo
slave2:
----------
Active:
----------
unit:
kB
value:
276072
Active(anon):
----------
unit:
kB
value:
136952
Active(file):
----------
unit:
kB
value:
139120
# Saída total ocultada devido ser muito grande.
# Vamos consultar o uptime:
root@SaltMaster:~\# salt 'slave2' status.uptime
slave2:
----------
days:
0
seconds:
1463
since_iso:
2021-05-07T14:06:52.662925
since_t:
1620396412
time:
0:24
users:
1
Salt State
Embora o uso de comandos remotos no Salt seja poderoso para gerenciamento de máquinas, em larga escala, a execução direta de comandos individuais (conhecida como ad-hoc) pode ser ineficiente. Normalmente, não vamos apenas realizar uma ou duas tarefas simples, mas fazer mudanças maiores e mais significativas. Escrever scripts longos em Bash com múltiplos comandos do Salt não é uma boa prática, e o gerenciamento de várias tarefas repetitivas manualmente não é ideal.
Para resolver esse problema, o SaltStack inclui um gerenciador de configuração, que nos permite criar templates reutilizáveis e estruturados chamados de Salt States. Isso facilita a aplicação de configurações em múltiplos Minions de forma organizada e eficiente, evitando a necessidade de rodar comandos ad-hoc manualmente.
Arquivo de template
Os templates no Salt, chamados de arquivos SLS (SaLt State), são usados para definir o estado desejado de um ou mais Minions. Esses arquivos geralmente ficam localizados no diretório /srv/salt/
, mas essa localização pode ser ajustada no arquivo de configuração do Salt Master (/etc/salt/master
). Os arquivos SLS são executados de forma hierárquica, com um arquivo principal chamado top.sls
, que define quais estados devem ser aplicados a quais Minions. Arquivos init.sls
são usados para definir estados específicos dentro de subdiretórios, seguindo a organização dos templates.
Por exemplo, a estrutura de diretórios seria:
# Ordem de execução:
/srv/salt/
├── locales
│ └── init.sls
└── top.sls
# 1° será executado o arquivo top.sls, depois ele vai executar o que estiver configurado nele.
$ cat top.sls
base:
'*':
- locales
# base = Define o ambiente base.
# '*' = Indica que o estado será aplicado a todos os Minions.
# - locales = Faz referência ao arquivo `init.sls` dentro do diretório `locales`.
# É possível declarar vários minions no embiente base:
base:
'*':
- locales
'web*':
- pkg_add
Esse modelo estruturado permite reutilizar configurações, aplicá-las a múltiplos sistemas, e garantir que a mesma configuração seja aplicada de forma consistente.
O link salt.modules.state possui todos os módulos do SaltStack que podemos usar para criar nossos templates.
Formato YAML
Os arquivos SLS utilizam YAML, que é um formato de dados em chaves/valores, tornando-os fáceis de ler e escrever. A estrutura dos arquivos SLS é baseada em uma série de pares chave-valor que definem o estado de cada recurso, seja um pacote a ser instalado, um serviço a ser iniciado, ou uma configuração a ser aplicada.
No Salt, tudo gira em torno de dados. O YAML é apenas um formato de serialização que, em Python, representa uma estrutura de dados semelhante a um dicionário. Quando pensamos em como projetar arquivos SLS, é importante lembrar que eles funcionam como pares chave-valor: cada item tem uma chave única que é usada para referenciar um valor. Esse valor pode ser um único item, uma lista de itens, ou até outro conjunto de pares chave-valor. O elemento-chave de um bloco no arquivo SLS é chamado de ID. Se um nome específico não for declarado no bloco, o ID é usado como nome. IDs devem ser globalmente únicos, pois duplicatas causarão erros.
Criando um template
Para demonstrar o que foi dito até agora, vamos criar um template para instalação de alguns problemas. Antes de continuarmos, certifique-se de o diretório /srv/salt/
existam, caso contrrário, crie eles ou altere a localização no arquivo master do Salt.
Vamos criar o arquivo de topo.
root@SaltMaster:~\# vim /srv/salt/top.sls
# Coloque o texto abaixo no seu arquivo:
base:
'*':
- pkg_add
Com o arquivo principal do template pronto, precisamos criar o arquivo onde vamos colocar os pacotes a serem instalados.
Crie o diretório pkg_add
.
root@SaltMaster:~# mkdir /srv/salt/pkg_add
Agora crie e edite o arquivo dentro de pkg_add, o nome do arquivo deve ser init.sls.
root@SaltMaster:~\# vim /srv/salt/pkg_add/init.sls
# Cole o texto abaixo no seu arquivo:
Pacotes a serem instalados:
pkg.installed:
- pkgs:
- emacs
- vim
- apache2
Antes de executarmos o nosso template, é sempre bom fazermos um teste para ter certeza que nada irá dar errado.
Para isso execute salt '*' state.apply test=True
Para aplicar o template sem especificar o que acabamos de criar, podemos usar o módulo state, ele é usado para trabalharmos com os templates, e a função apply, se essa função for executada sem argumentos, ela irá passar o que está no arquivo de topo como argumento, executando tudo que tivermos lá.
Vamos executar nosso template:
root@SaltMaster:~\# salt '*' state.apply
slave2:
----------
ID: Pacotes a serem instalados
Function: pkg.installed
Result: True
Comment: The following packages were installed/updated: emacs, apache2
The following packages were already installed: vim
Started: 20:18:30.577006
Duration: 75723.434 ms
Changes:
----------
adwaita-icon-theme:
----------
new:
3.36.1-2ubuntu0.20.04.2
old:
apache2:
----------
new:
2.4.41-4ubuntu3.1
old:
apache2-bin:
----------
new:
2.4.41-4ubuntu3.1
old:
apache2-data:
----------
new:
2.4.41-4ubuntu3.1
old:
apache2-utils:
----------
new:
2.4.41-4ubuntu3.1
old:
____________________
| |
| Trecho Omitido ! |
|____________________|
Summary for slave2
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
Total run time: 75.723 s
Caso você não tenha um arquivo top.sls, pode ver a mensagem abaixo, verificando que ele é procurado:
No Top file or master_tops data matches found. Please see master log for details.
Segue algumas funções do módulo state:
# Verificando o módulo de topo:
root@SaltMaster:/srv/salt\# salt '*' state.show_top
slave2:
----------
base:
- locales
slave3:
----------
base:
- locales
# Mostrando apenas os states:
root@SaltMaster:/srv/salt\# salt '*' state.show_states
slave2:
- locales
slave3:
- locales
# Mostrando de forma detalhada um state:
root@SaltMaster:/srv/salt# salt '*' state.show_sls locales
slave2:
----------
default_locale:
----------
__env__:
base
__sls__:
locales
locale:
|_
----------
name:
en_US.UTF-8
- system
|_
----------
order:
10001
pt_locale:
----------
__env__:
base
__sls__:
locales
locale:
|_
----------
name:
pt_BR.UTF-8
- present
|_
----------
order:
10000
O bloco include
no Salt é usados para incluir outros arquivos SLS dentro de um arquivo SLS. Isso é útil quando você tem uma grande árvore de arquivos SLS e deseja reutilizar configurações existentes em diferentes contextos. No topo de um arquivo SLS, você pode usar um bloco include
para referenciar outros arquivos SLS que serão importados. Veja um exemplo:
include:
- base
- emacs
Aqui, o arquivo SLS atual irá incluir os arquivos base.sls
e emacs.sls
. Se um arquivo chamado base/init.sls
ou emacs/init.sls
existir, eles também serão considerados. Um ponto importante é que os arquivos SLS incluídos não podem conter IDs duplicados. Ou seja, se o arquivo atual já tiver um estado com um determinado ID, e o arquivo incluído também tiver um estado com o mesmo ID, isso causará um erro. O bloco include
é uma declaração de nível superior e só pode aparecer uma vez em cada arquivo SLS.
A opção require
A diretiva require
é usada para criar dependências entre estados, garantindo que um determinado estado seja executado antes de outro.
/root/.vimrc:
file.managed:
- source: salt://vim/files/vimrc
- user: root
- group: root
- mode: 644
- require:
- install_vim
install_vim:
pkg.installed:
- name: vim
# '- install_vim' e '- pkg: install_vim' sao iguais, você pode passar o módulo e pode não passar.
No exemplo acima, o arquivo de configuração do Vim (/root/.vimrc
) só será transferido se o pacote do Vim (identificado pelo ID install_vim
) estiver instalado. Se o pacote não estiver instalado ou a instalação falhar, o arquivo de configuração não será transferido. A partir da versão 2016.3.0, o nome do módulo pode ser omitido, e o Salt identificará automaticamente o estado correspondente pelo ID. Nesse caso, o uso de apenas install_vim
ou pkg: install_vim
(abaixo de require
) resultará no mesmo comportamento, pois o ID já está associado ao estado de instalação do pacote.
Para mais detalhes, leia aqui.
Vale ressaltar que os nomes mencionados acima (install_vim) e o ID, podem ser usado como argumentos, no caso da transferência do arquivo, o ID também e o caminho para onde o arquivo deva ser enviado, caso o ID não corresponda a um atributo da função, devemos usar o atributo - name:
no lugar. Exemplo:
install_vim_package:
file.managed:
- name: /root/.vimrc
- source: salt://vim/files/vimrc
- user: root
- group: root
- mode: 644
- require:
- install_vim
install_vim:
pkg.installed:
- name: vim
A opção watch
A opção watch
é usada para criar dependências entre estados, de forma semelhante ao require
, mas com uma diferença importante, o watch
só aciona o estado dependente quando há uma mudança no estado monitorado. Basicamente, enquanto o require
sempre garante que a dependência seja executada antes, o watch
faz com que o estado dependente só seja executado se houver uma alteração no estado que está sendo monitorado. Exemplo
ntpd:
service.running:
- watch:
- file: /etc/ntp.conf
file.managed:
- name: /etc/ntp.conf
- source: salt://ntp/files/ntp.conf
No exemplo acima, o serviço ntpd
só será reiniciado ou recarregado se houver uma alteração no arquivo de configuração /etc/ntp.conf
. Caso o arquivo seja modificado (por exemplo, substituído ou atualizado), o estado service.running
será reavaliado e, se necessário, o serviço será reiniciado para aplicar as novas configurações. Se não houver nenhuma alteração no arquivo, o serviço ntpd
não será reiniciado.
Alguns módulos contém
mod_watch
, ele sempre deve estar presente nowatch
, caso não esteja, o módulowatch
terá o mesmo comportamento do módulorequire
.