system-config/playbooks/roles/install-ansible/files/inventory_plugins/yamlgroup.py
Ian Wienand 4abd0a3184 yamlgroup: add regex match; exclude puppet4 for arm64 mirrors
Two related changes that need to go together because we test with the
production groups.yaml.

Confusingly, there are arm64 PC1 puppet repos, and it contains a bunch
of things that it turns out are the common java parts only.  The
puppet-agent package is not available, and it doesn't seem like it
will be [1].  I think this means we can not run puppet4 on our arm64
xenial ci hosts.

The problem is the mirrors have been updated to puppet4 -- runs are
now breaking on the arm mirrors because they don't have puppet-agent
packages.  It seems all we can really do at this point is contine to
run them on puppet3.

This is hard (impossible?) to express with a fnmatch in the existing
yamlgroups syntax.  We could do something like list all the mirror
hosts and use anchors etc, but we have to keep that maintained.  Add
an feature to the inventory plugin that if the list entry starts with
a ^ it is considered a full regex and passed to re.match.  This
allows us to write more complex matchers where required -- in this
case the arm64 ci mirror hosts are excluded from the puppet4 group.

Testing is updated.

[1] https://groups.google.com/forum/#!msg/puppet-dev/iBMYJpvhaWM/WTGmJvXxAgAJ

Change-Id: I828e0c524f8d5ca866786978486bc04829464b47
2019-04-11 21:34:57 +00:00

100 lines
3.3 KiB
Python

# Copyright (c) 2018 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING.GPL or https://www.gnu.org/licenses/gpl-3.0.txt)
import fnmatch
import os
import re
from ansible.parsing.yaml.objects import AnsibleMapping
from ansible.plugins.inventory import BaseFileInventoryPlugin
DOCUMENTATION = '''
inventory: yamlgroup
version_added: "2.8"
short_description: Simple group manipulation for existing hosts
description:
- YAML based inventory that only manipulates group membership for
existing hosts.
options:
yaml_extensions:
description: list of 'valid' extensions for files containing YAML
type: list
default: ['.yaml', '.yml', '.json']
env:
- name: ANSIBLE_YAML_FILENAME_EXT
- name: ANSIBLE_INVENTORY_PLUGIN_EXTS
ini:
- key: yaml_valid_extensions
section: defaults
- section: inventory_plugin_yaml
key: yaml_valid_extensions
groups:
description: |
dict with group name as key. If the list item starts with a
^ it will be considered a regex pattern (i.e. passed to
re.match), otherwise it is considered a fnmatch pattern.
type: dict
default: {}
'''
EXAMPLES = '''
plugin: yamlgroup
groups:
amazing:
- fullhost.example.com
- amazing*
- ^regex.*pattern
'''
class InventoryModule(BaseFileInventoryPlugin):
NAME = 'yamlgroup'
def verify_file(self, path):
valid = False
if super(InventoryModule, self).verify_file(path):
file_name, ext = os.path.splitext(path)
if ext in self.get_option('yaml_extensions'):
valid = True
return valid
def parse(self, inventory, loader, path, cache=True):
''' parses the inventory file '''
super(InventoryModule, self).parse(inventory, loader, path)
self._read_config_data(path)
groups = self.get_option('groups')
found_groups = {}
for group, hosts in groups.items():
if not isinstance(hosts, list):
hosts = [hosts]
for candidate in hosts:
# If someone accidentally puts a dict into the list of hosts,
# the errors are ... obscure at best and the entire inventory
# will fail. Grab the dict key in those cases rather than
# failing.
if isinstance(candidate, AnsibleMapping):
candidate = list(candidate.keys())[0]
# Starts with ^ means it is already a regex.
# Otherwise it's a fnmatch compatible string; use it's
# helper to turn that into a regex so we have a common
# match below.
if not candidate.startswith('^'):
candidate = fnmatch.translate(candidate)
for existing in self.inventory.hosts.values():
if re.match(candidate, existing.get_name()):
found_groups.setdefault(group, [])
found_groups[group].append(existing)
for group, hosts in found_groups.items():
self.inventory.add_group(group)
for host in hosts:
self.inventory.add_child(group, host.get_name())