Skip to content

Commit

Permalink
Introduce 'exclude_tags' (#124)
Browse files Browse the repository at this point in the history
* added option for skip_tags var to omit objects

* documented skip_tags in openshift_applier README

* changed skip_tags to exclude_tags and allowed for use with filter_tags

* fixed newline error

* changed refrences in filter from filter_tags to include_tags

* fixed filter_content function name

* fixed include_list var

* handle overlapping invocation of include_tags and exclude_tags with erroring out

* added newline for ci job

* same as before

* removed blank line

* remove trailing white space

* updated error messages and default filter values

* updated filter error
  • Loading branch information
Ben Kincaid authored and oybed committed Aug 6, 2019
1 parent 1b87b99 commit f4d8f5e
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 20 deletions.
9 changes: 6 additions & 3 deletions roles/openshift-applier/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ openshift_cluster_content:
file: <file source>
action: <apply|create> # Optional: Defaults to 'apply'
no_log: <True|False> # Optional: no_log at content level if functionality desired. Defaults to False
tags: # Optional: Tags are only needed if `include_tags` is used
tags: # Optional: Tags are only needed if `include_tags` or `exclude_tags` is used
- tag1
- tag2
post_steps: # Optional: post-steps at content level can be added if desired
Expand Down Expand Up @@ -212,12 +212,15 @@ metadata:

### Filtering content based on tags

The `openshift-applier` supports the use of tags in the inventory (see example above) to allow for filtering which content should be processed and not. The `include_tags` variable/fact takes a comma separated list of tags that will be processed and only content with matching tags will be applied.
The `openshift-applier` supports the use of tags in the inventory (see example above) to allow for filtering which content should be processed and not. The `include_tags` and `exclude_tags` variables/facts take a comma separated list of tags that will be processed. The `include_tags` will apply content **only** with the matching tags, while `exclude_tags` will apply **anything but** the content with the matching tags.

**_NOTE:_** Entries in the inventory without tags will not be processed when a valid list is supplied with the `include_tags` option.
**_NOTE:_** Entries in the inventory without tags will not be processed when a valid list of tags is supplied with `include_tags`.

**_NOTE:_** If the same tag exists in both `include_tags` and `exclude_tags` the run will error out. Likewise, if tags from the two options annuls each other, the execution will also error out.

```
include_tags=tag1,tag2
exclude_tags=tag3,tag4

```
Expand Down
1 change: 1 addition & 0 deletions roles/openshift-applier/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ client: oc
default_oc_action: apply
tmp_inv_dir: ''
include_tags: ''
exclude_tags: ''
provision: True
params_from_vars: {}
oc_ignore_unknown_parameters: true
88 changes: 72 additions & 16 deletions roles/openshift-applier/filter_plugins/applier-filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,98 @@
from urllib.request import urlopen


# Return content invoked with improper tag usage
def get_invalid_tag_usage(applier_list, include_tags, exclude_tags):

if len(include_tags.strip()) == 0 or len(exclude_tags.strip()) == 0:
return []

# Convert comma seperated list to an actual list and strip off whitespaces of each element
include_list = include_tags.split(",")
include_list = [i.strip() for i in include_list]

exclude_list = exclude_tags.split(",")
exclude_list = [i.strip() for i in exclude_list]

repeated_tags = []
# Loop through the main list to check if any tags were invoked incorrectly
# - append to repeated_tags and return
for a in applier_list[:]:
if 'content' in a:
for c in a['content'][:]:
if 'tags' not in c:
continue

include_matches = list(set(include_list) & set(c['tags']))

exclude_matches = list(set(exclude_list) & set(c['tags']))

if include_matches and exclude_matches:
repeated_tags.append({
'object': a.get("object", "[unknown]"),
'name': c.get("name", "[unknown]"),
'invoked_tags': include_matches + exclude_matches,
})

return repeated_tags


# Helper function to simplify the 'filter_applier_items' below
def filter_content(content_dict, outer_list, filter_list):
# If tags don't exists at all, just remove the 'content'
def filter_content(content_dict, outer_list, include_list, exclude_list):
# Handle if tags don't exist in the 'content' section
if 'tags' not in content_dict:
outer_list.remove(content_dict)
if include_list:
outer_list.remove(content_dict)
return

# Find out of if any of the tags exists in the 'content' section
intersect_list = [val for val in content_dict['tags'] if val in filter_list]
# Handle if include_tags exists in the 'content' section
if include_list:
intersect_list = [
val for val in content_dict['tags'] if val in include_list]
if len(intersect_list) == 0:
outer_list.remove(content_dict)
return

# If none of the filter tags exists, remove it from the list
if len(intersect_list) == 0:
outer_list.remove(content_dict)
# Handle if exclude_tags exists in the 'content' section
if exclude_list:
intersect_list = [
val for val in content_dict['tags'] if val in exclude_list]
if len(intersect_list) != 0:
outer_list.remove(content_dict)
return


# Main 'filter_applier_items' function
def filter_applier_items(applier_list, include_tags):
# If no filter tags supplied - just return list as-is
if len(include_tags.strip()) == 0:
def filter_applier_items(applier_list, include_tags, exclude_tags):
# If no tag lists supplied - just return list as-is
if len(include_tags.strip()) == 0 and len(exclude_tags.strip()) == 0:
return applier_list

exclude_list, include_list = [], []

# Convert comma seperated list to an actual list and strip off whitespaces of each element
filter_list = include_tags.split(",")
filter_list = [i.strip() for i in filter_list]
if include_tags and len(include_tags.strip()) != 0:
include_list = include_tags.split(",")
include_list = [i.strip() for i in include_list]

if exclude_tags and len(exclude_tags.strip()) != 0:
exclude_list = exclude_tags.split(",")
exclude_list = [i.strip() for i in exclude_list]

# Loop through the main list to check tags
# - use a copy to allow for elements to be removed at the same time as we iterrate
for a in applier_list[:]:
# Handle the 'content' entries
if 'content' in a:
for c in a['content'][:]:
filter_content(c, a['content'], filter_list)
filter_content(c, a['content'], include_list, exclude_list)

if len(a['content']) == 0:
applier_list.remove(a)

return applier_list


# Function used to determine a files location - i.e.: URL, local file/directory or "something else"
def check_file_location(path):
# default return values
Expand All @@ -64,7 +118,7 @@ def check_file_location(path):
if (not path_status):
try:
url_status = urlopen(path)
except (IOError,ValueError):
except (IOError, ValueError):
# Must be a pre-loaded template, nothing to do
return return_vals

Expand All @@ -84,8 +138,10 @@ def check_file_location(path):

class FilterModule(object):
''' Filters to handle openshift_cluster_content data '''

def filters(self):
return {
'check_file_location': check_file_location,
'filter_applier_items': filter_applier_items
'filter_applier_items': filter_applier_items,
'get_invalid_tag_usage': get_invalid_tag_usage
}
6 changes: 6 additions & 0 deletions roles/openshift-applier/tasks/error-on-unsupported.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@
when:
- unsupported_items is defined
with_dict: "{{ unsupported_items }}"

- name: "Error out if any unsupported tag usage was found"
fail:
msg: "Confused - Do not know how to process the combination of tags for content {{ item.object }}/{{ item.name }} and include_tags/exclude_tags parameters."
with_items:
- "{{ openshift_cluster_content | get_invalid_tag_usage(include_tags, exclude_tags) }}"
2 changes: 1 addition & 1 deletion roles/openshift-applier/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
- name: "Create OpenShift objects"
include_tasks: process-content.yml
with_items:
- "{{ openshift_cluster_content | filter_applier_items(include_tags) | default([]) }}"
- "{{ openshift_cluster_content | filter_applier_items(include_tags, exclude_tags) | default([]) }}"
loop_control:
loop_var: entry
when:
Expand Down

0 comments on commit f4d8f5e

Please sign in to comment.