Sostituisci la variabile hosts del playbook Ansible dalla riga di comando


110

Questo è un frammento di un playbook che sto usando ( server.yml):

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

Il mio file hosts ha diversi gruppi di server, ad es

[web]
x.x.x.x

[droplets]
x.x.x.x

Ora voglio eseguire ansible-playbook -i hosts/<env> server.ymle sovrascrivere hosts: webda server.ymlper eseguire questo playbook [droplets].

Posso semplicemente ignorare come una cosa una tantum, senza modificare server.ymldirettamente?

Grazie.

Risposte:


128

Non credo che Ansible fornisca questa funzionalità, che dovrebbe. Ecco qualcosa che puoi fare:

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

e puoi passare variable_hostdalla riga di comando o da un file vars, ad esempio:

ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"

3
È necessaria una piccola correzione. Dovrebbe esserehosts: "{{ variable_host | default('web')}}"
SPM

16
Ecco una nota che ritengo completerebbe la risposta per i neofiti ansible che cercano questa soluzione: Esempio:ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
Frobbit

1
QUANDO (cioè in quale ordine) le variabili di analisi ansible Le variabili in group_vars/allsembrano essere analizzate dopo la hosts:riga del playbook. Tuttavia, le variabili in vars:e le variabili in vars_files:vengono analizzate prima della hosts:riga? NOTA Sto non chiedendo la precedenza.
Felipe Alvarez

2
Puoi usare anche al -eposto di --extra-vars.
sostantivo

Guarda altre risposte per maggiori dettagli
Anand Varkey Philips

63

Per chiunque possa venire a cercare la soluzione.
Gioca a Book

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

Inventario

[web]
x.x.x.x

[droplets]
x.x.x.x

Comando: ansible-playbook deplyment.yml -i hosts --extra-vars "host=droplets" Quindi puoi specificare il nome del gruppo in extra-vars


2
Nota, fai attenzione con la denominazione var. Lo stavo testando usando play_hostse non ottenendo i risultati attesi perché ho dimenticato che play_hostsè una variabile Ansible interna per tutti gli host nel gioco corrente.
Ryan Fisher

Suppongo che il valore predefinito dovrebbe essere impostato come nella risposta sopra.
kakaz

19

È un po 'tardi, ma penso che potresti usare il --limit or -lcomando per limitare il pattern a host più specifici. (versione 2.3.2.0)

Potresti avere - hosts: all (or group) tasks: - some_task

e poi ansible-playbook playbook.yml -l some_more_strict_host_or_pattern e usa il --list-hostsflag per vedere su quali host verrà applicata questa configurazione.


3
Sono appena arrivato ad ansible ma considero questa una soluzione molto efficace, molto più compatta delle altre. Perché è stato downvoted?
Alessandro Dentella

16
Questo è pericoloso. Nel caso in cui si dimentichi limitl'elenco degli host interessati, il playbook può causare molti danni.
Alexander Shcheblikin

3
Trovo che usare --extra-vars "variable_host=newtarget(s)"proprio come la soluzione accettata sia pericoloso e una soluzione più complicata. Utilizza un host predefinito webche potrebbe essere applicato anche qui invece di all. È possibile utilizzare un gruppo host rigoroso come impostazione predefinita per evitare di commettere errori e utilizzare il --list-hostsflag per avere una chiara comprensione di quali host si stanno influenzando.
Jonathan Hamel

3
La soluzione con extra-vars consente di specificare un gruppo vuoto (o non esistente) come valore predefinito. Quindi se dimentichi di fornire la variabile tramite la riga di comando non succede nulla di male. Soluzione con l'opzione "--limit" più pericolosa perché il playbook non poteva utilizzare un gruppo vuoto come valore predefinito per gli host. L'opzione "--llmit" viene applicata al valore hosts, quindi verrà applicata ai gruppi vuoti e fornirà un risultato vuoto. Quindi DEVI usare "all" o qualche altro host non vuoto come valore predefinito. E un giorno ti dimenticherai di fornire l'argomento "--limit" e il playbook verrà applicato a tutti gli host.
Gregory Petukhov

