summaryrefslogtreecommitdiffstats
path: root/filter_plugins
diff options
context:
space:
mode:
Diffstat (limited to 'filter_plugins')
-rw-r--r--filter_plugins/oo_filters.py273
-rw-r--r--filter_plugins/openshift_master.py33
-rw-r--r--filter_plugins/openshift_node.py43
3 files changed, 295 insertions, 54 deletions
diff --git a/filter_plugins/oo_filters.py b/filter_plugins/oo_filters.py
index cd67b69a5..e7409bf22 100644
--- a/filter_plugins/oo_filters.py
+++ b/filter_plugins/oo_filters.py
@@ -6,10 +6,13 @@ Custom filters for use in openshift-ansible
"""
from ansible import errors
+from collections import Mapping
+from distutils.version import LooseVersion
from operator import itemgetter
import OpenSSL.crypto
import os
import pdb
+import pkg_resources
import re
import json
import yaml
@@ -57,6 +60,55 @@ class FilterModule(object):
return [item for sublist in data for item in sublist]
@staticmethod
+ 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
+
+ @staticmethod
+ 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, basestring):
+ raise errors.AnsibleFilterError("|failed expects inventory_hostname is a string")
+ # pylint: disable=no-member
+ ansible_version = pkg_resources.get_distribution("ansible").version
+ merged_hostvars = {}
+ if LooseVersion(ansible_version) >= LooseVersion('2.0.0'):
+ merged_hostvars = FilterModule.oo_merge_dicts(hostvars[inventory_hostname],
+ variables)
+ else:
+ merged_hostvars = FilterModule.oo_merge_dicts(hostvars[inventory_hostname],
+ hostvars)
+ return merged_hostvars
+
+ @staticmethod
def oo_collect(data, 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
@@ -115,14 +167,14 @@ class FilterModule(object):
returns [1, 3]
"""
- if not isinstance(data, dict):
- raise errors.AnsibleFilterError("|failed expects to filter on a dict")
+ if not isinstance(data, Mapping):
+ raise errors.AnsibleFilterError("|failed expects to filter on a dict or object")
if not isinstance(keys, list):
raise errors.AnsibleFilterError("|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 data.has_key(key)]
+ retval = [data[key] for key in keys if key in data]
return retval
@@ -246,8 +298,11 @@ class FilterModule(object):
@staticmethod
def oo_split(string, separator=','):
- """ This splits the input string into a list
+ """ 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)
@staticmethod
@@ -283,7 +338,86 @@ class FilterModule(object):
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 x.has_key(filter_attr) and x[filter_attr]]
+ return [x for x in data if filter_attr in x and x[filter_attr]]
+
+ @staticmethod
+ def oo_oc_nodes_matching_selector(nodes, selector):
+ """ Filters a list of nodes by selector.
+
+ Examples:
+ nodes = [{"kind": "Node", "metadata": {"name": "node1.example.com",
+ "labels": {"kubernetes.io/hostname": "node1.example.com",
+ "color": "green"}}},
+ {"kind": "Node", "metadata": {"name": "node2.example.com",
+ "labels": {"kubernetes.io/hostname": "node2.example.com",
+ "color": "red"}}}]
+ selector = 'color=green'
+ returns = ['node1.example.com']
+
+ nodes = [{"kind": "Node", "metadata": {"name": "node1.example.com",
+ "labels": {"kubernetes.io/hostname": "node1.example.com",
+ "color": "green"}}},
+ {"kind": "Node", "metadata": {"name": "node2.example.com",
+ "labels": {"kubernetes.io/hostname": "node2.example.com",
+ "color": "red"}}}]
+ selector = 'color=green,color=red'
+ returns = ['node1.example.com','node2.example.com']
+
+ Args:
+ nodes (list[dict]): list of node definitions
+ selector (str): "label=value" node selector to filter `nodes` by
+ Returns:
+ list[str]: nodes filtered by selector
+ """
+ if not isinstance(nodes, list):
+ raise errors.AnsibleFilterError("failed expects nodes to be a list, got {0}".format(type(nodes)))
+ if not isinstance(selector, basestring):
+ raise errors.AnsibleFilterError("failed expects selector to be a string")
+ if not re.match('.*=.*', selector):
+ raise errors.AnsibleFilterError("failed selector does not match \"label=value\" format")
+ node_lists = []
+ for node_selector in ''.join(selector.split()).split(','):
+ label = node_selector.split('=')[0]
+ value = node_selector.split('=')[1]
+ node_lists.append(FilterModule.oo_oc_nodes_with_label(nodes, label, value))
+ nodes = set(node_lists[0])
+ for node_list in node_lists[1:]:
+ nodes.intersection_update(node_list)
+ return list(nodes)
+
+ @staticmethod
+ def oo_oc_nodes_with_label(nodes, label, value):
+ """ Filters a list of nodes by label, value.
+
+ Examples:
+ nodes = [{"kind": "Node", "metadata": {"name": "node1.example.com",
+ "labels": {"kubernetes.io/hostname": "node1.example.com",
+ "color": "green"}}},
+ {"kind": "Node", "metadata": {"name": "node2.example.com",
+ "labels": {"kubernetes.io/hostname": "node2.example.com",
+ "color": "red"}}}]
+ label = 'color'
+ value = 'green'
+ returns = ['node1.example.com']
+ Args:
+ nodes (list[dict]): list of node definitions
+ label (str): label to filter `nodes` by
+ value (str): value of `label` to filter `nodes` by
+ Returns:
+ list[str]: nodes filtered by selector
+ """
+ if not isinstance(nodes, list):
+ raise errors.AnsibleFilterError("failed expects nodes to be a list")
+ if not isinstance(label, basestring):
+ raise errors.AnsibleFilterError("failed expects label to be a string")
+ if not isinstance(value, basestring):
+ raise errors.AnsibleFilterError("failed expects value to be a string")
+ matching_nodes = []
+ for node in nodes:
+ if label in node['metadata']['labels']:
+ if node['metadata']['labels'][label] == value:
+ matching_nodes.append(node['metadata']['name'])
+ return matching_nodes
@staticmethod
def oo_nodes_with_label(nodes, label, value=None):
@@ -558,7 +692,9 @@ class FilterModule(object):
@staticmethod
def oo_openshift_env(hostvars):
- ''' Return facts which begin with "openshift_"
+ ''' Return facts which begin with "openshift_" and translate
+ legacy facts to their openshift_env counterparts.
+
Ex: hostvars = {'openshift_fact': 42,
'theyre_taking_the_hobbits_to': 'isengard'}
returns = {'openshift_fact': 42}
@@ -571,6 +707,11 @@ class FilterModule(object):
for key in hostvars:
if regex.match(key):
facts[key] = hostvars[key]
+
+ migrations = {'openshift_router_selector': 'openshift_hosted_router_selector'}
+ for old_fact, new_fact in migrations.iteritems():
+ if old_fact in facts and new_fact not in facts:
+ facts[new_fact] = facts[old_fact]
return facts
@staticmethod
@@ -588,36 +729,54 @@ class FilterModule(object):
if persistent_volumes == None:
persistent_volumes = []
- for component in hostvars['openshift']['hosted']:
- kind = hostvars['openshift']['hosted'][component]['storage']['kind']
- create_pv = hostvars['openshift']['hosted'][component]['storage']['create_pv']
- if kind != None and create_pv:
- if kind == 'nfs':
- host = hostvars['openshift']['hosted'][component]['storage']['host']
- if host == None:
- if len(groups['oo_nfs_to_config']) > 0:
- host = groups['oo_nfs_to_config'][0]
+ if 'hosted' in hostvars['openshift']:
+ for component in hostvars['openshift']['hosted']:
+ if 'storage' in hostvars['openshift']['hosted'][component]:
+ params = hostvars['openshift']['hosted'][component]['storage']
+ kind = params['kind']
+ create_pv = params['create_pv']
+ if kind != None and create_pv:
+ if kind == 'nfs':
+ host = params['host']
+ if host == None:
+ if len(groups['oo_nfs_to_config']) > 0:
+ host = groups['oo_nfs_to_config'][0]
+ else:
+ raise errors.AnsibleFilterError("|failed no storage host detected")
+ directory = params['nfs']['directory']
+ volume = params['volume']['name']
+ path = directory + '/' + volume
+ size = params['volume']['size']
+ access_modes = params['access_modes']
+ persistent_volume = dict(
+ name="{0}-volume".format(volume),
+ capacity=size,
+ access_modes=access_modes,
+ storage=dict(
+ nfs=dict(
+ server=host,
+ path=path)))
+ persistent_volumes.append(persistent_volume)
+ elif kind == 'openstack':
+ volume = params['volume']['name']
+ size = params['volume']['size']
+ access_modes = params['access_modes']
+ filesystem = params['openstack']['filesystem']
+ volume_id = params['openstack']['volumeID']
+ persistent_volume = dict(
+ name="{0}-volume".format(volume),
+ capacity=size,
+ access_modes=access_modes,
+ storage=dict(
+ cinder=dict(
+ fsType=filesystem,
+ volumeID=volume_id)))
+ persistent_volumes.append(persistent_volume)
else:
- raise errors.AnsibleFilterError("|failed no storage host detected")
- directory = hostvars['openshift']['hosted'][component]['storage']['nfs']['directory']
- volume = hostvars['openshift']['hosted'][component]['storage']['volume']['name']
- path = directory + '/' + volume
- size = hostvars['openshift']['hosted'][component]['storage']['volume']['size']
- access_modes = hostvars['openshift']['hosted'][component]['storage']['access_modes']
- persistent_volume = dict(
- name="{0}-volume".format(volume),
- capacity=size,
- access_modes=access_modes,
- storage=dict(
- nfs=dict(
- server=host,
- path=path)))
- persistent_volumes.append(persistent_volume)
- else:
- msg = "|failed invalid storage kind '{0}' for component '{1}'".format(
- kind,
- component)
- raise errors.AnsibleFilterError(msg)
+ msg = "|failed invalid storage kind '{0}' for component '{1}'".format(
+ kind,
+ component)
+ raise errors.AnsibleFilterError(msg)
return persistent_volumes
@staticmethod
@@ -632,18 +791,20 @@ class FilterModule(object):
if persistent_volume_claims == None:
persistent_volume_claims = []
- for component in hostvars['openshift']['hosted']:
- kind = hostvars['openshift']['hosted'][component]['storage']['kind']
- create_pv = hostvars['openshift']['hosted'][component]['storage']['create_pv']
- if kind != None and create_pv:
- volume = hostvars['openshift']['hosted'][component]['storage']['volume']['name']
- size = hostvars['openshift']['hosted'][component]['storage']['volume']['size']
- access_modes = hostvars['openshift']['hosted'][component]['storage']['access_modes']
- persistent_volume_claim = dict(
- name="{0}-claim".format(volume),
- capacity=size,
- access_modes=access_modes)
- persistent_volume_claims.append(persistent_volume_claim)
+ if 'hosted' in hostvars['openshift']:
+ for component in hostvars['openshift']['hosted']:
+ if 'storage' in hostvars['openshift']['hosted'][component]:
+ kind = hostvars['openshift']['hosted'][component]['storage']['kind']
+ create_pv = hostvars['openshift']['hosted'][component]['storage']['create_pv']
+ if kind != None and create_pv:
+ volume = hostvars['openshift']['hosted'][component]['storage']['volume']['name']
+ size = hostvars['openshift']['hosted'][component]['storage']['volume']['size']
+ access_modes = hostvars['openshift']['hosted'][component]['storage']['access_modes']
+ persistent_volume_claim = dict(
+ name="{0}-claim".format(volume),
+ capacity=size,
+ access_modes=access_modes)
+ persistent_volume_claims.append(persistent_volume_claim)
return persistent_volume_claims
@staticmethod
@@ -711,18 +872,24 @@ class FilterModule(object):
return retval
@staticmethod
- def oo_image_tag_to_rpm_version(version):
+ 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.
+ 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, basestring):
raise errors.AnsibleFilterError("|failed expects a string or unicode")
-
+ # TODO: Do we need to make this actually convert v1.2.0-rc1 into 1.2.0-0.rc1
+ # We'd need to be really strict about how we build the RPM Version+Release
if version.startswith("v"):
- version = "-" + version.replace("v", "")
+ version = version.replace("v", "")
+ version = version.split('-')[0]
+
+ if include_dash:
+ version = "-" + version
return version
@@ -755,4 +922,8 @@ class FilterModule(object):
"oo_pods_match_component": self.oo_pods_match_component,
"oo_get_hosts_from_hostvars": self.oo_get_hosts_from_hostvars,
"oo_image_tag_to_rpm_version": self.oo_image_tag_to_rpm_version,
+ "oo_merge_dicts": self.oo_merge_dicts,
+ "oo_oc_nodes_matching_selector": self.oo_oc_nodes_matching_selector,
+ "oo_oc_nodes_with_label": self.oo_oc_nodes_with_label,
+ "oo_merge_hostvars": self.oo_merge_hostvars,
}
diff --git a/filter_plugins/openshift_master.py b/filter_plugins/openshift_master.py
index d0fb98ec3..bb2f5ba7a 100644
--- a/filter_plugins/openshift_master.py
+++ b/filter_plugins/openshift_master.py
@@ -9,8 +9,14 @@ import sys
import yaml
from ansible import errors
-from ansible.runner.filter_plugins.core import bool as ansible_bool
+# pylint: disable=no-name-in-module,import-error
+try:
+ # ansible-2.0
+ from ansible.runner.filter_plugins.core import bool as ansible_bool
+except ImportError:
+ # ansible-1.9.x
+ from ansible.plugins.filter.core import bool as ansible_bool
class IdentityProviderBase(object):
""" IdentityProviderBase
@@ -57,7 +63,7 @@ class IdentityProviderBase(object):
mapping_method = None
for key in mm_keys:
if key in self._idp:
- mapping_method = self._idp[key]
+ mapping_method = self._idp.pop(key)
if mapping_method is None:
mapping_method = self.get_default('mappingMethod')
self.mapping_method = mapping_method
@@ -527,9 +533,30 @@ class FilterModule(object):
'openshift-master.kubeconfig']
return certs
+ @staticmethod
+ def oo_htpasswd_users_from_file(file_contents):
+ ''' return a dictionary of htpasswd users from htpasswd file contents '''
+ htpasswd_entries = {}
+ if not isinstance(file_contents, basestring):
+ raise errors.AnsibleFilterError("failed, expects to filter on a string")
+ for line in file_contents.splitlines():
+ user = None
+ passwd = None
+ if len(line) == 0:
+ continue
+ if ':' in line:
+ user, passwd = line.split(':', 1)
+
+ if user is None or len(user) == 0 or passwd is None or len(passwd) == 0:
+ error_msg = "failed, expects each line to be a colon separated string representing the user and passwd"
+ raise errors.AnsibleFilterError(error_msg)
+ htpasswd_entries[user] = passwd
+ return htpasswd_entries
+
def filters(self):
''' returns a mapping of filters to methods '''
return {"translate_idps": self.translate_idps,
"validate_pcs_cluster": self.validate_pcs_cluster,
- "certificates_to_synchronize": self.certificates_to_synchronize}
+ "certificates_to_synchronize": self.certificates_to_synchronize,
+ "oo_htpasswd_users_from_file": self.oo_htpasswd_users_from_file}
diff --git a/filter_plugins/openshift_node.py b/filter_plugins/openshift_node.py
new file mode 100644
index 000000000..22670cf79
--- /dev/null
+++ b/filter_plugins/openshift_node.py
@@ -0,0 +1,43 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# vim: expandtab:tabstop=4:shiftwidth=4
+'''
+Custom filters for use in openshift-node
+'''
+from ansible import errors
+
+class FilterModule(object):
+ ''' Custom ansible filters for use by openshift_node role'''
+
+ @staticmethod
+ def get_dns_ip(openshift_dns_ip, hostvars):
+ ''' Navigates the complicated logic of when to set dnsIP
+
+ In all situations if they've set openshift_dns_ip use that
+ For 1.0/3.0 installs we use the openshift_master_cluster_vip, openshift_node_first_master_ip, else None
+ For 1.1/3.1 installs we use openshift_master_cluster_vip, else None (product will use kube svc ip)
+ For 1.2/3.2+ installs we set to the node's default interface ip
+ '''
+
+ if not issubclass(type(hostvars), dict):
+ raise errors.AnsibleFilterError("|failed expects hostvars is a dict")
+
+ # We always use what they've specified if they've specified a value
+ if openshift_dns_ip != None:
+ return openshift_dns_ip
+
+ if bool(hostvars['openshift']['common']['use_dnsmasq']):
+ return hostvars['ansible_default_ipv4']['address']
+ elif bool(hostvars['openshift']['common']['version_gte_3_1_or_1_1']):
+ if 'openshift_master_cluster_vip' in hostvars:
+ return hostvars['openshift_master_cluster_vip']
+ else:
+ if 'openshift_master_cluster_vip' in hostvars:
+ return hostvars['openshift_master_cluster_vip']
+ elif 'openshift_node_first_master_ip' in hostvars:
+ return hostvars['openshift_node_first_master_ip']
+ return None
+
+ def filters(self):
+ ''' returns a mapping of filters to methods '''
+ return {'get_dns_ip': self.get_dns_ip}