2013-08-12 14 views
148

Sto utilizzando Ansible per alcune semplici attività di gestione degli utenti con un piccolo gruppo di computer. Attualmente, ho i miei Playbooks impostato hosts: all e il mio file hosts è solo un singolo gruppo con tutte le macchine elencate:Limitare in sicurezza i playbook Ansible su una singola macchina?

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

mi sono trovato spesso di dover indirizzare una singola macchina. Il comando ansible-playbook può limitare i giochi in questo modo:

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

ma che sembra tipo di fragili, soprattutto per un playbook potenzialmente distruttiva. Lasciando fuori la bandiera limit significa che il playbook verrà eseguito ovunque. Dal momento che questi strumenti vengono utilizzati solo occasionalmente, sembra che sia opportuno adottare misure per una riproduzione infallibile, in modo da non nuotare accidentalmente qualcosa tra qualche mese.

Esiste una procedura ottimale per limitare le esecuzioni di Playbook a una singola macchina? Idealmente i quaderni dovrebbero essere innocui se alcuni dettagli importanti sono stati lasciati fuori.

risposta

141

Risulta che è possibile immettere un nome host direttamente nel playbook, quindi l'esecuzione del playbook con hosts: imac-2.local funzionerà correttamente. Ma è un po 'goffo.

Una soluzione migliore potrebbe essere definire gli host del PlayBook utilizzando una variabile, passando poi in un indirizzo host specifico tramite --extra-vars:

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

Esecuzione del playbook:

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

Se {{ target }} non è definito, il playbook non fa nulla. Un gruppo dal file hosts può anche essere passato, se necessario. Nel complesso, questo sembra un modo molto più sicuro per costruire un playbook potenzialmente distruttivo.

Playbook mira un singolo 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 gruppo di ospiti:

$ 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 

Dimenticando per definire gli host è sicuro!

$ ansible-playbook user.yml --list-hosts 

playbook: user.yml 

    play #1 ({{target}}): host count=0 
+30

Questo è risolvibile in 1.5.3 con '--limit office [0]' –

+3

La variabile deve essere quotata, ad esempio: '' {{target}} ''- in base a http: //docs.ansible. com/playbooks_variables.html # hey-wait-a-yaml-gotcha –

+0

Buona presa, è stata citata nei miei quaderni dall'inizio. Aggiornato. – joemaller

123

C'è anche un piccolo trucco carino che consente di specificare un singolo host sulla riga di comando (o più host, immagino), senza un inventario intermediario:

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

nota la virgola (,) alla fine; questo indica che si tratta di una lista, non di un file.

Ora, questo non ti proteggerà se accidentalmente passi un file di inventario reale, quindi potrebbe non essere una buona soluzione a questo specifico problema. Ma è un trucco utile da sapere!

+0

È fantastico. Uso regolarmente il flag -l, che funziona con etc/ansible/hosts (che viene popolato utilizzando l'API di scoperta EC2), ma a volte ho davvero bisogno di una sola macchina. Grazie! – Vic

+2

Questo trucco dovrebbe usare il file hosts? Sto usando gli host come inventario dinamico per il nostro sistema AWS EC2 e restituisce: 'saltando: nessun host abbinato '. Forse questo trucco non funziona più poiché '--limit' funziona? – hamx0r

+0

Questo trucco non ha funzionato per me. Ma questo ha funzionato: '$ ansible-playbook -kK --limit = myhost1 myplaybook.yml'. Vedi la risposta di Marwan. –

15

Per espandere la risposta di joemailer, se si desidera che l'abilità di corrispondenza del modello corrisponda a qualsiasi sottoinsieme di macchine remote (come fa il comando ansible), ma si desidera comunque rendere molto difficile l'esecuzione accidentale del playbook su tutte le macchine, questo è quello che è venuta in mente:

stesso playbook come in altra risposta:

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

Diamo i seguenti ospiti:

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

Ora, per eseguire il comando su tutti i dispositivi, è necessario explicty impostare la variabile di destinazione a "tutti"

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

E per limitarlo giù ad un modello specifico, è possibile impostare target=pattern_here

o , in alternativa, è possibile lasciare target=all e aggiungere il --limit argomento, per esempio:

--limit imac-1* 

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

che si traduce in:

playbook: user.yml 

    play #1 (office): host count=2 
    imac-10.local 
    imac-11.local 
+0

Questo è lo schema che ho seguito in [ansible- django-postgres-nginx] (https://github.com/ajoyoommen/ansible-django-postgres-nginx) – Ajoy

61

Questo approccio si esce se più di un singolo host viene realizzato controllando la variabile play_hosts. Il fail module viene utilizzato per uscire se non viene soddisfatta la condizione dell'host singolo. Gli esempi seguenti usano un file hosts con due host, alice e bob.

user.yml (Playbook)

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

Run playbook senza filtri ospitanti

$ 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 

Run playbook sul singolo 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!" 
} 
+0

Questo sembra essere l'approccio migliore. Grazie! Usandolo nei miei quaderni ora. –

+0

Definitivamente il migliore, '--limit' è la strada da percorrere – berto

+3

' play_hosts' è deprecato in Ansible 2.2 e sostituito con 'ansible_play_hosts'. Per eseguire su un host senza richiedere '--limit', puoi usare' when: inventory_hostname == ansible_play_hosts [0] '. –

5

utenti AWS utilizzando l'inventario esterno Script EC2 possono semplicemente filtrare per esempio id:

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

Questo funziona perché lo script di inventario creates default groups.

+1

Option --limit non è limitato a EC2 e può essere utilizzato per ospitare/gruppi i nomi del tuo inventario. Grazie. – martinezdelariva

2

Poiché la versione 1.7 ansible ha l'opzione run_once. La sezione contiene anche alcune discussioni su varie altre tecniche.

1

Ho uno script di wrapper chiamato provision che ti obbliga a scegliere il target, quindi non devo gestirlo altrove.

Per quelli che sono curiosi, io uso ENV vars per le opzioni che il mio vagrantfile usa (aggiungendo il corrispondente arg ansibile per i sistemi cloud) e lascia passare il resto degli argomenti ansibili.Dove sto creando e provisioning più di 10 server alla volta includo un auto retry su server falliti (a patto che vengano fatti progressi - ho scoperto quando ho creato 100 o più server alla volta, alcuni falliscono la prima volta).

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)/ 
' 
16

C'è IMHO in un modo più conveniente. È possibile infatti richiedere all'utente in modo interattivo per la macchina (s) che vuole applicare il playbook di grazie a vars_prompt:

--- 

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

Molto interessante. Questo ha anche il vantaggio che il playbook non è specifico per il file di inventario. – Erfan

+2

Thx per la modifica! In realtà mi stavo chiedendo perché l'input fosse per default trattato con "stile password". Mi era sfuggito che nei documenti :) – Buzut

+0

La var di hosts può essere impostata dalla riga di comando per eliminare il prompt con questo playbook? – andig

-1

Io davvero non capisco come tutte le risposte sono così complicate, il modo per farlo è semplicemente:

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

La modalità di controllo consente di eseguire in modalità di funzionamento a secco, senza apportare alcuna modifica.

+2

Probabilmente a causa delle risposte, hai perso la domanda, che chiedeva un modo per evitare l'esecuzione quando i parametri vengono omessi per errore. Hai suggerito di aggiungere più parametri che vanno contro il requisito. – techraf

2

Abbiamo alcuni playbook generici che sono utilizzabili da un gran numero di team. Disponiamo inoltre di file di inventario specifici dell'ambiente, che contengono più dichiarazioni di gruppo.

Per forzare qualcuno che chiama un playbook per specificare un gruppo di correre contro, abbiamo seme di una voce fittizia nella parte superiore del playbook:

[ansible-dummy-group] 
dummy-server 

Abbiamo poi sono i seguenti controllo come un primo passo nella condiviso playbook:

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

Se il manichino-server mostra nella lista di host questo playbook è pianificata l'esecuzione contro (ansible_play_batch), poi il chiamante non ha specificato un gruppo e l'esecuzione Playbook avrà esito negativo.