diff options
author | Matt Bruzek <mbruzek@gmail.com> | 2018-01-18 15:27:13 -0600 |
---|---|---|
committer | Matt Bruzek <mbruzek@gmail.com> | 2018-01-18 15:27:13 -0600 |
commit | cb581bfb67a53f887c4705d45fc7b0024a6816f9 (patch) | |
tree | 9c351ddd9282f5d3d37c1189af0ac2ad444c0125 /filter_plugins | |
parent | c7a1c448cbd64de98e1f097d14b58ee9f6ccf511 (diff) | |
parent | 1a2a895356df638756d2117e3d324710167737db (diff) | |
download | openshift-cb581bfb67a53f887c4705d45fc7b0024a6816f9.tar.gz openshift-cb581bfb67a53f887c4705d45fc7b0024a6816f9.tar.bz2 openshift-cb581bfb67a53f887c4705d45fc7b0024a6816f9.tar.xz openshift-cb581bfb67a53f887c4705d45fc7b0024a6816f9.zip |
Merge branch 'master' into mbruzek-openshift-openstack
Diffstat (limited to 'filter_plugins')
-rw-r--r-- | filter_plugins/oo_filters.py | 1001 | ||||
-rw-r--r-- | filter_plugins/openshift_version.py | 69 |
2 files changed, 0 insertions, 1070 deletions
diff --git a/filter_plugins/oo_filters.py b/filter_plugins/oo_filters.py deleted file mode 100644 index 3eaf2aed5..000000000 --- a/filter_plugins/oo_filters.py +++ /dev/null @@ -1,1001 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# pylint: disable=too-many-lines -""" -Custom filters for use in openshift-ansible -""" -import json -import os -import pdb -import random -import re - -from base64 import b64encode -from collections import Mapping -# pylint no-name-in-module and import-error disabled here because pylint -# fails to properly detect the packages when installed in a virtualenv -from distutils.util import strtobool # pylint:disable=no-name-in-module,import-error -from distutils.version import LooseVersion # pylint:disable=no-name-in-module,import-error -from operator import itemgetter - -import pkg_resources -import yaml - -from ansible import errors -from ansible.parsing.yaml.dumper import AnsibleDumper - -# ansible.compat.six goes away with Ansible 2.4 -try: - from ansible.compat.six import string_types, u - from ansible.compat.six.moves.urllib.parse import urlparse -except ImportError: - from ansible.module_utils.six import string_types, u - from ansible.module_utils.six.moves.urllib.parse import urlparse - -HAS_OPENSSL = False -try: - import OpenSSL.crypto - HAS_OPENSSL = True -except ImportError: - pass - - -def oo_pdb(arg): - """ This pops you into a pdb instance where arg is the data passed in - from the filter. - Ex: "{{ hostvars | oo_pdb }}" - """ - pdb.set_trace() - return arg - - -def get_attr(data, attribute=None): - """ This looks up dictionary attributes of the form a.b.c and returns - the value. - - If the key isn't present, None is returned. - Ex: data = {'a': {'b': {'c': 5}}} - attribute = "a.b.c" - returns 5 - """ - if not attribute: - raise errors.AnsibleFilterError("|failed expects attribute to be set") - - ptr = data - for attr in attribute.split('.'): - if attr in ptr: - ptr = ptr[attr] - else: - ptr = None - break - - return ptr - - -def oo_flatten(data): - """ This filter plugin will flatten a list of lists - """ - if not isinstance(data, list): - raise errors.AnsibleFilterError("|failed expects to flatten a List") - - return [item for sublist in data for item in sublist] - - -def oo_merge_dicts(first_dict, second_dict): - """ Merge two dictionaries where second_dict values take precedence. - Ex: first_dict={'a': 1, 'b': 2} - second_dict={'b': 3, 'c': 4} - returns {'a': 1, 'b': 3, 'c': 4} - """ - if not isinstance(first_dict, dict) or not isinstance(second_dict, dict): - raise errors.AnsibleFilterError("|failed expects to merge two dicts") - merged = first_dict.copy() - merged.update(second_dict) - return merged - - -def oo_merge_hostvars(hostvars, variables, inventory_hostname): - """ Merge host and play variables. - - When ansible version is greater than or equal to 2.0.0, - merge hostvars[inventory_hostname] with variables (ansible vars) - otherwise merge hostvars with hostvars['inventory_hostname']. - - Ex: hostvars={'master1.example.com': {'openshift_variable': '3'}, - 'openshift_other_variable': '7'} - variables={'openshift_other_variable': '6'} - inventory_hostname='master1.example.com' - returns {'openshift_variable': '3', 'openshift_other_variable': '7'} - - hostvars=<ansible.vars.hostvars.HostVars object> (Mapping) - variables={'openshift_other_variable': '6'} - inventory_hostname='master1.example.com' - returns {'openshift_variable': '3', 'openshift_other_variable': '6'} - """ - if not isinstance(hostvars, Mapping): - raise errors.AnsibleFilterError("|failed expects hostvars is dictionary or object") - if not isinstance(variables, dict): - raise errors.AnsibleFilterError("|failed expects variables is a dictionary") - if not isinstance(inventory_hostname, string_types): - raise errors.AnsibleFilterError("|failed expects inventory_hostname is a string") - ansible_version = pkg_resources.get_distribution("ansible").version # pylint: disable=maybe-no-member - merged_hostvars = {} - if LooseVersion(ansible_version) >= LooseVersion('2.0.0'): - merged_hostvars = oo_merge_dicts( - hostvars[inventory_hostname], variables) - else: - merged_hostvars = oo_merge_dicts( - hostvars[inventory_hostname], hostvars) - return merged_hostvars - - -def oo_collect(data_list, attribute=None, filters=None): - """ This takes a list of dict and collects all attributes specified into a - list. If filter is specified then we will include all items that - match _ALL_ of filters. If a dict entry is missing the key in a - filter it will be excluded from the match. - Ex: data_list = [ {'a':1, 'b':5, 'z': 'z'}, # True, return - {'a':2, 'z': 'z'}, # True, return - {'a':3, 'z': 'z'}, # True, return - {'a':4, 'z': 'b'}, # FAILED, obj['z'] != obj['z'] - ] - attribute = 'a' - filters = {'z': 'z'} - returns [1, 2, 3] - - This also deals with lists of lists with dict as elements. - Ex: data_list = [ - [ {'a':1, 'b':5, 'z': 'z'}, # True, return - {'a':2, 'b':6, 'z': 'z'} # True, return - ], - [ {'a':3, 'z': 'z'}, # True, return - {'a':4, 'z': 'b'} # FAILED, obj['z'] != obj['z'] - ], - {'a':5, 'z': 'z'}, # True, return - ] - attribute = 'a' - filters = {'z': 'z'} - returns [1, 2, 3, 5] - """ - if not isinstance(data_list, list): - raise errors.AnsibleFilterError("oo_collect expects to filter on a List") - - if not attribute: - raise errors.AnsibleFilterError("oo_collect expects attribute to be set") - - data = [] - retval = [] - - for item in data_list: - if isinstance(item, list): - retval.extend(oo_collect(item, attribute, filters)) - else: - data.append(item) - - if filters is not None: - if not isinstance(filters, dict): - raise errors.AnsibleFilterError( - "oo_collect expects filter to be a dict") - retval.extend([get_attr(d, attribute) for d in data if ( - all([d.get(key, None) == filters[key] for key in filters]))]) - else: - retval.extend([get_attr(d, attribute) for d in data]) - - retval = [val for val in retval if val is not None] - - return retval - - -def oo_select_keys_from_list(data, keys): - """ This returns a list, which contains the value portions for the keys - Ex: data = { 'a':1, 'b':2, 'c':3 } - keys = ['a', 'c'] - returns [1, 3] - """ - - if not isinstance(data, list): - raise errors.AnsibleFilterError("|oo_select_keys_from_list failed expects to filter on a list") - - if not isinstance(keys, list): - raise errors.AnsibleFilterError("|oo_select_keys_from_list failed expects first param is a list") - - # Gather up the values for the list of keys passed in - retval = [oo_select_keys(item, keys) for item in data] - - return oo_flatten(retval) - - -def oo_select_keys(data, keys): - """ This returns a list, which contains the value portions for the keys - Ex: data = { 'a':1, 'b':2, 'c':3 } - keys = ['a', 'c'] - returns [1, 3] - """ - - if not isinstance(data, Mapping): - raise errors.AnsibleFilterError("|oo_select_keys failed expects to filter on a dict or object") - - if not isinstance(keys, list): - raise errors.AnsibleFilterError("|oo_select_keys failed expects first param is a list") - - # Gather up the values for the list of keys passed in - retval = [data[key] for key in keys if key in data] - - return retval - - -def oo_prepend_strings_in_list(data, prepend): - """ This takes a list of strings and prepends a string to each item in the - list - Ex: data = ['cart', 'tree'] - prepend = 'apple-' - returns ['apple-cart', 'apple-tree'] - """ - if not isinstance(data, list): - raise errors.AnsibleFilterError("|failed expects first param is a list") - if not all(isinstance(x, string_types) for x in data): - raise errors.AnsibleFilterError("|failed expects first param is a list" - " of strings") - retval = [prepend + s for s in data] - return retval - - -def oo_combine_key_value(data, joiner='='): - """Take a list of dict in the form of { 'key': 'value'} and - arrange them as a list of strings ['key=value'] - """ - if not isinstance(data, list): - raise errors.AnsibleFilterError("|failed expects first param is a list") - - rval = [] - for item in data: - rval.append("%s%s%s" % (item['key'], joiner, item['value'])) - - return rval - - -def oo_combine_dict(data, in_joiner='=', out_joiner=' '): - """Take a dict in the form of { 'key': 'value', 'key': 'value' } and - arrange them as a string 'key=value key=value' - """ - if not isinstance(data, dict): - # pylint: disable=line-too-long - raise errors.AnsibleFilterError("|failed expects first param is a dict [oo_combine_dict]. Got %s. Type: %s" % (str(data), str(type(data)))) - - return out_joiner.join([in_joiner.join([k, str(v)]) for k, v in data.items()]) - - -def oo_dict_to_list_of_dict(data, key_title='key', value_title='value'): - """Take a dict and arrange them as a list of dicts - - Input data: - {'region': 'infra', 'test_k': 'test_v'} - - Return data: - [{'key': 'region', 'value': 'infra'}, {'key': 'test_k', 'value': 'test_v'}] - - Written for use of the oc_label module - """ - if not isinstance(data, dict): - # pylint: disable=line-too-long - raise errors.AnsibleFilterError("|failed expects first param is a dict. Got %s. Type: %s" % (str(data), str(type(data)))) - - rval = [] - for label in data.items(): - rval.append({key_title: label[0], value_title: label[1]}) - - return rval - - -def oo_ami_selector(data, image_name): - """ This takes a list of amis and an image name and attempts to return - the latest ami. - """ - if not isinstance(data, list): - raise errors.AnsibleFilterError("|failed expects first param is a list") - - if not data: - return None - else: - if image_name is None or not image_name.endswith('_*'): - ami = sorted(data, key=itemgetter('name'), reverse=True)[0] - return ami['ami_id'] - else: - ami_info = [(ami, ami['name'].split('_')[-1]) for ami in data] - ami = sorted(ami_info, key=itemgetter(1), reverse=True)[0][0] - return ami['ami_id'] - - -def oo_ec2_volume_definition(data, host_type, docker_ephemeral=False): - """ This takes a dictionary of volume definitions and returns a valid ec2 - volume definition based on the host_type and the values in the - dictionary. - The dictionary should look similar to this: - { 'master': - { 'root': - { 'volume_size': 10, 'device_type': 'gp2', - 'iops': 500 - }, - 'docker': - { 'volume_size': 40, 'device_type': 'gp2', - 'iops': 500, 'ephemeral': 'true' - } - }, - 'node': - { 'root': - { 'volume_size': 10, 'device_type': 'io1', - 'iops': 1000 - }, - 'docker': - { 'volume_size': 40, 'device_type': 'gp2', - 'iops': 500, 'ephemeral': 'true' - } - } - } - """ - if not isinstance(data, dict): - # pylint: disable=line-too-long - raise errors.AnsibleFilterError("|failed expects first param is a dict [oo_ec2_volume_def]. Got %s. Type: %s" % (str(data), str(type(data)))) - if host_type not in ['master', 'node', 'etcd']: - raise errors.AnsibleFilterError("|failed expects etcd, master or node" - " as the host type") - - root_vol = data[host_type]['root'] - root_vol['device_name'] = '/dev/sda1' - root_vol['delete_on_termination'] = True - if root_vol['device_type'] != 'io1': - root_vol.pop('iops', None) - if host_type in ['master', 'node'] and 'docker' in data[host_type]: - docker_vol = data[host_type]['docker'] - docker_vol['device_name'] = '/dev/xvdb' - docker_vol['delete_on_termination'] = True - if docker_vol['device_type'] != 'io1': - docker_vol.pop('iops', None) - if docker_ephemeral: - docker_vol.pop('device_type', None) - docker_vol.pop('delete_on_termination', None) - docker_vol['ephemeral'] = 'ephemeral0' - return [root_vol, docker_vol] - elif host_type == 'etcd' and 'etcd' in data[host_type]: - etcd_vol = data[host_type]['etcd'] - etcd_vol['device_name'] = '/dev/xvdb' - etcd_vol['delete_on_termination'] = True - if etcd_vol['device_type'] != 'io1': - etcd_vol.pop('iops', None) - return [root_vol, etcd_vol] - return [root_vol] - - -def oo_split(string, separator=','): - """ This splits the input string into a list. If the input string is - already a list we will return it as is. - """ - if isinstance(string, list): - return string - return string.split(separator) - - -def oo_list_to_dict(lst, separator='='): - """ This converts a list of ["k=v"] to a dictionary {k: v}. - """ - kvs = [i.split(separator) for i in lst] - return {k: v for k, v in kvs} - - -def oo_haproxy_backend_masters(hosts, port): - """ This takes an array of dicts and returns an array of dicts - to be used as a backend for the haproxy role - """ - servers = [] - for idx, host_info in enumerate(hosts): - server = dict(name="master%s" % idx) - server_ip = host_info['openshift']['common']['ip'] - server['address'] = "%s:%s" % (server_ip, port) - server['opts'] = 'check' - servers.append(server) - return servers - - -def oo_filter_list(data, filter_attr=None): - """ This returns a list, which contains all items where filter_attr - evaluates to true - Ex: data = [ { a: 1, b: True }, - { a: 3, b: False }, - { a: 5, b: True } ] - filter_attr = 'b' - returns [ { a: 1, b: True }, - { a: 5, b: True } ] - """ - if not isinstance(data, list): - raise errors.AnsibleFilterError("|failed expects to filter on a list") - - if not isinstance(filter_attr, string_types): - raise errors.AnsibleFilterError("|failed expects filter_attr is a str or unicode") - - # Gather up the values for the list of keys passed in - return [x for x in data if filter_attr in x and x[filter_attr]] - - -def oo_nodes_with_label(nodes, label, value=None): - """ Filters a list of nodes by label and value (if provided) - - It handles labels that are in the following variables by priority: - openshift_node_labels, cli_openshift_node_labels, openshift['node']['labels'] - - Examples: - data = ['a': {'openshift_node_labels': {'color': 'blue', 'size': 'M'}}, - 'b': {'openshift_node_labels': {'color': 'green', 'size': 'L'}}, - 'c': {'openshift_node_labels': {'size': 'S'}}] - label = 'color' - returns = ['a': {'openshift_node_labels': {'color': 'blue', 'size': 'M'}}, - 'b': {'openshift_node_labels': {'color': 'green', 'size': 'L'}}] - - data = ['a': {'openshift_node_labels': {'color': 'blue', 'size': 'M'}}, - 'b': {'openshift_node_labels': {'color': 'green', 'size': 'L'}}, - 'c': {'openshift_node_labels': {'size': 'S'}}] - label = 'color' - value = 'green' - returns = ['b': {'labels': {'color': 'green', 'size': 'L'}}] - - Args: - nodes (list[dict]): list of node to node variables - label (str): label to filter `nodes` by - value (Optional[str]): value of `label` to filter by Defaults - to None. - - Returns: - list[dict]: nodes filtered by label and value (if provided) - """ - if not isinstance(nodes, list): - raise errors.AnsibleFilterError("failed expects to filter on a list") - if not isinstance(label, string_types): - raise errors.AnsibleFilterError("failed expects label to be a string") - if value is not None and not isinstance(value, string_types): - raise errors.AnsibleFilterError("failed expects value to be a string") - - def label_filter(node): - """ filter function for testing if node should be returned """ - if not isinstance(node, dict): - raise errors.AnsibleFilterError("failed expects to filter on a list of dicts") - if 'openshift_node_labels' in node: - labels = node['openshift_node_labels'] - elif 'cli_openshift_node_labels' in node: - labels = node['cli_openshift_node_labels'] - elif 'openshift' in node and 'node' in node['openshift'] and 'labels' in node['openshift']['node']: - labels = node['openshift']['node']['labels'] - else: - return False - - if isinstance(labels, string_types): - labels = yaml.safe_load(labels) - if not isinstance(labels, dict): - raise errors.AnsibleFilterError( - "failed expected node labels to be a dict or serializable to a dict" - ) - return label in labels and (value is None or labels[label] == value) - - return [n for n in nodes if label_filter(n)] - - -def oo_parse_heat_stack_outputs(data): - """ Formats the HEAT stack output into a usable form - - The goal is to transform something like this: - - +---------------+-------------------------------------------------+ - | Property | Value | - +---------------+-------------------------------------------------+ - | capabilities | [] | | - | creation_time | 2015-06-26T12:26:26Z | | - | description | OpenShift cluster | | - | … | … | - | outputs | [ | - | | { | - | | "output_value": "value_A" | - | | "description": "This is the value of Key_A" | - | | "output_key": "Key_A" | - | | }, | - | | { | - | | "output_value": [ | - | | "value_B1", | - | | "value_B2" | - | | ], | - | | "description": "This is the value of Key_B" | - | | "output_key": "Key_B" | - | | }, | - | | ] | - | parameters | { | - | … | … | - +---------------+-------------------------------------------------+ - - into something like this: - - { - "Key_A": "value_A", - "Key_B": [ - "value_B1", - "value_B2" - ] - } - """ - - # Extract the “outputs” JSON snippet from the pretty-printed array - in_outputs = False - outputs = '' - - line_regex = re.compile(r'\|\s*(.*?)\s*\|\s*(.*?)\s*\|') - for line in data['stdout_lines']: - match = line_regex.match(line) - if match: - if match.group(1) == 'outputs': - in_outputs = True - elif match.group(1) != '': - in_outputs = False - if in_outputs: - outputs += match.group(2) - - outputs = json.loads(outputs) - - # Revamp the “outputs” to put it in the form of a “Key: value” map - revamped_outputs = {} - for output in outputs: - revamped_outputs[output['output_key']] = output['output_value'] - - return revamped_outputs - - -# pylint: disable=too-many-branches -def oo_parse_named_certificates(certificates, named_certs_dir, internal_hostnames): - """ Parses names from list of certificate hashes. - - Ex: certificates = [{ "certfile": "/root/custom1.crt", - "keyfile": "/root/custom1.key", - "cafile": "/root/custom-ca1.crt" }, - { "certfile": "custom2.crt", - "keyfile": "custom2.key", - "cafile": "custom-ca2.crt" }] - - returns [{ "certfile": "/etc/origin/master/named_certificates/custom1.crt", - "keyfile": "/etc/origin/master/named_certificates/custom1.key", - "cafile": "/etc/origin/master/named_certificates/custom-ca1.crt", - "names": [ "public-master-host.com", - "other-master-host.com" ] }, - { "certfile": "/etc/origin/master/named_certificates/custom2.crt", - "keyfile": "/etc/origin/master/named_certificates/custom2.key", - "cafile": "/etc/origin/master/named_certificates/custom-ca-2.crt", - "names": [ "some-hostname.com" ] }] - """ - if not isinstance(named_certs_dir, string_types): - raise errors.AnsibleFilterError("|failed expects named_certs_dir is str or unicode") - - if not isinstance(internal_hostnames, list): - raise errors.AnsibleFilterError("|failed expects internal_hostnames is list") - - if not HAS_OPENSSL: - raise errors.AnsibleFilterError("|missing OpenSSL python bindings") - - for certificate in certificates: - if 'names' in certificate.keys(): - continue - else: - certificate['names'] = [] - - if not os.path.isfile(certificate['certfile']) or not os.path.isfile(certificate['keyfile']): - raise errors.AnsibleFilterError("|certificate and/or key does not exist '%s', '%s'" % - (certificate['certfile'], certificate['keyfile'])) - - try: - st_cert = open(certificate['certfile'], 'rt').read() - cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, st_cert) - certificate['names'].append(str(cert.get_subject().commonName.decode())) - for i in range(cert.get_extension_count()): - if cert.get_extension(i).get_short_name() == 'subjectAltName': - for name in str(cert.get_extension(i)).replace('DNS:', '').split(', '): - certificate['names'].append(name) - except Exception: - raise errors.AnsibleFilterError(("|failed to parse certificate '%s', " % certificate['certfile'] + - "please specify certificate names in host inventory")) - - certificate['names'] = list(set(certificate['names'])) - if 'cafile' not in certificate: - certificate['names'] = [name for name in certificate['names'] if name not in internal_hostnames] - if not certificate['names']: - raise errors.AnsibleFilterError(("|failed to parse certificate '%s' or " % certificate['certfile'] + - "detected a collision with internal hostname, please specify " + - "certificate names in host inventory")) - - for certificate in certificates: - # Update paths for configuration - certificate['certfile'] = os.path.join(named_certs_dir, os.path.basename(certificate['certfile'])) - certificate['keyfile'] = os.path.join(named_certs_dir, os.path.basename(certificate['keyfile'])) - if 'cafile' in certificate: - certificate['cafile'] = os.path.join(named_certs_dir, os.path.basename(certificate['cafile'])) - return certificates - - -def oo_pretty_print_cluster(data, prefix='tag_'): - """ Read a subset of hostvars and build a summary of the cluster - in the following layout: - -"c_id": { -"master": { -"default": [ - { "name": "c_id-master-12345", "public IP": "172.16.0.1", "private IP": "192.168.0.1" } -] -"node": { -"infra": [ - { "name": "c_id-node-infra-23456", "public IP": "172.16.0.2", "private IP": "192.168.0.2" } -], -"compute": [ - { "name": "c_id-node-compute-23456", "public IP": "172.16.0.3", "private IP": "192.168.0.3" }, -... -] -} - """ - - def _get_tag_value(tags, key): - """ Extract values of a map implemented as a set. - Ex: tags = { 'tag_foo_value1', 'tag_bar_value2', 'tag_baz_value3' } - key = 'bar' - returns 'value2' - """ - for tag in tags: - if tag[:len(prefix) + len(key)] == prefix + key: - return tag[len(prefix) + len(key) + 1:] - raise KeyError(key) - - def _add_host(clusters, - clusterid, - host_type, - sub_host_type, - host): - """ Add a new host in the clusters data structure """ - if clusterid not in clusters: - clusters[clusterid] = {} - if host_type not in clusters[clusterid]: - clusters[clusterid][host_type] = {} - if sub_host_type not in clusters[clusterid][host_type]: - clusters[clusterid][host_type][sub_host_type] = [] - clusters[clusterid][host_type][sub_host_type].append(host) - - clusters = {} - for host in data: - try: - _add_host(clusters=clusters, - clusterid=_get_tag_value(host['group_names'], 'clusterid'), - host_type=_get_tag_value(host['group_names'], 'host-type'), - sub_host_type=_get_tag_value(host['group_names'], 'sub-host-type'), - host={'name': host['inventory_hostname'], - 'public IP': host['oo_public_ipv4'], - 'private IP': host['oo_private_ipv4']}) - except KeyError: - pass - return clusters - - -def oo_generate_secret(num_bytes): - """ generate a session secret """ - - if not isinstance(num_bytes, int): - raise errors.AnsibleFilterError("|failed expects num_bytes is int") - - return b64encode(os.urandom(num_bytes)).decode('utf-8') - - -def to_padded_yaml(data, level=0, indent=2, **kw): - """ returns a yaml snippet padded to match the indent level you specify """ - if data in [None, ""]: - return "" - - try: - transformed = u(yaml.dump(data, indent=indent, allow_unicode=True, - default_flow_style=False, - Dumper=AnsibleDumper, **kw)) - padded = "\n".join([" " * level * indent + line for line in transformed.splitlines()]) - return "\n{0}".format(padded) - except Exception as my_e: - raise errors.AnsibleFilterError('Failed to convert: %s' % my_e) - - -def oo_31_rpm_rename_conversion(rpms, openshift_version=None): - """ Filters a list of 3.0 rpms and return the corresponding 3.1 rpms - names with proper version (if provided) - - If 3.1 rpms are passed in they will only be augmented with the - correct version. This is important for hosts that are running both - Masters and Nodes. - """ - if not isinstance(rpms, list): - raise errors.AnsibleFilterError("failed expects to filter on a list") - if openshift_version is not None and not isinstance(openshift_version, string_types): - raise errors.AnsibleFilterError("failed expects openshift_version to be a string") - - rpms_31 = [] - for rpm in rpms: - if 'atomic' not in rpm: - rpm = rpm.replace("openshift", "atomic-openshift") - if openshift_version: - rpm = rpm + openshift_version - rpms_31.append(rpm) - - return rpms_31 - - -def oo_pods_match_component(pods, deployment_type, component): - """ Filters a list of Pods and returns the ones matching the deployment_type and component - """ - if not isinstance(pods, list): - raise errors.AnsibleFilterError("failed expects to filter on a list") - if not isinstance(deployment_type, string_types): - raise errors.AnsibleFilterError("failed expects deployment_type to be a string") - if not isinstance(component, string_types): - raise errors.AnsibleFilterError("failed expects component to be a string") - - image_prefix = 'openshift/origin-' - if deployment_type == 'openshift-enterprise': - image_prefix = 'openshift3/ose-' - - matching_pods = [] - image_regex = image_prefix + component + r'.*' - for pod in pods: - for container in pod['spec']['containers']: - if re.search(image_regex, container['image']): - matching_pods.append(pod) - break # stop here, don't add a pod more than once - - return matching_pods - - -def oo_get_hosts_from_hostvars(hostvars, hosts): - """ Return a list of hosts from hostvars """ - retval = [] - for host in hosts: - try: - retval.append(hostvars[host]) - except errors.AnsibleError: - # host does not exist - pass - - return retval - - -def oo_image_tag_to_rpm_version(version, include_dash=False): - """ Convert an image tag string to an RPM version if necessary - Empty strings and strings that are already in rpm version format - are ignored. Also remove non semantic version components. - - Ex. v3.2.0.10 -> -3.2.0.10 - v1.2.0-rc1 -> -1.2.0 - """ - if not isinstance(version, string_types): - raise errors.AnsibleFilterError("|failed expects a string or unicode") - if version.startswith("v"): - version = version[1:] - # Strip release from requested version, we no longer support this. - version = version.split('-')[0] - - if include_dash and version and not version.startswith("-"): - version = "-" + version - - return version - - -def oo_hostname_from_url(url): - """ Returns the hostname contained in a URL - - Ex: https://ose3-master.example.com/v1/api -> ose3-master.example.com - """ - if not isinstance(url, string_types): - raise errors.AnsibleFilterError("|failed expects a string or unicode") - parse_result = urlparse(url) - if parse_result.netloc != '': - return parse_result.netloc - else: - # netloc wasn't parsed, assume url was missing scheme and path - return parse_result.path - - -# pylint: disable=invalid-name, unused-argument -def oo_openshift_loadbalancer_frontends( - api_port, servers_hostvars, use_nuage=False, nuage_rest_port=None): - """TODO: Document me.""" - loadbalancer_frontends = [{'name': 'atomic-openshift-api', - 'mode': 'tcp', - 'options': ['tcplog'], - 'binds': ["*:{0}".format(api_port)], - 'default_backend': 'atomic-openshift-api'}] - if bool(strtobool(str(use_nuage))) and nuage_rest_port is not None: - loadbalancer_frontends.append({'name': 'nuage-monitor', - 'mode': 'tcp', - 'options': ['tcplog'], - 'binds': ["*:{0}".format(nuage_rest_port)], - 'default_backend': 'nuage-monitor'}) - return loadbalancer_frontends - - -# pylint: disable=invalid-name -def oo_openshift_loadbalancer_backends( - api_port, servers_hostvars, use_nuage=False, nuage_rest_port=None): - """TODO: Document me.""" - loadbalancer_backends = [{'name': 'atomic-openshift-api', - 'mode': 'tcp', - 'option': 'tcplog', - 'balance': 'source', - 'servers': oo_haproxy_backend_masters(servers_hostvars, api_port)}] - if bool(strtobool(str(use_nuage))) and nuage_rest_port is not None: - # pylint: disable=line-too-long - loadbalancer_backends.append({'name': 'nuage-monitor', - 'mode': 'tcp', - 'option': 'tcplog', - 'balance': 'source', - 'servers': oo_haproxy_backend_masters(servers_hostvars, nuage_rest_port)}) - return loadbalancer_backends - - -def oo_chomp_commit_offset(version): - """Chomp any "+git.foo" commit offset string from the given `version` - and return the modified version string. - -Ex: -- chomp_commit_offset(None) => None -- chomp_commit_offset(1337) => "1337" -- chomp_commit_offset("v3.4.0.15+git.derp") => "v3.4.0.15" -- chomp_commit_offset("v3.4.0.15") => "v3.4.0.15" -- chomp_commit_offset("v1.3.0+52492b4") => "v1.3.0" - """ - if version is None: - return version - else: - # Stringify, just in case it's a Number type. Split by '+' and - # return the first split. No concerns about strings without a - # '+', .split() returns an array of the original string. - return str(version).split('+')[0] - - -def oo_random_word(length, source='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'): - """Generates a random string of given length from a set of alphanumeric characters. - The default source uses [a-z][A-Z][0-9] - Ex: - - oo_random_word(3) => aB9 - - oo_random_word(4, source='012') => 0123 - """ - return ''.join(random.choice(source) for i in range(length)) - - -def oo_contains_rule(source, apiGroups, resources, verbs): - '''Return true if the specified rule is contained within the provided source''' - - rules = source['rules'] - - if rules: - for rule in rules: - if set(rule['apiGroups']) == set(apiGroups): - if set(rule['resources']) == set(resources): - if set(rule['verbs']) == set(verbs): - return True - - return False - - -def oo_selector_to_string_list(user_dict): - """Convert a dict of selectors to a key=value list of strings - -Given input of {'region': 'infra', 'zone': 'primary'} returns a list -of items as ['region=infra', 'zone=primary'] - """ - selectors = [] - for key in user_dict: - selectors.append("{}={}".format(key, user_dict[key])) - return selectors - - -def oo_filter_sa_secrets(sa_secrets, secret_hint='-token-'): - """Parse the Service Account Secrets list, `sa_secrets`, (as from -oc_serviceaccount_secret:state=list) and return the name of the secret -containing the `secret_hint` string. For example, by default this will -return the name of the secret holding the SA bearer token. - -Only provide the 'results' object to this filter. This filter expects -to receive a list like this: - - [ - { - "name": "management-admin-dockercfg-p31s2" - }, - { - "name": "management-admin-token-bnqsh" - } - ] - - -Returns: - -* `secret_name` [string] - The name of the secret matching the - `secret_hint` parameter. By default this is the secret holding the - SA's bearer token. - -Example playbook usage: - -Register a return value from oc_serviceaccount_secret with and pass -that result to this filter plugin. - - - name: Get all SA Secrets - oc_serviceaccount_secret: - state: list - service_account: management-admin - namespace: management-infra - register: sa - - - name: Save the SA bearer token secret name - set_fact: - management_token: "{{ sa.results | oo_filter_sa_secrets }}" - - - name: Get the SA bearer token value - oc_secret: - state: list - name: "{{ management_token }}" - namespace: management-infra - decode: true - register: sa_secret - - - name: Print the bearer token value - debug: - var: sa_secret.results.decoded.token - - """ - secret_name = None - - for secret in sa_secrets: - # each secret is a hash - if secret['name'].find(secret_hint) == -1: - continue - else: - secret_name = secret['name'] - break - - return secret_name - - -class FilterModule(object): - """ Custom ansible filter mapping """ - - # pylint: disable=no-self-use, too-few-public-methods - def filters(self): - """ returns a mapping of filters to methods """ - return { - "oo_select_keys": oo_select_keys, - "oo_select_keys_from_list": oo_select_keys_from_list, - "oo_chomp_commit_offset": oo_chomp_commit_offset, - "oo_collect": oo_collect, - "oo_flatten": oo_flatten, - "oo_pdb": oo_pdb, - "oo_prepend_strings_in_list": oo_prepend_strings_in_list, - "oo_ami_selector": oo_ami_selector, - "oo_ec2_volume_definition": oo_ec2_volume_definition, - "oo_combine_key_value": oo_combine_key_value, - "oo_combine_dict": oo_combine_dict, - "oo_dict_to_list_of_dict": oo_dict_to_list_of_dict, - "oo_split": oo_split, - "oo_list_to_dict": oo_list_to_dict, - "oo_filter_list": oo_filter_list, - "oo_parse_heat_stack_outputs": oo_parse_heat_stack_outputs, - "oo_parse_named_certificates": oo_parse_named_certificates, - "oo_haproxy_backend_masters": oo_haproxy_backend_masters, - "oo_pretty_print_cluster": oo_pretty_print_cluster, - "oo_generate_secret": oo_generate_secret, - "oo_nodes_with_label": oo_nodes_with_label, - "oo_31_rpm_rename_conversion": oo_31_rpm_rename_conversion, - "oo_pods_match_component": oo_pods_match_component, - "oo_get_hosts_from_hostvars": oo_get_hosts_from_hostvars, - "oo_image_tag_to_rpm_version": oo_image_tag_to_rpm_version, - "oo_merge_dicts": oo_merge_dicts, - "oo_hostname_from_url": oo_hostname_from_url, - "oo_merge_hostvars": oo_merge_hostvars, - "oo_openshift_loadbalancer_frontends": oo_openshift_loadbalancer_frontends, - "oo_openshift_loadbalancer_backends": oo_openshift_loadbalancer_backends, - "to_padded_yaml": to_padded_yaml, - "oo_random_word": oo_random_word, - "oo_contains_rule": oo_contains_rule, - "oo_selector_to_string_list": oo_selector_to_string_list, - "oo_filter_sa_secrets": oo_filter_sa_secrets, - } diff --git a/filter_plugins/openshift_version.py b/filter_plugins/openshift_version.py deleted file mode 100644 index 7a70b158b..000000000 --- a/filter_plugins/openshift_version.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -""" -Custom version comparison filters for use in openshift-ansible -""" - -# pylint can't locate distutils.version within virtualenv -# https://github.com/PyCQA/pylint/issues/73 -# pylint: disable=no-name-in-module, import-error -from distutils.version import LooseVersion - - -def gte_function_builder(name, gte_version): - """ - Build and return a version comparison function. - - Ex: name = 'oo_version_gte_3_6' - version = '3.6' - - returns oo_version_gte_3_6, a function which based on the - version will return true if the provided version is greater - than or equal to the function's version - """ - def _gte_function(version): - """ - Dynamic function created by gte_function_builder. - - Ex: version = '3.1' - returns True/False - """ - version_gte = False - if str(version) >= LooseVersion(gte_version): - version_gte = True - return version_gte - _gte_function.__name__ = name - return _gte_function - - -# pylint: disable=too-few-public-methods -class FilterModule(object): - """ - Filters for version checking. - """ - # Each element of versions is composed of (major, minor_start, minor_end) - # Origin began versioning 3.x with 3.6, so begin 3.x with 3.6. - versions = [(3, 6, 10)] - - def __init__(self): - """ - Creates a new FilterModule for ose version checking. - """ - self._filters = {} - - # For each set of (major, minor, minor_iterations) - for major, minor_start, minor_end in self.versions: - # For each minor version in the range - for minor in range(minor_start, minor_end): - # Create the function name - func_name = 'oo_version_gte_{}_{}'.format(major, minor) - # Create the function with the builder - func = gte_function_builder(func_name, "{}.{}.0".format(major, minor)) - # Add the function to the mapping - self._filters[func_name] = func - - def filters(self): - """ - Return the filters mapping. - """ - return self._filters |