可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I've got a playbook that includes and tags various roles:
- name: base
hosts: "{{ host | default('localhost') }}"
roles:
- { role: apt, tags: [ 'base', 'apt', 'ubuntu']}
- { role: homebrew, tags: [ 'base', 'homebrew', osx' ]}
- { role: base16, tags: [ 'base', 'base16', 'osx' ]}
- { role: nodejs, tags: [ 'base', 'nodejs' ]}
- { role: tmux, tags: [ 'base', 'tmux' ]}
- { role: vim, tags: [ 'base', 'vim' ]}
- { role: virtualenv, tags: [ 'base', virtualenv', 'python' ]}
- { role: homebrew_cask, tags: [ 'desktop', 'homebrew_cask', osx' ]}
- { role: gnome_terminator, tags: [ 'desktop', 'gnome_terminator', ubuntu' ]}
Most of the tasks are using when clauses to determine which OS they should run on, for example:
- name: install base packages
when: ansible_distribution == 'MacOSX'
sudo: no
homebrew:
name: "{{ item.name }}"
state: latest
install_options: "{{ item.install_options|default() }}"
with_items: homebrew_packages
If I run ansible-playbook base.yml
without specifying any tags, all the tasks run. If I specify a tag, for example ansible-playbook base.yml --tags='base'
, only the roles tagged with base run
.
By default (if no tags are specified), I'd only like to run the roles tagged with 'base'
, and not the roles tagged with 'desktop'
.
It would also be really nice to set a default 'os' tag, based on the current operating system, to avoid including all the tasks for the ubuntu when I'm running the playbook on OSX (and vice-versa).
Any ideas if this is possible, and how I might do it?
回答1:
Unfortunately there is no such feature. Tag handling in Ansible currently is very limited. You can not set default tags and you can not exclude tags by default.
There are some threads on the Google user group and feature requests on github regarding this. But no outcome yet. The common answer so far is, you should create a shell script and place it in front of your playbook. This script then can set the --tags
and --skip-tags
accordingly to your needs. Very unpleasant but as far as I know the only option right now.
回答2:
If I run ansible-playbook base.yml without specifying any tags, all the tasks run.
Yes, this is very dangerous.
If You forget to add '--tags=xxxxx' it may run unwanted tasks...
There is a workaround, it's nasty, but it would prevent running Your tasks when there are no tags in commandline.
You could use --extra-vars and use it in your playbook, then run:
ansible-playbook base.yml -e'SOMEVAR=TRUE'
And in Your playbook:
- hosts: localhost
tasks:
- name: some task
ping:
tags:
- sometag
- name: Register SOMEVARANS
set_fact: SOMEVARANS={{SOMEVAR | default('False')}}
tags:
- every_tag_you_know_since_there_is_no_ALL_option
- sometag
- debug: msg="{{SOMEVARANS}}"
tags:
- every_tag_you_know_since_there_is_no_ALL_option
- sometag
- debug: msg="run only with extravars SOMEVAR=True"
when: SOMEVARANS
tags:
- every_tag_you_know_since_there_is_no_ALL_option
- sometag
The result:
$ ansible-playbook -i /subsystem/ansible/etc/inventory-qa.ini tags.yml
PLAY [localhost] **************************************************************
TASK: [some task] *************************************************************
ok: [localhost]
TASK: [Register SOMEVARANS] ***************************************************
ok: [localhost]
TASK: [debug msg="{{SOMEVARANS}}"] ********************************************
ok: [localhost] => {
"msg": "False"
}
TASK: [debug msg="run only with extravars SOMEVAR=True"] **********************
skipping: [localhost]
PLAY RECAP ********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
WITH 'SOMEVAR=True'
$ ansible-playbook -i /subsystem/ansible/etc/inventory-qa.ini tags.yml -e 'SOMEVAR=True'
PLAY [localhost] **************************************************************
TASK: [some task] *************************************************************
ok: [localhost]
TASK: [Register SOMEVARANS] ***************************************************
ok: [localhost]
TASK: [debug msg="{{SOMEVARANS}}"] ********************************************
ok: [localhost] => {
"msg": "True"
}
TASK: [debug msg="run only with extravars SOMEVAR=True"] **********************
ok: [localhost] => {
"msg": "run only with extravars SOMEVAR=True"
}
PLAY RECAP ********************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0
ALL IN ONE :)
$ ansible-playbook -i /subsystem/ansible/etc/inventory-qa.ini tags.yml -e 'SOMEVAR=True' --tags=sometag
PLAY [localhost] **************************************************************
TASK: [some task] *************************************************************
ok: [localhost]
TASK: [Register SOMEVARANS] ***************************************************
ok: [localhost]
TASK: [debug msg="{{SOMEVARANS}}"] ********************************************
ok: [localhost] => {
"msg": "True"
}
TASK: [debug msg="run only with extravars SOMEVAR=True"] **********************
ok: [localhost] => {
"msg": "run only with extravars SOMEVAR=True"
}
PLAY RECAP ********************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0
回答3:
I use command-line variable overrides (-e
) to achieve this:
$ ansible-playbook playbook.xml -e desktop=true
Rather than define desktop
as a tag, it could instead be defined as a variable with a default value of false
. Then, for roles requiring desktop
to be true, replace the tag with a when
clause. The playbook posted in the question might be rewritten like this:
- name: base
hosts: "{{ host | default('localhost') }}"
# default value to prevent errors when not overridden
vars:
desktop: false
roles:
# no change to "base" roles
- { role: apt, tags: [ 'base', 'apt', 'ubuntu'] }
# ...
# "desktop" roles get a "when" clause
- role: homebrew_cask
when: desktop | bool
tags: [ 'homebrew_cask', 'osx' ]
- role: gnome_terminator
when: desktop | bool
tags: [ 'gnome_terminator', ubuntu' ]
This is probably just a simplified version of one of the existing answers. As stated elsewhere, tags aren't the answer at this time to defaulting some actions to not run unless something is explicitly specified. Variables, on the other hand, are perfect for this.
回答4:
Since Ansible 2.5 there is a new feature which solves these kinds of situations.
Another special tag is never, which will prevent a task from running
unless a tag is specifically requested.
Example:
tasks:
- debug: msg='{{ showmevar}}'
tags: [ 'never', 'debug' ]
So your problem should be addressed like this:
- name: base
hosts: "{{ host | default('localhost') }}"
roles:
- { role: apt, tags: [ 'base', 'apt', 'ubuntu']}
- { role: homebrew, tags: [ 'base', 'homebrew', osx' ]}
- { role: base16, tags: [ 'base', 'base16', 'osx' ]}
- { role: nodejs, tags: [ 'base', 'nodejs' ]}
- { role: tmux, tags: [ 'base', 'tmux' ]}
- { role: vim, tags: [ 'base', 'vim' ]}
- { role: virtualenv, tags: [ 'base', virtualenv', 'python' ]}
- { role: homebrew_cask, tags: [ 'never','desktop', 'homebrew_cask', osx' ]}
- { role: gnome_terminator, tags: [ 'never','desktop', 'gnome_terminator', ubuntu' ]}
回答5:
There are another 3 special keywords for tags, ‘tagged’, ‘untagged’ and ‘all’, which run only tagged, only untagged and all tasks respectively.
By default ansible runs as if ‘–tags all’ had been specified.
You can check the docs here: http://docs.ansible.com/ansible/playbooks_tags.html#special-tags
回答6:
The reason to use default usually is: I want to type as less as possible in my most common use case. So I think what OP actually want is:
Are there ways to run 'base' tasks with as less arguments as possible.
As others pointed out, there are no "default" tag in ansible. But there are always ways.
First way is just use script to wrap it, like
writing a run.sh
like this:
ansible-playbook -t base base.yml
It is much shorter to type ./run.sh
instead of full command.
Second way is for the people that is looking for the pure ansible solution. You can have two playbooks like:
base.yml
- { role: apt, tags: [ 'base', 'apt', 'ubuntu']}
- { role: homebrew, tags: [ 'base', 'homebrew', osx' ]}
- { role: base16, tags: [ 'base', 'base16', 'osx' ]}
- { role: nodejs, tags: [ 'base', 'nodejs' ]}
- { role: tmux, tags: [ 'base', 'tmux' ]}
- { role: vim, tags: [ 'base', 'vim' ]}
- { role: virtualenv, tags: [ 'base', virtualenv', 'python' ]}
desktop.yml
- { role: homebrew_cask, tags: [ 'desktop', 'homebrew_cask', osx' ]}
- { role: gnome_terminator, tags: [ 'desktop', 'gnome_terminator', ubuntu' ]}
For base only tasks, run ansible-playbook base.yml
;
for desktop only tasks, run ansible-playbook desktop.yml
;
for all tasks, run ansible-playbook base.yml desktop.yml
It is also more error-prone than defining a 'default' tag.
OP also wants a default OS tag. It is easy to achieve that with when
- { role: some_role, when: "ansible_os_family == 'Debian'" }
with when
, you don't need to do anything in command line, ansible detects the type and runs corresponding tasks for you.