Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
ansible
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
ansible
Commits
c81d9811
Commit
c81d9811
authored
Feb 25, 2015
by
Brian Coca
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #10183 from bcoca/tag_control
adds complex tag management
parents
a1e2ae08
f6a6df21
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
138 additions
and
67 deletions
+138
-67
bin/ansible-playbook
+4
-22
docsite/rst/playbooks_tags.rst
+25
-3
lib/ansible/playbook/__init__.py
+59
-24
lib/ansible/playbook/play.py
+21
-16
lib/ansible/playbook/task.py
+4
-1
test/integration/Makefile
+10
-1
test/integration/test_tags.yml
+15
-0
No files found.
bin/ansible-playbook
View file @
c81d9811
...
...
@@ -227,22 +227,6 @@ def main(args):
label
=
play
.
name
hosts
=
pb
.
inventory
.
list_hosts
(
play
.
hosts
)
# Filter all tasks by given tags
if
pb
.
only_tags
!=
'all'
:
if
options
.
subset
and
not
hosts
:
continue
matched_tags
,
unmatched_tags
=
play
.
compare_tags
(
pb
.
only_tags
)
# Remove skipped tasks
matched_tags
=
matched_tags
-
set
(
pb
.
skip_tags
)
unmatched_tags
.
discard
(
'all'
)
unknown_tags
=
((
set
(
pb
.
only_tags
)
|
set
(
pb
.
skip_tags
))
-
(
matched_tags
|
unmatched_tags
))
if
unknown_tags
:
continue
if
options
.
listhosts
:
print
' play #
%
d (
%
s): host count=
%
d'
%
(
playnum
,
label
,
len
(
hosts
))
for
host
in
hosts
:
...
...
@@ -251,12 +235,10 @@ def main(args):
if
options
.
listtasks
:
print
' play #
%
d (
%
s):'
%
(
playnum
,
label
)
for
task
in
play
.
tasks
():
if
(
set
(
task
.
tags
)
.
intersection
(
pb
.
only_tags
)
and
not
set
(
task
.
tags
)
.
intersection
(
pb
.
skip_tags
)):
if
getattr
(
task
,
'name'
,
None
)
is
not
None
:
# meta tasks have no names
print
'
%
s'
%
task
.
name
for
task
in
pb
.
tasks_to_run_in_play
(
play
):
if
getattr
(
task
,
'name'
,
None
)
is
not
None
:
# meta tasks have no names
print
'
%
s'
%
task
.
name
if
options
.
listhosts
or
options
.
listtasks
:
print
''
continue
...
...
docsite/rst/playbooks_tags.rst
View file @
c81d9811
Tags
====
If you have a large playbook it may become useful to be able to run a
specific part of the configuration without running the whole playbook.
If you have a large playbook it may become useful to be able to run a
specific part of the configuration without running the whole playbook.
Both plays and tasks support a "tags:" attribute for this reason.
...
...
@@ -24,7 +24,7 @@ Example::
If you wanted to just run the "configuration" and "packages" part of a very long playbook, you could do this::
ansible-playbook example.yml --tags "configuration,packages"
On the other hand, if you want to run a playbook *without* certain tasks, you could do this::
ansible-playbook example.yml --skip-tags "notification"
...
...
@@ -40,6 +40,28 @@ And you may also tag basic include statements::
Both of these have the function of tagging every single task inside the include statement.
Special Tags
````````````
There is a special 'always' tag that will always run a task, unless specifically skipped (--skip-tags always)
Example::
tasks:
- debug: msg="Always runs"
tags:
- always
- debug: msg="runs when you use tag1"
tags:
- tag1
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.
.. seealso::
:doc:`playbooks`
...
...
lib/ansible/playbook/__init__.py
View file @
c81d9811
...
...
@@ -36,6 +36,7 @@ import pipes
# holds all other variables about a host
SETUP_CACHE
=
ansible
.
cache
.
FactCache
()
VARS_CACHE
=
collections
.
defaultdict
(
dict
)
RESERVED_TAGS
=
[
'all'
,
'tagged'
,
'untagged'
,
'always'
]
class
PlayBook
(
object
):
...
...
@@ -314,6 +315,7 @@ class PlayBook(object):
assert
play
is
not
None
matched_tags
,
unmatched_tags
=
play
.
compare_tags
(
self
.
only_tags
)
matched_tags_all
=
matched_tags_all
|
matched_tags
unmatched_tags_all
=
unmatched_tags_all
|
unmatched_tags
...
...
@@ -332,10 +334,13 @@ class PlayBook(object):
# the user can correct the arguments.
unknown_tags
=
((
set
(
self
.
only_tags
)
|
set
(
self
.
skip_tags
))
-
(
matched_tags_all
|
unmatched_tags_all
))
unknown_tags
.
discard
(
'all'
)
for
t
in
RESERVED_TAGS
:
unknown_tags
.
discard
(
t
)
if
len
(
unknown_tags
)
>
0
:
unmatched_tags_all
.
discard
(
'all'
)
for
t
in
RESERVED_TAGS
:
unmatched_tags_all
.
discard
(
t
)
msg
=
'tag(s) not found in playbook:
%
s. possible values:
%
s'
unknown
=
','
.
join
(
sorted
(
unknown_tags
))
unmatched
=
','
.
join
(
sorted
(
unmatched_tags_all
))
...
...
@@ -667,7 +672,53 @@ class PlayBook(object):
return
filename
# *****************************************************
def
tasks_to_run_in_play
(
self
,
play
):
tasks
=
[]
for
task
in
play
.
tasks
():
# only run the task if the requested tags match or has 'always' tag
u
=
set
([
'untagged'
])
task_set
=
set
(
task
.
tags
)
if
'always'
in
task
.
tags
:
should_run
=
True
else
:
if
'all'
in
self
.
only_tags
:
should_run
=
True
else
:
should_run
=
False
if
'tagged'
in
self
.
only_tags
:
if
task_set
!=
u
:
should_run
=
True
elif
'untagged'
in
self
.
only_tags
:
if
task_set
==
u
:
should_run
=
True
else
:
if
task_set
.
intersection
(
self
.
only_tags
):
should_run
=
True
# Check for tags that we need to skip
if
'all'
in
self
.
skip_tags
:
should_run
=
False
else
:
if
'tagged'
in
self
.
skip_tags
:
if
task_set
!=
u
:
should_run
=
False
elif
'untagged'
in
self
.
skip_tags
:
if
task_set
==
u
:
should_run
=
False
else
:
if
should_run
:
if
task_set
.
intersection
(
self
.
skip_tags
):
should_run
=
False
if
should_run
:
tasks
.
append
(
task
)
return
tasks
# *****************************************************
def
_run_play
(
self
,
play
):
''' run a list of tasks for a given pattern, in order '''
...
...
@@ -720,7 +771,7 @@ class PlayBook(object):
play
.
_play_hosts
=
self
.
_trim_unavailable_hosts
(
on_hosts
)
self
.
inventory
.
also_restrict_to
(
on_hosts
)
for
task
in
play
.
tasks
(
):
for
task
in
self
.
tasks_to_run_in_play
(
play
):
if
task
.
meta
is
not
None
:
# meta tasks can force handlers to run mid-play
...
...
@@ -730,27 +781,11 @@ class PlayBook(object):
# skip calling the handler till the play is finished
continue
# only run the task if the requested tags match
should_run
=
False
for
x
in
self
.
only_tags
:
for
y
in
task
.
tags
:
if
x
==
y
:
should_run
=
True
break
# Check for tags that we need to skip
if
should_run
:
if
any
(
x
in
task
.
tags
for
x
in
self
.
skip_tags
):
should_run
=
False
if
should_run
:
if
not
self
.
_run_task
(
play
,
task
,
False
):
# whether no hosts matched is fatal or not depends if it was on the initial step.
# if we got exactly no hosts on the first step (setup!) then the host group
# just didn't match anything and that's ok
return
False
if
not
self
.
_run_task
(
play
,
task
,
False
):
# whether no hosts matched is fatal or not depends if it was on the initial step.
# if we got exactly no hosts on the first step (setup!) then the host group
# just didn't match anything and that's ok
return
False
# Get a new list of what hosts are left as available, the ones that
# did not go fail/dark during the task
...
...
lib/ansible/playbook/play.py
View file @
c81d9811
...
...
@@ -669,20 +669,6 @@ class Play(object):
# *************************************************
def
_is_valid_tag
(
self
,
tag_list
):
"""
Check to see if the list of tags passed in is in the list of tags
we only want (playbook.only_tags), or if it is not in the list of
tags we don't want (playbook.skip_tags).
"""
matched_skip_tags
=
set
(
tag_list
)
&
set
(
self
.
playbook
.
skip_tags
)
matched_only_tags
=
set
(
tag_list
)
&
set
(
self
.
playbook
.
only_tags
)
if
len
(
matched_skip_tags
)
>
0
or
(
self
.
playbook
.
only_tags
!=
[
'all'
]
and
len
(
matched_only_tags
)
==
0
):
return
False
return
True
# *************************************************
def
tasks
(
self
):
''' return task objects for this play '''
return
self
.
_tasks
...
...
@@ -783,8 +769,27 @@ class Play(object):
# compare the lists of tags using sets and return the matched and unmatched
all_tags_set
=
set
(
all_tags
)
tags_set
=
set
(
tags
)
matched_tags
=
all_tags_set
&
tags_set
unmatched_tags
=
all_tags_set
-
tags_set
matched_tags
=
all_tags_set
.
intersection
(
tags_set
)
unmatched_tags
=
all_tags_set
.
difference
(
tags_set
)
a
=
set
([
'always'
])
u
=
set
([
'untagged'
])
if
'always'
in
all_tags_set
:
matched_tags
=
matched_tags
.
union
(
a
)
unmatched_tags
=
all_tags_set
.
difference
(
a
)
if
'all'
in
tags_set
:
matched_tags
=
matched_tags
.
union
(
all_tags_set
)
unmatched_tags
=
set
()
if
'tagged'
in
tags_set
:
matched_tags
=
all_tags_set
.
difference
(
u
)
unmatched_tags
=
u
if
'untagged'
in
tags_set
and
'untagged'
in
all_tags_set
:
matched_tags
=
matched_tags
.
union
(
u
)
unmatched_tags
=
unmatched_tags
.
difference
(
u
)
return
matched_tags
,
unmatched_tags
...
...
lib/ansible/playbook/task.py
View file @
c81d9811
...
...
@@ -129,7 +129,7 @@ class Task(object):
# load various attributes
self
.
name
=
ds
.
get
(
'name'
,
None
)
self
.
tags
=
[
'
all
'
]
self
.
tags
=
[
'
untagged
'
]
self
.
register
=
ds
.
get
(
'register'
,
None
)
self
.
sudo
=
utils
.
boolean
(
ds
.
get
(
'sudo'
,
play
.
sudo
))
self
.
su
=
utils
.
boolean
(
ds
.
get
(
'su'
,
play
.
su
))
...
...
@@ -316,6 +316,9 @@ class Task(object):
self
.
tags
.
extend
(
apply_tags
)
self
.
tags
.
extend
(
import_tags
)
if
len
(
self
.
tags
)
>
1
:
self
.
tags
.
remove
(
'untagged'
)
if
additional_conditions
:
new_conditions
=
additional_conditions
[:]
if
self
.
when
:
...
...
test/integration/Makefile
View file @
c81d9811
...
...
@@ -21,7 +21,7 @@ VAULT_PASSWORD_FILE = vault-password
CONSUL_RUNNING
:=
$(
shell
python consul_running.py
)
all
:
parsing test_var_precedence unicode non_destructive destructive includes check_mode test_hash test_handlers test_group_by test_vault
all
:
parsing test_var_precedence unicode non_destructive destructive includes check_mode test_hash test_handlers test_group_by test_vault
test_tags
parsing
:
ansible-playbook bad_parsing.yml
-i
$(INVENTORY)
-e
@
$(VARS_FILE)
$(CREDENTIALS_ARG)
-vvv
$(TEST_FLAGS)
--tags
prepare,common,scenario1
;
[
$$
?
-eq
3
]
...
...
@@ -82,6 +82,15 @@ test_delegate_to:
test_winrm
:
ansible-playbook test_winrm.yml
-i
inventory.winrm
-e
@
$(VARS_FILE)
$(CREDENTIALS_ARG)
-v
$(TEST_FLAGS)
test_tags
:
# Run everything by default
[
"
$$
(ansible-playbook --list-tasks test_tags.yml -i
$(INVENTORY)
-e @
$(VARS_FILE)
$(CREDENTIALS_ARG)
-v
$(TEST_FLAGS)
| fgrep Task_with | xargs)"
=
"Task_with_tag Task_with_always_tag Task_without_tag"
]
# Run the exact tags, and always
[
"
$$
(ansible-playbook --list-tasks --tags tag test_tags.yml -i
$(INVENTORY)
-e @
$(VARS_FILE)
$(CREDENTIALS_ARG)
-v
$(TEST_FLAGS)
| fgrep Task_with | xargs)"
=
"Task_with_tag Task_with_always_tag"
]
# Skip one tag
[
"
$$
(ansible-playbook --list-tasks --skip-tags tag test_tags.yml -i
$(INVENTORY)
-e @
$(VARS_FILE)
$(CREDENTIALS_ARG)
-v
$(TEST_FLAGS)
| fgrep Task_with | xargs)"
=
"Task_with_always_tag Task_without_tag"
]
cloud
:
amazon rackspace
cloud_cleanup
:
amazon_cleanup rackspace_cleanup
...
...
test/integration/test_tags.yml
0 → 100644
View file @
c81d9811
---
-
name
:
verify tags work as expected
hosts
:
localhost
gather_facts
:
False
connection
:
local
tasks
:
-
name
:
Task_with_tag
debug
:
msg=
tags
:
tag
-
name
:
Task_with_always_tag
debug
:
msg=
tags
:
always
-
name
:
Task_without_tag
debug
:
msg=
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment