Remplacer la variable hosts du playbook Ansible à partir de la ligne de commande

110

Ceci est un fragment d'un playbook que j'utilise ( server.yml):

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

Mon fichier hosts a différents groupes de serveurs, par exemple

[web]
x.x.x.x

[droplets]
x.x.x.x

Maintenant , je veux exécuter ansible-playbook -i hosts/<env> server.ymlet passer outre hosts: webde server.ymlfaire fonctionner ce livre de jeux pour [droplets].

Puis-je simplement remplacer en une seule fois, sans modifier server.ymldirectement?

Merci.

luqo33
la source

Réponses:

128

Je ne pense pas qu'Ansible fournisse cette fonctionnalité, ce qu'il devrait. Voici quelque chose que vous pouvez faire:

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

et vous pouvez passer à variable_hostpartir de la ligne de commande ou d'un fichier vars, par exemple:

ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
wallydrag
la source
3
Une petite correction s'impose. Ça devrait êtrehosts: "{{ variable_host | default('web')}}"
SPM
16
Voici une note qui, à mon avis, compléterait la réponse pour les débutants à la recherche de cette solution: Exemple:ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
Frobbit
1
QUAND (c'est-à-dire dans quel ordre) est-ce que ansible analyse les variables Les variables dans group_vars/allsemblent être analysées après la hosts:ligne du playbook. Cependant, les variables dans vars:et les variables dans vars_files:sont analysées avant la hosts:ligne? REMARQUE Je ne demande pas la préséance.
Felipe Alvarez
2
Vous pouvez également utiliser à la -eplace de --extra-vars.
substantif
Regardez les autres réponses pour plus de détails
Anand Varkey Philips
63

Pour tous ceux qui pourraient chercher la solution.
Livre de jeu

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

Inventaire

[web]
x.x.x.x

[droplets]
x.x.x.x

Commande: ansible-playbook deplyment.yml -i hosts --extra-vars "host=droplets" vous pouvez donc spécifier le nom du groupe dans les extra-vars

Mrunal Gosar
la source
2
Remarque, soyez prudent avec la dénomination des var. Je testais cela en utilisant play_hostset n'obtenais pas les résultats escomptés car j'avais oublié qu'il s'agissait d' play_hostsune variable Ansible interne pour tous les hôtes de la lecture actuelle.
Ryan Fisher
Je suppose que la valeur par défaut doit être définie comme dans la réponse ci-dessus.
kakaz le
19

C'est un peu tard, mais je pense que vous pourriez utiliser le --limit or -l commande pour limiter le modèle à des hôtes plus spécifiques. (version 2.3.2.0)

Tu aurais pu - hosts: all (or group) tasks: - some_task

puis ansible-playbook playbook.yml -l some_more_strict_host_or_pattern et utilisez l' --list-hostsindicateur pour voir sur quels hôtes cette configuration serait appliquée.

Jonathan Hamel
la source
3
Je suis très nouveau dans ansible mais je considère que c'est une solution très efficace, beaucoup plus compacte que les autres. Pourquoi a-t-il été rejeté?
Alessandro Dentella
16
C'est dangereux. Au cas où l'on oublie limitla liste des hôtes concernés, le playbook peut causer beaucoup de dégâts.
Alexander Shcheblikin
3
Je trouve qu'utiliser --extra-vars "variable_host=newtarget(s)"comme la solution acceptée est aussi dangereux et une solution plus compliquée. Il utilise un hôte par défaut webqui pourrait également être appliqué ici à la place de all. Vous pouvez utiliser un groupe d'hôtes strict par défaut pour éviter de faire une erreur et utiliser l' --list-hostsindicateur pour avoir une compréhension claire des hôtes que vous affectez.
Jonathan Hamel
3
La solution avec extra-vars permet de spécifier un groupe vide (ou non existant) comme valeur par défaut. Donc, si vous oubliez de fournir la variable via la ligne de commande, rien de mal ne se produit. Solution avec l'option "--limit" plus dangereuse car le playbook ne pouvait pas utiliser de groupe vide comme valeur par défaut pour les hôtes. L'option "--llmit" est appliquée à la valeur des hôtes, elle sera donc appliquée aux groupes vides et fournira un résultat vide. Vous DEVEZ donc utiliser "tout" ou un autre hôte non vide comme valeur par défaut. Et un jour, vous oublierez de fournir l'argument "--limit" et le playbook sera appliqué à tous les hôtes.
Gregory Petukhov
4
Cela devrait être combiné avec la réponse de @ TmTron pour attraper le cas où l'appelant n'a pas fourni --limit(sinon cela affectera tous les hôtes possibles, ce qui peut ne pas être le comportement que vous souhaitez)
ncoghlan
14

Nous utilisons une tâche d' échec simple pour forcer l'utilisateur à spécifier l' option de limite Ansible , afin de ne pas s'exécuter sur tous les hôtes par défaut / accident.

Le moyen le plus simple que j'ai trouvé est le suivant:

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

Maintenant, nous devons utiliser l' option -l(= --limit) lorsque nous exécutons le playbook, par exemple

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

Documents sur les options de limite :

Limiter à un ou plusieurs hôtes Ceci est requis lorsque l'on souhaite exécuter un playbook contre un groupe d'hôtes, mais uniquement contre un ou plusieurs membres de ce groupe.

Limité à un hôte

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

Limiter à plusieurs hôtes

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

Limite annulée.
REMARQUE: des guillemets simples DOIVENT être utilisés pour empêcher l'interpolation bash.

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

Limiter au groupe d'hôtes

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

TmTron
la source
7

J'utilise une autre approche qui ne nécessite aucun inventaire et fonctionne avec cette commande simple:

ansible-playbook site.yml -e working_host=myhost

Pour ce faire, vous avez besoin d'un playbook avec deux pièces:

  • la première lecture s'exécute sur localhost et ajoute un hôte (à partir d'une variable donnée) dans un groupe connu dans l'inventaire en mémoire
  • le deuxième jeu tourne sur ce groupe connu

Un exemple de travail (copiez-le et exécutez-le avec la commande précédente):

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

J'utilise ansible 2.4.3 et 2.3.3

Nelson G.
la source
7

J'ai changé le mien par défaut en aucun hôte et j'ai un chèque pour l'attraper. De cette façon, l'utilisateur ou cron est obligé de fournir un seul hôte ou groupe, etc. J'aime la logique du commentaire de @wallydrag. Le empty_groupne contient aucun hôte dans l'inventaire.

- hôtes: "{{variable_host | default ('empty_group')}}"

Ajoutez ensuite les tâches d'archivage:

   Tâches:
   - nom: Échec du script si le paramètre requis variable_host est manquant
     échouer:
       msg: "Vous devez ajouter le --extra-vars = 'variable_host ='"
     quand: (variable_host n'est pas défini) ou (variable_host == "")
Tony-Caffe
la source
5

Je viens de trouver une solution sur Google. En fait, il y en a un dans Ansible 2.5. Vous pouvez spécifier votre fichier d'inventaire avec --inventory, comme ceci:ansible --inventory configs/hosts --list-hosts all

Boeuf
la source
Je crois que c'est la réponse la plus correcte de l'Année de Notre Seigneur 2019. D'après 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 vous souhaitez exécuter une tâche associée à un hôte, mais sur un hôte différent, vous devez essayer delegate_to .

Dans votre cas, vous devez déléguer à votre hôte local (maître ansible) et appeler la ansible-playbookcommande

Nghnam
la source
2

J'utilise ansible 2.5 (2.5.3 exactement), et il semble que le fichier vars soit chargé avant l'exécution du paramètre hosts. Vous pouvez donc définir l'hôte dans un fichier vars.yml et écrire simplementhosts: {{ host_var }} dans votre playbook

Par exemple, dans mon playbook.yml:

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

Et dans vars / project.yml:

---

# general
host_name: your-fancy-host-name
Homme léger
la source
0

Voici une solution intéressante que j'ai proposée pour spécifier en toute sécurité les hôtes via l' --limitoption. Dans cet exemple, la lecture se terminera si le playbook a été exécuté sans aucun hôte spécifié via le--limit option.

Cela a été testé sur la version 2.7.10 d'Ansible

---
- 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
la source
0

Une autre solution consiste à utiliser la variable spéciale ansible_limitqui est le contenu de l' --limitoption CLI pour l'exécution en cours d'Ansible.

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

Si l' --limitoption est omise, Ansible émet un avertissement, mais ne fait rien car aucun hôte ne correspond.

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

PLAY ****************************************************************
skipping: no hosts matched
Manolo
la source