J'utilise Ansible pour certaines tâches simples de gestion des utilisateurs avec un petit groupe d'ordinateurs. Actuellement, mes livres de lecture sont définis sur hosts: all
et mon fichier hosts est constitué d'un seul groupe avec toutes les machines répertoriées:
# file: hosts
[office]
iMac-1.local
iMac-2.local
iMac-3.local
Je me suis souvent trouvé dans l'obligation de cibler une seule machine. La commande ansible-playbook
peut limiter les lectures comme ceci:
ansible-playbook --limit iMac-2.local user.yml
Mais cela semble un peu fragile, en particulier pour un livre de jeu potentiellement destructeur. Si vous laissez de côté le drapeau limit
, le livret de jeu serait exécuté partout. Étant donné que ces outils ne sont utilisés que de temps en temps, il semble utile de prendre des mesures pour une lecture à toute épreuve afin d'éviter toute attaque accidentelle dans les prochains mois.
Existe-t-il une bonne pratique pour limiter les exécutions de playbook à une seule machine? Idéalement, les cahiers devraient être inoffensifs si certains détails importants étaient omis.
Il s'avère qu'il est possible d'entrer un nom d'hôte directement dans le livre de lecture. L'exécution du livre de lecture avec hosts: iMac-2.local
fonctionnera sans problème. Mais c'est un peu maladroit.
Une meilleure solution pourrait être de définir les hôtes du livre de lecture en utilisant une variable, puis de passer une adresse d'hôte spécifique via --extra-vars
:
# file: user.yml (playbook)
---
- hosts: '{{ target }}'
user: ...
Lancer le playbook:
ansible-playbook user.yml --extra-vars "target=iMac-2.local"
Si {{ target }}
n'est pas défini, le livre de lecture ne fait rien. Un groupe du fichier hosts peut également être passé si nécessaire. Globalement, cela semble être un moyen beaucoup plus sûr de construire un livre de jeu potentiellement destructeur.
Playbook ciblant un seul hôte:
$ 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 avec un groupe d'hôtes:
$ 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
Oublier de définir des hôtes est sûr!
$ ansible-playbook user.yml --list-hosts
playbook: user.yml
play #1 ({{target}}): Host count=0
Il existe également une petite astuce qui vous permet de spécifier un hôte unique sur la ligne de commande (ou plusieurs hôtes, je suppose), sans inventaire intermédiaire:
ansible-playbook -i "iMac1-local," user.yml
Notez la virgule (, ) à la fin; cela signifie que c'est une liste, pas un fichier.
À présent, cela ne vous protégera pas si vous transmettez accidentellement un fichier d'inventaire réel. Ce n'est donc peut-être pas une bonne solution à ce problème spécifique. Mais c'est un truc pratique à savoir!
Cette approche se terminera si plusieurs hôtes sont fournis en vérifiant la variable play_hosts . Le module fail est utilisé pour sortir si la condition d'hôte unique n'est pas remplie. Les exemples ci-dessous utilisent un fichier hosts avec deux hôtes alice et 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!'
Exécuter le livre de lecture sans filtres d'hôte
$ 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
Exécuter le livre de lecture sur un hôte unique
$ 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!"
}
Il y a IMHO un moyen plus pratique. Vous pouvez en effet demander de manière interactive à l'utilisateur la ou les machines auxquelles il souhaite appliquer le livre de lecture grâce à vars_Prompt
:
---
- hosts: "{{ hosts }}"
vars_Prompt:
- name: "hosts"
Prompt: "Which hosts would you like to setup?"
private: no
tasks:
[…]
Pour développer la réponse de joemailer, si vous souhaitez que la capacité de correspondance de modèle corresponde à tout sous-ensemble de machines distantes (comme le fait la commande ansible
), tout en rendant très difficile l’exécution accidentelle du playbook sur toutes les est ce que je suis venu avec:
Même livre de jeu que dans l'autre réponse:
# file: user.yml (playbook)
---
- hosts: '{{ target }}'
user: ...
Ayons les hôtes suivants:
iMac-10.local
iMac-11.local
iMac-22.local
Maintenant, pour exécuter la commande sur tous les périphériques, vous devez expliquer la valeur "all" de la variable cible.
ansible-playbook user.yml --extra-vars "target=all"
Et pour le limiter à un modèle spécifique, vous pouvez définir target=pattern_here
ou, alternativement, vous pouvez laisser target=all
et ajouter l'argument --limit
, par exemple:
--limit iMac-1*
c'est à dire. ansible-playbook user.yml --extra-vars "target=all" --limit iMac-1* --list-hosts
qui se traduit par:
playbook: user.yml
play #1 (office): Host count=2
iMac-10.local
iMac-11.local
Les utilisateurs AWS utilisant le script d'inventaire externe EC2 peuvent simplement filtrer par ID d'instance:
ansible-playbook sample-playbook.yml --limit i-c98d5a71 --list-hosts
Cela fonctionne car le script d'inventaire crée des groupes par défaut .
Depuis la version 1.7, ansible a l'option run_once . La section contient également des informations sur diverses autres techniques.
Nous avons des cahiers génériques utilisables par un grand nombre d’équipes. Nous avons également des fichiers d’inventaire spécifiques à l’environnement, contenant plusieurs déclarations de groupe.
Pour forcer une personne appelant un livre de jeu à spécifier un groupe auquel faire face, nous semons une entrée factice en haut du livre:
[ansible-dummy-group]
dummy-server
Nous incluons ensuite le contrôle suivant comme première étape dans le livre de jeu partagé:
- 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 le serveur factice apparaît dans la liste des hôtes sur lesquels le playbook doit être exécuté (ansible_play_batch), alors l'appelant n'a pas spécifié de groupe et l'exécution du playbook échouera.
Je ne comprends vraiment pas comment toutes les réponses sont si compliquées.
ansible-playbook user.yml -i hosts/hosts --limit iMac-2.local --check
Le mode de vérification vous permet de fonctionner en mode sèche, sans apporter de modification.
J'ai un script d'emballage appelé provision qui vous oblige à choisir la cible. Je n'ai donc pas à le gérer ailleurs.
Pour ceux qui sont curieux, j'utilise ENV vars pour les options utilisées par mon vagrantfile (ajout de l'argument ansible correspondant pour les systèmes en nuage) et je laisse passer le reste des arguments anibles. Lorsque je crée et alimente plus de 10 serveurs à la fois, j'inclue une nouvelle tentative automatique sur les serveurs défaillants (tant que des progrès sont accomplis - lors de la création d'une centaine de serveurs à la fois, plusieurs échouaient la première fois ).
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)/
'
C'est un peu plus compliqué si vous voulez utiliser une connexion locale. Mais cela devrait être correct si vous utilisez une variable pour le paramètre hosts et créez dans le fichier hosts une entrée spéciale pour localhost.
Dans (tous) les playbooks, les hôtes: line sont réglés sur:
- hosts: "{{ target | default('no_hosts')}}"
Dans le fichier hôtes d’inventaire, ajoutez une entrée pour l’hôte local qui définit la connexion comme étant locale:
[localhost]
127.0.0.1 ansible_connection=local
Ensuite, sur la ligne de commande, exécutez les commandes définissant explicitement la cible - par exemple:
$ ansible-playbook --extra-vars "target=localhost" test.yml
Cela fonctionnera également avec ansible-pull:
$ ansible-pull -U <git-repo-here> -d ~/ansible --extra-vars "target=localhost" test.yml
Si vous oubliez de définir la variable sur la ligne de commande, la commande commettra une erreur en toute sécurité (tant que vous n'avez pas créé de groupe d'hôtes appelé 'no_hosts'!) Avec l'avertissement suivant:
skipping: no hosts matched
Et comme mentionné ci-dessus, vous pouvez cibler une seule machine (tant qu'elle se trouve dans votre fichier hosts) avec:
$ ansible-playbook --extra-vars "target=server.domain" test.yml
ou un groupe avec quelque chose comme:
$ ansible-playbook --extra-vars "target=web-servers" test.yml