Substituir a variável de hosts do playbook Ansible na linha de comando

110

Este é um fragmento de um manual que estou usando ( server.yml):

- name: Determine Remote User
  hosts: web
  gather_facts: false
  roles:
    - { role: remote-user, tags: [remote-user, always] }

Meu arquivo hosts tem diferentes grupos de servidores, por exemplo

[web]
x.x.x.x

[droplets]
x.x.x.x

Agora desejo executar ansible-playbook -i hosts/<env> server.ymle substituir hosts: webde server.ymlpara executar este manual [droplets].

Posso apenas substituir como uma coisa única, sem editar server.ymldiretamente?

Obrigado.

luqo33
fonte

Respostas:

128

Não acho que o Ansible ofereça esse recurso, o que deveria. Aqui está algo que você pode fazer:

hosts: "{{ variable_host | default('web') }}"

e você pode passar variable_hostda linha de comando ou de um arquivo vars, por exemplo:

ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
Wallydrag
fonte
3
Uma pequena correção necessária. Deveria serhosts: "{{ variable_host | default('web')}}"
SPM
16
Aqui está uma nota que acho que completaria a resposta para iniciantes ansible que procuram por esta solução: Exemplo:ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
Frobbit
1
QUANDO (isto é, em que ordem) o ansible analisa as variáveis ​​As variáveis ​​em group_vars/allparecem ser analisadas após a hosts:linha do manual. No entanto, as variáveis ​​em vars:e as variáveis ​​em vars_files:são analisadas antes da hosts:linha? NOTA estou não perguntando sobre precedência.
Felipe Alvarez
2
Você também pode usar em -evez de --extra-vars.
substantivo
Veja as outras respostas para mais detalhes
Anand Varkey Philips
63

Para quem vier à procura da solução.
Livro de cantadas

- hosts: '{{ host }}'
  tasks:
  - debug: msg="Host is {{ ansible_fqdn }}"

Inventário

[web]
x.x.x.x

[droplets]
x.x.x.x

Comando: ansible-playbook deplyment.yml -i hosts --extra-vars "host=droplets" Assim, você pode especificar o nome do grupo no extra-vars

Mrunal Gosar
fonte
2
Observe, tome cuidado com a nomenclatura de var. Eu estava testando isso usando play_hostse não obtive os resultados esperados porque esqueci que play_hostsé uma var interna do Ansible para todos os hosts no jogo atual.
Ryan Fisher
Suponho que o padrão deve ser definido como na resposta acima.
kakaz de
19

É um pouco tarde, mas acho que você poderia usar o --limit or -l comando para limitar o padrão a hosts mais específicos. (versão 2.3.2.0)

Você pode ter - hosts: all (or group) tasks: - some_task

e então ansible-playbook playbook.yml -l some_more_strict_host_or_pattern use o --list-hostssinalizador para ver em quais hosts essa configuração seria aplicada.

Jonathan Hamel
fonte
3
Eu sou muito novo no ansible, mas considero esta uma solução muito eficaz, muito mais compacta que as outras. Por que foi rejeitado?
Alessandro Dentella,
16
Isso é perigoso. Caso se esqueça limitda lista de hosts afetados, o manual pode causar muitos danos.
Alexander Shcheblikin
3
Acho que usar --extra-vars "variable_host=newtarget(s)"exatamente como a solução aceita é tão perigoso e uma solução mais complicada. Ele usa um host padrão webque pode ser aplicado aqui também em vez de all. Você pode usar um grupo de hosts restrito como padrão para evitar cometer erros e usar o --list-hostssinalizador para ter uma compreensão clara de quais hosts você está afetando.
Jonathan Hamel
3
A solução com extra-vars permite especificar um grupo vazio (ou não existente) como valor padrão. Portanto, se você esquecer de fornecer a variável via linha de comando, nada de ruim acontecerá. Solução com a opção "--limit" mais perigosa porque o manual não pode usar o grupo vazio como valor padrão para os hosts. A opção "--llmit" é aplicada ao valor dos hosts, portanto, será aplicada aos grupos vazios e fornecerá um resultado vazio. Portanto, você TEM que usar "all" ou algum outro host não vazio como valor padrão. E algum dia você se esquecerá de fornecer o argumento "--limit" e o manual será aplicado a todos os hosts.
Gregory Petukhov
4
Isso deve ser combinado com a resposta de @TmTron para detectar o caso em que o chamador falhou no fornecimento --limit(caso contrário, afetará todos os hosts possíveis, que podem não ser o comportamento que você deseja)
ncoghlan
14

Usamos uma tarefa de falha simples para forçar o usuário a especificar a opção de limite Ansible , de modo que não executemos em todos os hosts por padrão / acidente.

A maneira mais fácil que encontrei é esta:

