Zastąp zmienną hosts elementu playbook Ansible z wiersza poleceń

110

Oto fragment poradnika, którego używam ( server.yml):

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

Mój plik hosts zawiera różne grupy serwerów, np

[web]
x.x.x.x

[droplets]
x.x.x.x

Teraz chcę wykonać ansible-playbook -i hosts/<env> server.ymli zastąpić hosts: webz, server.ymlaby uruchomić ten podręcznik dla [droplets].

Czy mogę nadpisać jako jednorazową rzecz bez server.ymlbezpośredniej edycji ?

Dzięki.

luqo33
źródło

Odpowiedzi:

128

Myślę, że Ansible nie zapewnia takiej funkcji, która powinna. Oto coś, co możesz zrobić:

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

i możesz przekazać variable_hostz linii poleceń lub z pliku vars, np:

ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
wallydrag
źródło
3
Wymagana niewielka korekta. Powinno byćhosts: "{{ variable_host | default('web')}}"
SPM
16
Oto uwaga, która moim zdaniem byłaby uzupełnieniem odpowiedzi dla początkujących użytkowników ansibla szukających tego rozwiązania: Przykład:ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
Frobbit
1
KIEDY (czyli w jakiej kolejności) Czy ansibl zmienne analizy: Zmienne w group_vars/allwydaje się być analizowany po tej hosts:linii Playbook. Jednak zmienne wi vars:zmienne w vars_files:są analizowane przed hosts:wierszem? UWAGA ja nie pytając o pierwszeństwo.
Felipe Alvarez
2
Możesz użyć także -ezamiast --extra-vars.
rzeczownik
Zobacz inne odpowiedzi, aby uzyskać więcej szczegółów
Anand Varkey Philips,
63

Dla każdego, kto szuka rozwiązania.
Play Book

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

Inwentarz

[web]
x.x.x.x

[droplets]
x.x.x.x

Polecenie: ansible-playbook deplyment.yml -i hosts --extra-vars "host=droplets" Więc możesz określić nazwę grupy w extra-vars

Mrunal Gosar
źródło
2
Uwaga, uważaj na zmienne nazewnictwo. Testowałem to, używając play_hostsi nie otrzymując oczekiwanych wyników, ponieważ zapomniałem, że play_hostsjest to wewnętrzna zmienna Ansible dla wszystkich hostów w bieżącej grze.
Ryan Fisher
Przypuszczam, że wartość domyślna powinna być ustawiona tak, jak w odpowiedzi powyżej.
kakaz
19

To trochę późno, ale myślę, że przydałby się plik --limit or -l polecenia, aby ograniczyć wzorzec do bardziej konkretnych hostów. (wersja 2.3.2.0)

Mogłeś - hosts: all (or group) tasks: - some_task

a następnie ansible-playbook playbook.yml -l some_more_strict_host_or_pattern użyj --list-hostsflagi, aby zobaczyć, na których hostach zostanie zastosowana ta konfiguracja.

Jonathan Hamel
źródło
3
Jestem bardzo nowy w ansiblu, ale uważam to za bardzo skuteczne rozwiązanie, dużo bardziej kompaktowe niż inne. Dlaczego został odrzucony?
Alessandro Dentella
16
To jest niebezpieczne. W przypadku, gdy zapomni się limito liście hostów, których to dotyczy, playbook może spowodować wiele szkód.
Alexander Shcheblikin
3
Uważam, że używanie --extra-vars "variable_host=newtarget(s)"tak samo jak przyjętego rozwiązania jest równie niebezpieczne i bardziej skomplikowane. Używa domyślnych hostów, webktórych można również użyć tutaj zamiast all. Możesz użyć ścisłej grupy hostów jako domyślnej, aby uniknąć popełnienia błędu i użyć --list-hostsflagi, aby dokładnie zrozumieć, na które hosty wpływasz.
Jonathan Hamel
3
Rozwiązanie z dodatkowymi zmiennymi pozwala określić pustą grupę (lub nieistniejącą) jako wartość domyślną. Więc jeśli zapomnisz podać zmienną w wierszu poleceń, nic złego się nie stanie. Rozwiązanie z opcją „--limit” jest bardziej niebezpieczne, ponieważ element playbook nie może użyć pustej grupy jako wartości domyślnej dla hostów. Opcja „--llmit” jest stosowana do wartości hostów, dlatego zostanie zastosowana do pustych grup i zapewni pusty wynik. Więc MUSISZ użyć "all" lub innego niepustego hosta jako wartości domyślnej. I któregoś dnia zapomnisz o podaniu argumentu „--limit”, a podręcznik zostanie zastosowany do wszystkich hostów.
Gregory Petukhov
4
Należy to połączyć z odpowiedzią @ TmTron, aby wychwycić przypadek, w którym dzwoniący nie dostarczył --limit(w przeciwnym razie wpłynie to na wszystkie możliwe hosty, co może nie być zachowaniem, którego chcesz)
ncoghlan
14