4
Questo dovrebbe essere combinato con la risposta di @ TmTron per rilevare il caso in cui il chiamante non è riuscito a fornire --limit(altrimenti influenzerà tutti i possibili host, il che potrebbe non essere il comportamento desiderato)
ncoghlan

14

Usiamo un semplice task fail per forzare l'utente a specificare l' opzione Ansible limit , in modo da non eseguire su tutti gli host per impostazione predefinita / accidental.

Il modo più semplice che ho trovato è questo:

---
- 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

Ora dobbiamo usare l' opzione -l(= --limit) quando eseguiamo il playbook, ad es

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

Documenti sulle opzioni limite :

Limite a uno o più host Ciò è necessario quando si desidera eseguire un playbook contro un gruppo host, ma solo contro uno o più membri di quel gruppo.

Limita a un host

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

Limita a più host

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

Limite negato.
NOTA: le virgolette singole DEVONO essere utilizzate per impedire l'interpolazione bash.

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

Limita al gruppo ospitante

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


7

Sto usando un altro approccio che non necessita di inventario e funziona con questo semplice comando:

ansible-playbook site.yml -e working_host=myhost

Per farlo, hai bisogno di un playbook con due giochi:

  • la prima riproduzione viene eseguita su localhost e aggiunge un host (da una determinata variabile) in un gruppo noto nell'inventario inmemory
  • il secondo gioco viene eseguito su questo gruppo noto

Un esempio funzionante (copialo ed eseguilo con il comando precedente):

- 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 }}"

Sto usando ansible 2.4.3 e 2.3.3


7

Ho cambiato il mio come predefinito su nessun host e ho un controllo per prenderlo. In questo modo l'utente o cron è costretto a fornire un singolo host o gruppo ecc. Mi piace la logica del commento di @wallydrag. Non empty_groupcontiene host nell'inventario.

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

Quindi aggiungi le attività di check-in:

   compiti:
   - name: script non riuscito se manca il parametro variable_host richiesto
     fallire:
       msg: "Devi aggiungere --extra-vars = 'variable_host ='"
     quando: (variable_host non è definito) o (variable_host == "")

5

Mi sono appena imbattuto in questo googling per una soluzione. In realtà, ce n'è uno in Ansible 2.5. Puoi specificare il tuo file di inventario con --inventory, in questo modo:ansible --inventory configs/hosts --list-hosts all


Credo che questa sia la risposta più corretta nell'Anno di Nostro Signore 2019. Da Ansible 2.8.4 -h:-i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY specify inventory host path or comma separated host list. --inventory-file is deprecated
pyansharp

3

Se vuoi eseguire un'attività associata a un host, ma su un host diverso, dovresti provare delegate_to .

Nel tuo caso, dovresti delegare al tuo localhost (ansible master) e chiamare il ansible-playbookcomando


2

Sto usando ansible 2.5 (esattamente 2.5.3) e sembra che il file vars venga caricato prima che venga eseguito il parametro hosts. Quindi puoi impostare l'host in un file vars.yml e scrivere semplicemente hosts: {{ host_var }}nel tuo playbook

Ad esempio, nel mio playbook.yml:

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

E all'interno di vars / project.yml:

---

# general
host_name: your-fancy-host-name

0

Ecco una soluzione interessante che ho trovato per specificare in modo sicuro gli host tramite l' --limitopzione. In questo esempio, la riproduzione terminerà se il playbook è stato eseguito senza alcun host specificato tramite l' --limitopzione.

Questo è stato testato su Ansible versione 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}}"

0

Un'altra soluzione è usare la variabile speciale ansible_limitche è il contenuto --limitdell'opzione CLI per l'esecuzione corrente di Ansible.

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

Se l' --limitopzione viene omessa, Ansible emette un avviso, ma non fa nulla poiché nessun host corrisponde.

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

PLAY ****************************************************************
skipping: no hosts matched
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.