---
- name: Force limit
  # 'all' is okay here, because the fail task will force the user to specify a limit on the command line, using -l or --limit
  hosts: 'all'

  tasks:
  - name: checking limit arg
    fail:
      msg: "you must use -l or --limit - when you really want to use all hosts, use -l 'all'"
    when: ansible_limit is not defined
    run_once: true

Agora devemos usar a opção -l(= --limit) quando executamos o manual, por exemplo

ansible-playbook playbook.yml -l www.example.com

Documentos de opção de limite :

Limite a um ou mais hosts Isso é necessário quando se deseja executar um manual contra um grupo de hosts, mas apenas contra um ou mais membros desse grupo.

Limite a um host

ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit "host1"

Limite a vários hosts

ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit "host1,host2"

Limite negado.
NOTA: As aspas simples DEVEM ser usadas para evitar a interpolação do bash.

ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit 'all:!host1'

Limite ao grupo de acolhimento

ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit 'group1'

TmTron
fonte
7

Estou usando outra abordagem que não precisa de nenhum inventário e funciona com este comando simples:

ansible-playbook site.yml -e working_host=myhost

Para fazer isso, você precisa de um manual com duas jogadas:

  • a primeira execução é executada em localhost e adiciona um host (de determinada variável) em um grupo conhecido no inventário de memória
  • a segunda jogada acontece neste grupo conhecido

Um exemplo de trabalho (copie-o e execute-o com o comando anterior):

- hosts: localhost
  connection: local
  tasks:
  - add_host:
      name: "{{ working_host }}"
      groups: working_group
    changed_when: false

- hosts: working_group
  gather_facts: false
  tasks:
  - debug:
      msg: "I'm on {{ ansible_host }}"

Estou usando o ansible 2.4.3 e 2.3.3

Nelson G.
fonte
7

Eu mudei o meu para o padrão sem host e tenho uma verificação para detectá-lo. Dessa forma, o usuário ou cron é forçado a fornecer um único host ou grupo etc. Gosto da lógica do comentário de @wallydrag. O empty_groupnão contém hosts no inventário.

- hosts: "{{variable_host | default ('empty_group')}}"

Em seguida, adicione as tarefas de check-in:

   tarefas:
   - name: Falha no script se o parâmetro variable_host necessário estiver ausente
     falhou:
       msg: "Você deve adicionar o --extra-vars = 'variable_host ='"
     quando: (host_variável não está definido) ou (host_variável == "")
Tony-Caffe
fonte
5

Acabei de encontrar esta busca no Google por uma solução. Na verdade, existe um no Ansible 2.5. Você pode especificar seu arquivo de inventário com --inventory, desta forma:ansible --inventory configs/hosts --list-hosts all

Bebef
fonte
Acredito que esta seja a resposta mais correta no Ano de Nosso Senhor 2019. Do Ansible 2.8.4's -h:-i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY specify inventory host path or comma separated host list. --inventory-file is deprecated
pyansharp
3

Se você deseja executar uma tarefa que está associada a um host, mas em um host diferente, você deve tentar delegate_to .

No seu caso, você deve delegar ao seu host local (ansible master) e chamar o ansible-playbookcomando

nghnam
fonte
2

Estou usando o ansible 2.5 (exatamente 2.5.3) e parece que o arquivo vars é carregado antes que o parâmetro hosts seja executado. Assim, você pode definir o host em um arquivo vars.yml e apenas escrever hosts: {{ host_var }}em seu manual

Por exemplo, em meu playbook.yml:

---
- hosts: "{{ host_name }}"
  become: yes
  vars_files:
    - vars/project.yml
  tasks:
    ... 

E dentro de vars / project.yml:

---

# general
host_name: your-fancy-host-name
Homem leve
fonte
0

Aqui está uma solução legal que vim para especificar hosts com segurança por meio da --limitopção. Neste exemplo, a reprodução terminará se o manual for executado sem nenhum host especificado por meio da --limitopção.

Isso foi testado em Ansible versão 2.7.10

---
- name: Playbook will fail if hosts not specified via --limit option.
  # Hosts must be set via limit. 
  hosts: "{{ play_hosts }}"
  connection: local
  gather_facts: false
  tasks:
  - set_fact:
      inventory_hosts: []
  - set_fact:
      inventory_hosts: "{{inventory_hosts + [item]}}"
    with_items: "{{hostvars.keys()|list}}"

  - meta: end_play
    when: "(play_hosts|length) == (inventory_hosts|length)"

  - debug:
      msg: "About to execute tasks/roles for {{inventory_hostname}}"
alma sudo
fonte
0

Uma outra solução é usar a variável especial ansible_limitque é o conteúdo da --limitopção CLI para a execução atual de Ansible.

- hosts: "{{ ansible_limit | default(omit) }}"

Se a --limitopção for omitida, o Ansible emitirá um aviso, mas não fará nada, já que nenhum host correspondeu.

[WARNING]: Could not match supplied host pattern, ignoring: None

PLAY ****************************************************************
skipping: no hosts matched
Manolo
fonte