Laboratório de Puppet Task
Estudo e testes do Puppet Task
Em outubro de 2017 a Puppet apresentou a sua nova aposta, o Puppet Tasks. Com isso a Puppet tenta cobrir uma lacuna que sua ferramenta apresentava com relação a workflow de tarefas.
Nesse Lab, vamos seguir o seguinte conteúdo para conhecer sobre o puppet task.
Introdução ao Puppet Task
Conhecendo o bolt
Criação e definição de nodes
Provisionando em Vagrant
Provisionando em Docker
Manipulando os nodes
Rodando comandos Shell nos nodes Linux
Rodando comandos PowerShell no node Windows
Rodando Scripts no Linux
Rodando Scripts no Windows
Usando Package e Services
Escrevendo as Tasks
Tasks com parâmetros
Controlando parâmetros com metadata
Tasks com tratamento de error
Escrevendo os Plans
Todos os códigos estão no repostório do https://github.com/clodonil/puppet-tasks.git.
1. Introdução ao Puppet Task
Puppet é uma ferramente de gestão de configurações. Ela mantem o estado desejado de um servidor. O Puppet garante que o resultado/estado final é o desejado, mais não garante a ordem da execução das tarefas.
Para controlar as ordens de execução é necessário utilizar recursos tais como before/require e notify/subscribe o que é praticamente enviável em ambientes complexos.
Visando essa lacuna a Puppet lançou o recursos de Tasks, também conhecido com o Puppet Tasks.
Basicamente o Puppet Tasks é um conjunto de funções, tais como executar comandos remotamente, enviar arquivos, executar scripts, executar tarefas, gerenciar serviços e instalar pacotes.
Todas essas funções podem ser executadas ad-hoc, diretamente em um node. Além de executar ad-hoc os comandos, é possível criar um Plan que orquestra um conjunto de funções de forma ordenada, criando uma infinidades de possibilidades, e mais diretamente um forma poderosa de fazer deploy.
A Puppet disponibilizou no Puppet Enterprise, apenas os recursos de tasks, services e package. E também lançou uma ferramenta opensource chamado puppet-bolt que possuem todos os outros recursos e utiliza o ssh/winrm para se comunicar com os nodes.
Portanto para esse estudo estaremos utilizando o bolt.
Para execução dos Plans e das Tasks não é necessário ter instalado o Puppet e nem o Puppet Enterprise, apenas o bolt. O computador com o bolt instalado recebe o nome de manager, nenhum outro recurso do Puppet é necessário para execução desse lab.
Todas as tasks e plans escritos para serem executados com o bolt, mantém 100% de compatibilidade com o Puppet Enterprise.
1.1 Instalação no Centos 7
Para instalação no Centos 7, primeiramente instale o repositório do puppet e em seguida instalar o puppet-bolt.
$ rpm -ivh http://yum.puppet.com/puppet5/puppet5-release-el-7.noarch.rpm
$ yum install puppet-bolt
1.2 Instalação no Windows
No windows é possível instalar o pacote compilado msi através do seguinte link Puppet-Bolt.
Também é possível instalar através do chocolaty:
C:\> choco install Ruby
C:\> refreshenv
C:\> gem install puppe-bolt
1.3. Conhecendo o Bolt
Com o Bolt instalado execute o bolt --help para mostrar todas as opções do bolt.
Bolt command run Executa comandos remotamente
bolt file upload Upload de arquivos
bolt script run Upload do script e executa remotamente
bolt task show Mostra a lista das tasks disponíveis
bolt task show	Mostra a documentação de uma task
bolt task run Executa uma task puppet
bolt plan show Mostra a lista de plan disponível
bolt plan show	Mostra a documentação de um plan
bolt plan run Executa um Plan escrito em Puppet
-n, –nodes Identifica o node alvo
–noop Executa uma tasks/comando/script em modo noop (simulação)
-u, –user Usuário para autenticação SSH/Winrm
-p, –password Senha do usuário para autenticação
–private-key Chaves SSH para autenticação
Elevação de acesso:
–run-as Usuário que será utilizado para elevação de acesso.
–sudo-password Senha para elevação de acesso com sudo
-c, –concurrency Número máximo de conexão simultânea (default 100)
–modulepath Lista de diretórios dos módulos, separados por ",".
–configfile Especifica o path do arquivo de configuração do bolt (default ~/.puppetlabs/bolt.yaml
–inventoryfile Especifica o path do arquivo de inventário. (default ~/.puppetlabs/bolt/inventory.yaml
–transport Define o protocolo de transporte ssh, winrm,pcp, local;
–connect-timeout Timeout de conexão
–[no–]tty Ativa o pseudo terminal.
–tmpdir Define o arquivo temporário para upload dos arquivos para execução nos nodes.
Muitos dos parâmetros podem ser configurados diretamente no arquivo do bolt, simplificando a execução do comando.
Um exemplo do arquivo ~/.puppetlabs/bolt.yaml:
modulepath: "/opt/modules:/etc/puppet/code/modules"
private-key: ~/.ssh/bolt_id
2. Criação e definição de nodes
Para realização deste laboratório será utilizado 2 nodes em Linux (Centos 7) e um node Windows. Nos servidores Linux a comunicação será realizada utilizando o SSH e no Windows o WinRM.
Existe várias formas de realizar o provisionamento dos nodes, nesse lab usaremos o provisionamento em Docker e Vagrant com Virtualbox. O adotado para o restante do lab será o vagrant.
2.1 Provisionando em Vagrant
Considerando que o virtualbox e o vagrant está instalado, crie o Vagrantfile no diretório ~/puppet-task com o seguinte conteúdo.
$node_count = 2
(1..$node_count).each do |id|
config.vm.define "node#{id}" do |nodes|
nodes.vm.hostname = "node#{id}"
nodes.vm.network :private_network, :ip => "10.20.1.#{10+id}"
nodes.vm.provision :hosts, :sync_hosts => true
# Node of Windows
windows.vm.network "private_network", ip: "10.20.1.20"
windows.vm.provision :hosts, :sync_hosts => true
# Puppet Tasks - Bolt
config.vm.define :bolt do |bolt|
bolt.vm.hostname = "bolt"
bolt.vm.network :private_network, :ip => "10.20.1.100"
bolt.vm.provision :hosts, :sync_hosts => true
# Install of Puppet Bolt
bolt.vm.provision "shell", inline: "rpm -ivh http://yum.puppet.com/puppet5/puppet5-release-el-7.noarch.rpm &&  yum -y install puppet-bolt"
Os seguintes plugins do vagrant devem estar instalados:
vagrant-hosts (2.8.2)
winrm (2.2.3)
winrm-elevated (1.1.0)
winrm-fs (1.2.0)
Uma rápida explicação sobre o Vagrantfile, caso você não esteja familiarizado com essa tecnologia. A variável $node_count define a quantidade de nodes que serão criadas do centos 7 e a comunicação via SSH. Também está sendo provisionado uma máquina Windows (Nano Server) com a comunicação WinRM.
A vm "bolt" será utilizado como manager para gerenciar os outros nodes. Para isso é necessário que essa vm acesse todas as outras. Para tornar isso possível, copie a chave de acesso para a pasta do puppet-task:
$ cp ~/.vagrant.d/insecure_private_key /puppet-task/
Para aplicar a configuração do vagrantfile e criar as máquinas virtuais, execute o comando:
$ vagrant up node1 node2 windows bolt
Uma forma rápida de acesso com o SSH ao nodes provisionados é criando um arquivo de ssh-config.
Para isso acesse a vm bolt ("vagrant ssh bolt"), e como root crie o arquivo "generate-ssh.sh" e execute para criar o arquivo /root/.ssh/config.
echo "" > /root/.ssh/config
ip=$(echo $line | awk {'print $1'})
host=$(echo $line | awk {'print $2'})
echo "Host $host" >> /root/.ssh/config
echo "    HostName $ip" >> /root/.ssh/config
echo "    User vagrant" >> /root/.ssh/config
echo "    Port 22" >> /root/.ssh/config
echo "    PasswordAuthentication no" >> /root/.ssh/config
echo "    IdentityFile /vagrant/insecure_private_key" >> /root/.ssh/config
echo "    IdentitiesOnly yes" >> /root/.ssh/config
echo "    LogLevel FATAL" >> /root/.ssh/config
echo "    ForwardAgent yes"   >> /root/.ssh/config
done  < /etc/hosts
Executando o arquivo:
$ chmod +x generate-ssh.sh
$ ./generate-ssh.sh
Para testar a conexão com os nodes:
2.2 Provisionando em Docker
Usando o docker também é possível provisionar os nodes Linux de forma rápida. Para isso edit o arquivo docker-compose.yml e tenha instalado o docker.
Execute o seguinte comando para provisionar o servidor ubuntu com SSH.
Caso você queira mais servidores, pode utilizar o –scale para determinar a quantidade de nodes.
$ docker-compose up --scale ssh=3 --detach
Não tem importância a forma de provisionar, basicamente os nodes Linux precisam ter SSH e WinRM nos servidores Windows. Portanto provisione da forma que você achar melhor.
3. Manipulando os nodes
Nos nodes provisionados é possível executar comandos, fazer upload de arquivos, rodar scripts e executar tasks e Plans.
Tasks são tarefas (scripts) que serão executada nos nodes. A principal diferença entre as tasks e scripts é que as tasks recebem parâmetros e os parâmetros podem podem ser controlados.
3.1 Rodando comandos shell nos nodes Linux
Para executar comandos ad-hoc do bolt:
$ bolt command run --nodes
Como exemplo, é executado primeiramente o comando 'uptime' para retornar o tempo que o servidor está trabalhando:
$ bolt command run 'uptime' --nodes node1
Started on node1...
Finished on node1:
13:30:04 up 14:56,  0 users,  load average: 0.02, 0.03, 0.05
Successful on 1 node: node1
Ran on 1 node in 0.72 seconds
Em caso de erro Host key verification failled, existe um conflito de chaves do SSH, é preciso apagar as entradas relacionadas no arquivo ~/.ssh/sshd_hosts.
Também é possível executar comandos em múltiplos nodes ao mesmo tempo.
$ bolt command run 'uptime' --nodes node1,node2
Started on node2...
13:30:37 up 14:57,  0 users,  load average: 0.01, 0.03, 0.05
Finished on node2:
13:30:37 up 14:55,  0 users,  load average: 0.00, 0.01, 0.05
Successful on 2 nodes: node1,node2
Ran on 2 nodes in 0.71 seconds
Para grandes números de nodes ou para agrupa-lós é necessário a criação do arquivo de inventory.yaml. Crie esse arquivo no diretório ~/.puppetlabs/bolt.
nodes: [ node1, node2 ]
Em casos específicos, os nodes podem solicitar senha para autenticação, nesse caso é possível passar as informações ad-hoc na execução do bolt ou através da inclusão dos acessos no arquivo inventory.yaml.
$bolt command run --nodes all --user --password
E no inventory:
Nodes: [node1, node2, node3]
user    : <login>
3.2 Rodando comandos PowerShell no node Windows
O bolt executa os comandos no Windows através do WinRM, conforme já mencionado anteriormente.
$ bolt command run < comando> –nodes winrm:// --user --password
No parâmetros WinRM é informado o endereço do servidor Windows. E caso seja necessário informar o usuário e senha, utilize o "–user" e o "–password".
O bolt por padrão ativa a comunicação com SSL para comunicação com o WinRM, caso o servidor Windows não esteja com o SSL ativo, a conexão não vai ser realizado e uma mensagem de erro de comunicação será apresentado ("Unknown Protocol").
Para resolver esse erro é necessário ativar o SSL no WinRM no servidor Windows ou desativar a utilização do SSL pelo bolt através da opção '–no-ssl'.
Para simplificar a sintaxe do comando, será criado uma variável "WIN" com o endereçamento do WinRM.
WIN="winrm://vagrant:[email protected]:5985"
A chamada do comando bolt fica mais limpa:
$ bolt command run "gps | select ProcessName" --no-ssl --nodes $WIN
Started on windows...
Finished on windows:
##3.3 Rodando scripts no Linux Com o bolt é possível executar qualquer tipo de scripts, desde o compilador/interpretador esteja presente no node. Perceba que não é necessário ter o interpretador no servidor manager.
A sintaxe para executar scripts:
$ bolt script run
Nesse Lab vamos utilizar, bash para Linux e PowerShell para Windows.
Como exemplo de execução de script, será executado um harderning do Centos7.
Faça o download do script no diretório /root/scripts. É necessário criar esse diretório.
$ curl -O https://raw.githubusercontent.com/naingyeminn/CentOS7_Lockdown/master/centos7.sh
O script de hardening aplica um conjunto de configurações para tornar o linux mais seguro. Devido o script alterar arquivos protegidos, é necessário ter acesso de root nas VMs. Dessa forma, informa o parâmetro "–run-as" para elevação de acesso:
$ bolt script run /root/script/centos7.sh --run-as root -n all
Disabling Legacy Filesystems
Removing GCC compiler...
Removing legacy services...
Disabling LDAP...
Disabling DNS...
Disabling FTP Server...
Disabling Dovecot...
Disabling Samba...
Disabling HTTP Proxy Server...
Ao executar o script pelo bolt, primeiramente é feito o download nos nodes antes de executar.
3.4 Rodando scripts no Windows
Todos os administradores de sistema já têm um conjunto de scripts para serem executados nos servidores. Esses scripts podem ser reutilizados e serem facilmente aplicados em um conjunto de servidores. Caso você tenha um desses scripts pode utiliza-ló. Nesse exemplo vamos utilizar um script simples para teste de conexão.
Salve o conteúdo a seguir com o nome '/root/script/testconnection.ps1":
Test-Connection -ComputerName "example.com" -Count 3 -Delay 2 -TTL 255 -BufferSize 256 -ThrottleLimit 32
$ bolt script run /root/script/testconnection.ps1 --no-ssl -n $WIN
3.5 Upload de arquivo
Um dos recursos normalmente utilizado na administração de servidores é o upload de arquivos. Normalmente durante um deploy é necessário enviar o pacote da aplicação para os servidores ou um conjunto de configuração conforme o ambiente.
A sintaxe do upload de arquivo:
$ bolt file /local_dir/file /server_dir/file –nodes all
Para enviar uma atualização de pagina html para o servidor nginx, fica dessa forma:
Crie o arquivo /root/files/index.html com qualquer conteúdo.
$ bolt file upload /root/files/index.html /tmp/index.html --nodes node1
Uploaded '/root/files/index.html' to 'node1:/tmp/index.html'
Ran on 1 node in 1.14 seconds
3.6 Usando Package
Através do bolt é possível gerenciar pacotes e servidores. No exemplo a seguir é instalado o pacote "httpd" no node node1. As opções possíveis do parâmetro "action" são "install/status/unistall/upgrade".
$ bolt task run package action => 'install', name => 'httpd', version => latest --nodes web
Além de gerenciar os pacotes, também é possível gerenciar os serviços. As opções do parâmetros action são "start/stop/restart/enable/disable/status".
$ bolt task run service action => status  name => httpd --nodes all
Para o bolt utilizaros pacotes e módulos do Forge, é necessário instalar a ferramenta r10k.
4. Escrevendo Tasks
Igualmente aos scripts, as tasks podem ser escritos em qualquer linguagem de programação, desde que seja possível executar no node.
As tasks devem ser utilizadas como um módulo do Puppet. Isso significa que podem ser manipuladas pelo Forge e também gerenciadas pelas ferramentas existentes do Puppet.
Por padrão as tasks recebem argumentos como variável de ambiente prefixadas com PT (Puppet Tasks), tais como "$PT_exemplo".
As tasks devem ser criadas no diretório "tasks" dentro do módulo. Um módulo pode ter várias tasks, mas a tasks "init" é especial. Será executada caso nenhum nome de tasks seja passado durante a chamada do módulo.
Por exemplo, o módulo "exercicio1" e a tasks deploy em "exercicio1/tasks/deploy.sh", tem o nome composto de exercicio1::deploy. O nome funciona como referência a tasks para ser executada.
As tasks também pode ter metadata que valida os argumentos de entrada e controla como as tasks vai ser executada. A definição das entradas de parâmetros no metadata também é uma forma de reduzir o risco de segurança.
Como exemplo de tasks, crie o arquivo init.sh no diretório '/modules/exercicio1/tasks':
interface=$PT_interface
ip=$(/sbin/ip add show $interface | grep "inet\b" | awk '{print $2}' | cut -d / -f 1 )
Para executar a tasks padrão (init). Utilize o seguinte comando:
$ bolt task run exercicio1 interface=eth0 --nodes all --modulepath /modules/
eth0:10.0.2.15
Ran on 2 nodes in 1.21 seconds
Como o nome da tasks é "init", foi passado apenas o nome do módulo com o argumento interface que dentro do script fica como "PT_interface".
Tasks mais elaboradas desenvolvidas em outras linguagens como Python e Ruby podem retornar dados mais estruturados (não estou dizendo que em bash não seja possível).
Usando o exemplo do módulo exercicio1, crie mais uma tasks com o nome gethost.py com o seguinte conteúdo.
host = os.environ.get('PT_host')
result = { 'host': host }
result['ipaddr'] = socket.gethostbyname(host)
result['hostname'] = socket.gethostname()
# The _output key is special and used by bolt to display a human readable summary
result['_output'] = "%s is available at %s on %s" % (host, result['ipaddr'], result['hostname'])
# The _error key is special. Bolt will print the 'msg' in the error for the user.
result['_error'] = { 'msg': 'No host argument passed', 'kind': 'exercise5/missing_parameter' }
Pode executar a tasks da seguinte forma:
$ bolt task run exercicio1::gethost host="google.com" --nodes all --modulepath /modules/
google.com is available at 216.58.202.238 on node2
"ipaddr": "216.58.202.238"
google.com is available at 172.217.30.110 on node1
"ipaddr": "172.217.30.110"
Ran on 2 nodes in 1.20 seconds
Nesse exemplo um pré-requisito para execução do script é a presença do python no nodes.
4.1 Tasks com Parâmetros
As tasks recebem os parâmetros basicamente através de variável de ambiente (environment) ou através de entrada padrão (stdin). A escolha do método de passagem de parâmetros interfere diretamente na escrita do metadata e também no desenvolvido do próprio script.
A seguir temos alguns exemplos de recebimento de parâmetros em bash, ruby, python e PowerShell com passagem de parâmetros em stdin e environment. Para esses exemplos, crie o diretório exercicio2 no diretório modules.
Tasks em bash com env:
#filename: tasks_env_bash.sh
params=$PT_params
Tasks em bash com stdin:
#filename: tasks_stdin_bash.sh
Comando para execução da tasks:
$ bolt task run exercicio2::tasks_env_bash params=10 --nodes all --modulepath /modules/
Tasks em python com env:
#filename: tasks_env_python.py
Tasks em python com stdin:
#filename: tasks_stdin_python.py
host=input()
$ bolt task run exercicio2::tasks_env_python host="server1" --nodes all --modulepath /modules
Tasks em ruby com env:
#filename: tasks_env_ruby.rb
params = ENV["PT_valor"]
puts("Parâmetro: #{params}")
Tasks em ruby com stdin:
#filename: tasks_stdin_ruby.rb
params = STDIN.read
puts("Parâmetros: #{params}")
Comando para executar a tasks Ruby:
$ bolt task run exercicio2::tasks_env_ruby valor=10 --nodes all --modulepath /modules
Tasks em PowerShell
Sintaxe para execução da tasks no windows:
$ bolt task run exercicio2::tasks_powershell --no-ssl --nodes $WIN --modulepath /modules
$ bolt task run exercicio2::tasks_powershell name=System --no-ssl --nodes $WIN --modulepath /modules
Sempre estamos passado o caminho que estão localizados os módulos, entretanto podemos adicionar essa informação no arquivo ~/.puppetlabs/bolt/bolt.yaml.
modulepath: "/modules/"
4.2 Controlando parâmetros com metadata
Com os metadata é feito a documentação da tasks e também o controle dos parâmetros de entrada. O controle de parâmetros é importante para diminuir o risco de entrada de valores não desejáveis.
A tabela a seguir, mostra os parâmetros e os valores padrões da configuração do arquivo de metadata.
description Descrição da função da tasks String None
puppet_task_version A versão da tasks Integer 1
supports_noop Quando a tasks suporta noop Boolean False
input_method As opções de passagem de parâmetros para a tasks environment,
stdin,powershell stdin
parameters Tipo de dados do Puppet Tipo Puppet None
O metadata podem aceitar muitos tipos de dados no campo "parameters". A tabela seguinte mostra os mais comuns usadnos por tasks.
String Aceita qualquer String.
String[1] Aceita qualquer String não vazia.
Enun[opcao1, opcao2] Aceita parâmetros de uma lista possível
Pattern[/\A\W+\Z/] Aceita String que validas pelas expressão regular [/\A\W+\Z/]
Integer Aceita valores Inteiros.
Optional[String[1]] Aceita a opção de uma lista e também permite valores nulos.
Array[String] Aceita um Array de String.
Hash	Aceita um objeto Json.
Variant[Integer, Pattern[/\A\W+\Z/]] Aceita valores que aceita a expressão regular.
O script "install.sh", exemplifica a utilização do metadata. O script basicamente faz a instalação do openjdk com a opção de desinstalar a versão antiga.Pelo metadata deve ser realizado os seguintes controles:
A versão do openjdk deve ser homologada anteriormente;
A opção de desinstalação seja binária (yes ou no);
O script é feito normalmente, sem nenhum controle de parâmetro; Crie o diretório /modules/exercicio3/tasks.
uninstall="no"
version=$(echo $PT_version | sed s/_/./g)
uninstall=$PT_uninstall
old=$(rpm -qa | grep "openjdk")
pacote="java-$version-openjdk"
yum install -y $pacote &> /dev/null
echo "Instalado $pacote"
echo "Problema na Instalado do $pacote"
if [ "$uninstall" == "yes" ]; then
rpm -e $old
echo "Desinstalado $old"
echo "Problema na Desinstalacao do $pacote"
O arquivo de JSON deve ter o mesmo nome do script, "install.json". A opção "description" descreve o funcionamento do script e no campo "parameters" é possível controlar as entradas.
No exemplo, o parâmetro "version" obrigatoriamente deve ter um dos valores da lista (1_6_0, 1_7_0, 1_8), Igualmente o parâmetros "uninstall" deve ser "yes' ou "no".
Coloquei as versão do java (16_0, 1_7_0…), porque no arquivo de metadata na versão da elaboração desse LAB não aceitava o ponto "(1.6.0, 1.7.0…)" e a troca do "" pelo "." foi realizado no script.
Segue o arquivo do metadata install_openjdk.json.
"description" : "Instalação e Desinstalação do OpenJDK",
"input_method": "environment",
"description": "Versão do Java Homologado para instalação",
"type": "Enum['1_6_0','1_7_0','1_8_0']"
"uninstall":{
"description": "Desinstall versões antigas",
"type": "Enum[yes,no]"
Rodando o script:
bolt task run exercicio3::install version=1_8_0 uninstall=no --nodes all
Instalado java-1.8.0-openjdk
Ran on 2 nodes in 2.01 seconds
4.3 Tasks com tratamento de erro
Quando uma task é finalizada com um código diferente de zero, o puppet-tasks verifica uma chave de erro ("_error"). Se essa chave não estiver presente, um erro genérico será adicionado ao campo de retorno. Se não houver texto na saída padrão (stdout), mas se tiver presente no stderr, o texto stderr será incluído na mensagem.
A estrutura da chave de erro:
"msg"   : "Falha na task",
"king"  : "puppetlabs.tasks/tasks-errror",
"details: " { "exitcode" :1 }
A estrutura da mensagem de erro é composta dos seguintes campos:
msg : Mensagem amigável sobre o erro,
kind : Mensagem mais detalhada e avançada. Mensagem pode ser compartilhada entre os módulos.
details : Um objeto estruturado sobre a tasks.
A seguir um exemplo da utilização de tratamento de erro:
file = os.environ.get('PT_filename')
open_file = open(filename, "r")
conteudo  = open_file.readlines()
"msg" : "Problema ao abrir o arquivo {0}".format(filename),
"kind": "myproj/task-error",
"details": {"exitcode": 1},
5. Escrevendo Plan
O Plan é escrito utilizando a linguagem do Puppet, e nele pode ser vinculado a um conjunto de comandos, scripts pacotes, tasks e a outros plan, facilitando a reutilização de código. Os plan executa a lógica localmente e os comandos/scripts/tasks são executados remotamente.
Apesar do plan ser escrito utilizando a linguagem do Puppet, não é necessário ter o puppet instalado no manager.
O plan pode executar as seguintes funções:
run_command: Roda um comando em um ou mais nodes;
file_upload: Faz upload de arquivos para um ou mais nodes;
run_script: Roda um script ( não é uma tasks);
run_tasks: Roda uma task em um ou mais nodes;
run_plan: Roda um plan em um ou mais nodes;
Vamos para um exemplo simples para entender como funciona o plan. Para isso crie o seguinte arquivo /modules/exercicio4/plans/comandos.pp.
plan exercicio4::comandos (TargetSpec $nodes){
run_command("uptime", $nodes)
Nesse exemplo o plan basicamente executa um comando.
Para rodar o plan:
$ bolt plan run exercicio4::comandos --nodes all
Starting: command 'uptime' on node1, node2
Finished: command 'uptime' with 0 failures in 0.78 sec
Perceba que os nodes são passados pelo TargetSpec, além dos nodes outros parâmetros podem ser utilizado.
Além de comandos é possível executar as tasks e incluir lógica/controle de verificação dentro dos plans, conforme mostra o exemplo a seguir: