vars tower commands ansible ansible-playbook

tower - task ansible



¿Limitar con seguridad los libros de jugadas de Ansible a una sola máquina? (10)

Desde la versión 1.7, ansible tiene la opción run_once . La sección también contiene alguna discusión sobre varias otras técnicas.

Estoy usando Ansible para algunas tareas simples de administración de usuarios con un pequeño grupo de computadoras. Actualmente, tengo mis libros de jugadas configurados en hosts: all y mi archivo de hosts es solo un grupo con todas las máquinas listadas:

# file: hosts [office] imac-1.local imac-2.local imac-3.local

Me he encontrado con frecuencia teniendo que apuntar a una sola máquina. El comando ansible-playbook puede limitar juegos como este:

ansible-playbook --limit imac-2.local user.yml

Pero eso parece algo frágil, especialmente para un libro de jugadas potencialmente destructivo. Salir de la bandera de limit significa que el libro de jugadas se ejecutará en todas partes. Dado que estas herramientas solo se usan de vez en cuando, parece que vale la pena tomar medidas para proteger la reproducción a fin de evitar accidentalmente el uso de armas nucleares dentro de unos meses.

¿Existe una mejor práctica para limitar el funcionamiento del libro de jugadas a una sola máquina? Idealmente, los libros de jugadas deberían ser inofensivos si se dejaran algunos detalles importantes.


Este enfoque se cerrará si se proporciona más de un único host al verificar la variable play_hosts . El módulo de falla se usa para salir si no se cumple la condición de host único. Los ejemplos a continuación usan un archivo hosts con dos hosts alice y bob.

user.yml (libro de jugadas)

--- - hosts: all tasks: - name: Check for single host fail: msg="Single host check failed." when: "{{ play_hosts|length }} != 1" - debug: msg=''I got executed!''

Ejecuta el libro de jugadas sin filtros de host

$ ansible-playbook user.yml PLAY [all] **************************************************************** TASK: [Check for single host] ********************************************* failed: [alice] => {"failed": true} msg: Single host check failed. failed: [bob] => {"failed": true} msg: Single host check failed. FATAL: all hosts have already failed -- aborting

Ejecuta el libro de jugadas en un solo host

$ ansible-playbook user.yml --limit=alice PLAY [all] **************************************************************** TASK: [Check for single host] ********************************************* skipping: [alice] TASK: [debug msg=''I got executed!''] *************************************** ok: [alice] => { "msg": "I got executed!" }


Hay en mi humilde opinión una manera más conveniente. De hecho, puede solicitar interactivamente al usuario las máquinas a las que quiere aplicar el libro de jugadas gracias a vars_prompt :

--- - hosts: "{{ hosts }}" vars_prompt: - name: "hosts" prompt: "Which hosts would you like to setup?" private: no tasks: […]


Los usuarios de AWS que utilizan el script de inventario externo EC2 pueden simplemente filtrar por ID de instancia:

ansible-playbook sample-playbook.yml --limit i-c98d5a71 --list-hosts

Esto funciona porque la secuencia de comandos del inventario crea grupos predeterminados .


Para ampliar la respuesta de joemailer, si desea que la capacidad de coincidencia de patrones coincida con cualquier subconjunto de máquinas remotas (tal como lo hace el comando ansible ), pero aún desea que sea muy difícil ejecutar accidentalmente el libro de estrategias en todas las máquinas, esto es lo que se me ocurrió:

El mismo libro de jugadas que el en otra respuesta:

# file: user.yml (playbook) --- - hosts: ''{{ target }}'' user: ...

Tengamos los siguientes hosts:

imac-10.local imac-11.local imac-22.local

Ahora, para ejecutar el comando en todos los dispositivos, debe establecer explícitamente la variable de destino a "todos"

ansible-playbook user.yml --extra-vars "target=all"

Y para limitarlo a un patrón específico, puede establecer target=pattern_here

o, como alternativa, puede dejar target=all y agregar el argumento --limit , por ejemplo:

--limit imac-1*

es decir. ansible-playbook user.yml --extra-vars "target=all" --limit imac-1* --list-hosts

lo que resulta en:

playbook: user.yml play #1 (office): host count=2 imac-10.local imac-11.local


Realmente no entiendo cómo todas las respuestas son tan complicadas, la forma de hacerlo es simplemente:

ansible-playbook user.yml -i hosts/hosts --limit imac-2.local --check

El modo de verificación le permite ejecutar en modo de funcionamiento en seco, sin realizar ningún cambio.


Resulta que es posible ingresar un nombre de host directamente en el libro de jugadas, por lo que ejecutar el libro de jugadas con los hosts: imac-2.local funcionará bien. Pero es un poco torpe.

Una mejor solución podría ser definir los hosts del libro de jugadas usando una variable, y luego pasar una dirección de host específica a través de --extra-vars :

# file: user.yml (playbook) --- - hosts: ''{{ target }}'' user: ...

Ejecutando el libro de jugadas:

ansible-playbook user.yml --extra-vars "target=imac-2.local"

Si {{ target }} no está definido, el libro de jugadas no hace nada. Un grupo del archivo hosts también se puede pasar si es necesario. En general, esto parece una forma mucho más segura de construir un libro de jugadas potencialmente destructivo.

Playbook dirigido a un solo host:

$ ansible-playbook user.yml --extra-vars "target=imac-2.local" --list-hosts playbook: user.yml play #1 (imac-2.local): host count=1 imac-2.local

Playbook con un grupo de anfitriones:

$ ansible-playbook user.yml --extra-vars "target=office" --list-hosts playbook: user.yml play #1 (office): host count=3 imac-1.local imac-2.local imac-3.local

¡Olvidarse de definir hosts es seguro!

$ ansible-playbook user.yml --list-hosts playbook: user.yml play #1 ({{target}}): host count=0


También hay un lindo pequeño truco que te permite especificar un único host en la línea de comando (o varios hosts, supongo), sin un inventario intermedio:

ansible-playbook -i "imac1-local," user.yml

Tenga en cuenta la coma ( , ) al final; esto indica que es una lista, no un archivo.

Ahora, esto no lo protegerá si accidentalmente pasa un archivo de inventario real, por lo que puede no ser una buena solución para este problema específico. ¡Pero es un truco útil para saber!


Tenemos algunos libros de jugadas genéricos que son utilizables por una gran cantidad de equipos. También tenemos archivos de inventario específicos del entorno, que contienen múltiples declaraciones grupales.

Para forzar a alguien que llama a un libro de jugadas a especificar un grupo contra el cual competir, sembramos una entrada ficticia en la parte superior del libro de jugadas:

[ansible-dummy-group] dummy-server

Luego incluimos la siguiente verificación como primer paso en el libro de jugadas compartido:

- hosts: all gather_facts: False run_once: true tasks: - fail: msg: "Please specify a group to run this playbook against" when: ''"dummy-server" in ansible_play_batch''

Si el dummy-server aparece en la lista de hosts que está programado para ejecutar este libro de jugadas (ansible_play_batch), entonces el llamador no especificó un grupo y la ejecución del libro de jugadas fallará.


Tengo un script de envoltura llamado provision que obliga a elegir el objetivo, por lo que no tengo que manejarlo en otro lugar.

Para aquellos que son curiosos, uso ENV vars para las opciones que usa mi vagrantfile (agregando el argumento ansible correspondiente para los sistemas en la nube) y dejo pasar el resto de los argumentos ansible. Cuando estoy creando y aprovisionando más de 10 servidores a la vez, incluyo un reintento automático en servidores fallidos (siempre que se esté progresando). Encontré al crear aproximadamente 100 servidores a la vez, a menudo fallaron algunos la primera vez. )

echo ''Usage: [VAR=value] bin/provision [options] dev|all|TARGET|vagrant'' echo '' bootstrap - Bootstrap servers ssh port and initial security provisioning'' echo '' dev - Provision localhost for development and control'' echo '' TARGET - specify specific host or group of hosts'' echo '' all - provision all servers'' echo '' vagrant - Provision local vagrant machine (environment vars only)'' echo echo ''Environment VARS'' echo '' BOOTSTRAP - use cloud providers default user settings if set'' echo '' TAGS - if TAGS env variable is set, then only tasks with these tags are run'' echo '' SKIP_TAGS - only run plays and tasks whose tags do not match these values'' echo '' START_AT_TASK - start the playbook at the task matching this name'' echo ansible-playbook --help | sed -e ''1d s#=/etc/ansible/hosts# set by bin/provision argument# /-k/s/$/ (use for fresh systems)/ /--tags/s/$/ (use TAGS var instead)/ /--skip-tags/s/$/ (use SKIP_TAGS var instead)/ /--start-at-task/s/$/ (use START_AT_TASK var instead)/ ''