Anular la variable de hosts del libro de jugadas de Ansible desde la línea de comando

110

Este es un fragmento de un libro de jugadas que estoy usando ( server.yml):

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

Mi archivo de hosts tiene diferentes grupos de servidores, p. Ej.

[web]
x.x.x.x

[droplets]
x.x.x.x

Ahora quiero ejecutar ansible-playbook -i hosts/<env> server.ymly anular hosts: webdesde server.ymlpara ejecutar este libro de jugadas [droplets].

¿Puedo anularlo como una sola vez, sin editar server.ymldirectamente?

Gracias.

luqo33
fuente

Respuestas:

128

No creo que Ansible proporcione esta función, que debería. Aquí hay algo que puede hacer:

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

y puede pasar variable_hostdesde la línea de comandos o desde un archivo vars, por ejemplo:

ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
wallydrag
fuente
3
Se requiere una pequeña corrección. Debería serhosts: "{{ variable_host | default('web')}}"
SPM
16
Aquí hay una nota que creo que completaría la respuesta para los novatos de ansible que buscan esta solución: Ejemplo:ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
Frobbit
1
CUÁNDO (es decir, en qué orden) ansible analiza las variables Las variables en group_vars/allparece estar analizadas después de la hosts:línea del libro de jugadas. Sin embargo, ¿las variables en vars:y las variables en vars_files:se analizan antes de la hosts:línea? NOTA estoy no preguntando acerca de prioridad.
Felipe Alvarez
2
También puede utilizar en -elugar de --extra-vars.
sustantivo
Mire otras respuestas para obtener más detalles
Anand Varkey Philips
63

Para cualquiera que venga a buscar la solución.
Libro de juego

- 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" para que pueda especificar el nombre del grupo en las variables extra

Mrunal Gosar
fuente
2
Tenga cuidado con los nombres de var. Estaba probando esto usando play_hostsy no obteniendo los resultados esperados porque olvidé que play_hostses una var interna de Ansible para todos los hosts en el juego actual.
Ryan Fisher
Supongo que el valor predeterminado debe establecerse como en la respuesta anterior.
kakaz
19

Esto es un poco tarde, pero creo que podrías usar el --limit or -l comando para limitar el patrón a hosts más específicos. (versión 2.3.2.0)

Podrías tener - hosts: all (or group) tasks: - some_task

y entonces ansible-playbook playbook.yml -l some_more_strict_host_or_pattern y use la --list-hostsbandera para ver en qué hosts se aplicaría esta configuración.

Jonathan Hamel
fuente
3
Soy muy nuevo en ansible pero considero que esta es una solución muy eficaz, mucho más compacta que las demás. ¿Por qué se votó negativamente?
Alessandro Dentella
16
Esto es peligroso. En caso de que uno se olvide de limitla lista de hosts afectados, el libro de jugadas puede causar mucho daño.
Alexander Shcheblikin
3
Encuentro que usar --extra-vars "variable_host=newtarget(s)"la solución aceptada es tan peligrosa como una solución más complicada. Utiliza un host predeterminado webque podría aplicarse aquí también en lugar de all. Puede usar un grupo de hosts estricto como predeterminado para evitar cometer un error y usar la --list-hostsbandera para tener una comprensión clara de a qué hosts está afectando.
Jonathan Hamel
3
La solución con extra-vars permite especificar un grupo vacío (o no existente) como valor predeterminado. Entonces, si olvida proporcionar la variable a través de la línea de comando, no sucede nada malo. La solución con la opción "--limit" es más peligrosa porque el libro de jugadas no podía usar un grupo vacío como valor predeterminado para los hosts. La opción "--llmit" se aplica al valor de hosts, por lo que se aplicará a los grupos vacíos y proporcionará un resultado vacío. Entonces TIENES que usar "todos" o algún otro host no vacío como valor predeterminado. Y algún día se olvidará de proporcionar el argumento "--limit" y el libro de jugadas se aplicará a todos los hosts.
Gregory Petukhov
4
Esto debe combinarse con la respuesta de @ TmTron para detectar el caso en el que la persona que llama no pudo proporcionar --limit(de lo contrario, afectará a todos los hosts posibles, que pueden no ser el comportamiento que desea)
ncoghlan
14