Używamy prostego zadania niepowodzenia, aby zmusić użytkownika do określenia Ansible opcji limitu , aby nie wykonywać domyślnie / przypadkowo na wszystkich hostach.

Najłatwiejszy sposób, jaki znalazłem, jest następujący:

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

Teraz musimy użyć -l (= --limit), gdy uruchamiamy playbook, np

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

Ogranicz dokumenty opcji :

Ogranicz do jednego lub więcej hostów Jest to wymagane, gdy chce się uruchomić Playbook przeciwko grupie hostów, ale tylko przeciwko jednemu lub większej liczbie członków tej grupy.

Ogranicz do jednego hosta

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

Ogranicz do wielu hostów

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

Limit zanegowany.
UWAGA: Aby zapobiec interpolacji basha, MUSZĄ być używane pojedyncze cudzysłowy.

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

Ogranicz do grupy hostów

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

TmTron
źródło
7

Używam innego podejścia, które nie wymaga żadnych zapasów i działa z tym prostym poleceniem:

ansible-playbook site.yml -e working_host=myhost

Aby to zrobić, potrzebujesz playbooka z dwoma odtworzeniami:

  • pierwsza gra działa na hoście lokalnym i dodaje hosta (z podanej zmiennej) do znanej grupy w inwentarzu w pamięci
  • druga gra działa na tej znanej grupie

Działający przykład (skopiuj go i uruchom z poprzednim poleceniem):

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

Używam ansibla 2.4.3 i 2.3.3

Nelson G.
źródło
7

Zmieniłem mój na domyślny na brak hosta i mam czek, aby go złapać. W ten sposób użytkownik lub cron jest zmuszony do podania pojedynczego hosta lub grupy itp. Podoba mi się logika z komentarza @wallydrag. Nie empty_groupzawiera hostów w ekwipunku.

- hosty: "{{host_zmiennej | domyślny ('pusta_grupa')}}"

Następnie dodaj zadania odprawy:

   zadania:
   - name: Skrypt zakończony niepowodzeniem, jeśli brakuje wymaganego parametru zmiennej_host
     zawieść:
       msg: "Musisz dodać --extra-vars = 'variable_host ='"
     kiedy: (zmienna_host nie jest zdefiniowana) lub (zmienna_host == "")
Tony-Caffe
źródło
5

Właśnie natknąłem się na to googlowanie w poszukiwaniu rozwiązania. Właściwie w Ansible 2.5 jest jeden. Możesz określić plik zapasów za pomocą --inventory, na przykład:ansible --inventory configs/hosts --list-hosts all

Bebef
źródło
Uważam, że jest to najbardziej poprawna odpowiedź w Roku Pańskim 2019. Z 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

Jeśli chcesz uruchomić zadanie skojarzone z hostem, ale na innym hoście, powinieneś spróbować delegate_to .

W twoim przypadku powinieneś oddelegować do twojego lokalnego hosta (mastera ansible) i wywołać ansible-playbookpolecenie

nghnam
źródło
2

Używam ansible 2.5 (dokładnie 2.5.3) i wygląda na to, że plik vars jest ładowany przed wykonaniem parametru hosts. Możesz więc ustawić hosta w pliku vars.yml i po prostu pisać hosts: {{ host_var }}w swoim playbooku

Na przykład w moim playbook.yml:

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

A wewnątrz vars / project.yml:

---

# general
host_name: your-fancy-host-name
LightMan
źródło
0

Oto fajne rozwiązanie, które wymyśliłem, aby bezpiecznie określić hosty za pomocą --limitopcji. W tym przykładzie gra zakończy się, jeśli playbook został uruchomiony bez hostów określonych w --limitopcji.

Zostało to przetestowane na Ansible w wersji 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}}"
dusza sudo
źródło
0

Innym rozwiązaniem jest użycie specjalnej zmiennej, ansible_limitktóra jest zawartością --limitopcji CLI dla bieżącego wykonania Ansible.

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

Jeśli --limitopcja zostanie pominięta, Ansible wyświetla ostrzeżenie, ale nic nie robi, ponieważ żaden host nie został dopasowany.

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

PLAY ****************************************************************
skipping: no hosts matched
Manolo
źródło