Usamos una tarea de falla simple para obligar al usuario a especificar la opción de límite de Ansible , de modo que no se ejecute en todos los hosts de forma predeterminada / accidental.

La forma más fácil que encontré es 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

Ahora debemos usar la opción -l(= --limit) cuando ejecutamos el libro de jugadas, por ejemplo

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

Limitar los documentos de opciones :

Límite a uno o más hosts Esto es necesario cuando se quiere ejecutar un libro de jugadas contra un grupo de hosts, pero solo contra uno o más miembros de ese grupo.

Límite a un host

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

Límite a varios hosts

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

Límite negado.
NOTA: DEBEN usarse comillas simples para evitar la interpolación bash.

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

Límite al grupo anfitrión

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

TmTron
fuente
7

Estoy usando otro enfoque que no necesita ningún inventario y funciona con este simple comando:

ansible-playbook site.yml -e working_host=myhost

Para realizar eso, necesita un libro de jugadas con dos jugadas:

  • La primera reproducción se ejecuta en localhost y agrega un host (de una variable dada) en un grupo conocido en el inventario de inmemory.
  • la segunda jugada se ejecuta en este grupo conocido

Un ejemplo de trabajo (cópielo y ejecútelo con el 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 }}"

Estoy usando ansible 2.4.3 y 2.3.3

Nelson G.
fuente
7

Cambié el mío por defecto a ningún host y tengo una verificación para detectarlo. De esa manera, el usuario o cron se ve obligado a proporcionar un solo host o grupo, etc. Me gusta la lógica del comentario de @wallydrag. losempty_group contiene hosts en el inventario.

- hosts: "{{variable_host | predeterminado ('grupo_vacío')}}"

Luego agregue las tareas de registro:

   Tareas:
   - nombre: script de error si falta el parámetro de host variable requerido
     fallar:
       msg: "Tienes que agregar el --extra-vars = 'variable_host ='"
     cuando: (variable_host no está definido) o (variable_host == "")
Tony-Caffe
fuente
5

Acabo de encontrar una solución en Google. De hecho, hay uno en Ansible 2.5. Puede especificar su archivo de inventario con --inventory, así:ansible --inventory configs/hosts --list-hosts all

Bebef
fuente
Creo que esta es la respuesta más correcta en el Año de Nuestro Señor 2019. De 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

Si desea ejecutar una tarea que está asociada con un host, pero en un host diferente, debe probar delegate_to .

En su caso, debe delegar en su localhost (ansible master) y llamar al ansible-playbookcomando

nghnam
fuente
2

Estoy usando ansible 2.5 (2.5.3 exactamente), y parece que el archivo vars se carga antes de que se ejecute el parámetro de hosts. Entonces puede configurar el host en un archivo vars.yml y simplemente escribir hosts: {{ host_var }}en su libro de jugadas

Por ejemplo, en mi playbook.yml:

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

Y dentro de vars / project.yml:

---

# general
host_name: your-fancy-host-name
Hombre ligero
fuente
0

Aquí hay una solución genial que se me ocurrió para especificar hosts de forma segura a través de la --limitopción. En este ejemplo, el juego terminará si el libro de jugadas se ejecutó sin ningún host especificado a través de la --limitopción.

Esto fue probado en Ansible versión 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}}"
sudo soul
fuente
0

Otra solución es usar la variable especial ansible_limitque es el contenido de la --limitopción CLI para la ejecución actual de Ansible.

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

Si --limitse omite la opción, Ansible emite una advertencia, pero no hace nada ya que no coincide ningún host.

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

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