oo_filters.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. # vim: expandtab:tabstop=4:shiftwidth=4
  4. '''
  5. Custom filters for use in openshift-ansible
  6. '''
  7. from ansible import errors
  8. from operator import itemgetter
  9. import pdb
  10. def oo_pdb(arg):
  11. ''' This pops you into a pdb instance where arg is the data passed in
  12. from the filter.
  13. Ex: "{{ hostvars | oo_pdb }}"
  14. '''
  15. pdb.set_trace()
  16. return arg
  17. def oo_len(arg):
  18. ''' This returns the length of the argument
  19. Ex: "{{ hostvars | oo_len }}"
  20. '''
  21. return len(arg)
  22. def get_attr(data, attribute=None):
  23. ''' This looks up dictionary attributes of the form a.b.c and returns
  24. the value.
  25. Ex: data = {'a': {'b': {'c': 5}}}
  26. attribute = "a.b.c"
  27. returns 5
  28. '''
  29. if not attribute:
  30. raise errors.AnsibleFilterError("|failed expects attribute to be set")
  31. ptr = data
  32. for attr in attribute.split('.'):
  33. ptr = ptr[attr]
  34. return ptr
  35. def oo_flatten(data):
  36. ''' This filter plugin will flatten a list of lists
  37. '''
  38. if not issubclass(type(data), list):
  39. raise errors.AnsibleFilterError("|failed expects to flatten a List")
  40. return [item for sublist in data for item in sublist]
  41. def oo_collect(data, attribute=None, filters=None):
  42. ''' This takes a list of dict and collects all attributes specified into a
  43. list If filter is specified then we will include all items that match
  44. _ALL_ of filters.
  45. Ex: data = [ {'a':1, 'b':5, 'z': 'z'}, # True, return
  46. {'a':2, 'z': 'z'}, # True, return
  47. {'a':3, 'z': 'z'}, # True, return
  48. {'a':4, 'z': 'b'}, # FAILED, obj['z'] != obj['z']
  49. ]
  50. attribute = 'a'
  51. filters = {'z': 'z'}
  52. returns [1, 2, 3]
  53. '''
  54. if not issubclass(type(data), list):
  55. raise errors.AnsibleFilterError("|failed expects to filter on a List")
  56. if not attribute:
  57. raise errors.AnsibleFilterError("|failed expects attribute to be set")
  58. if filters is not None:
  59. if not issubclass(type(filters), dict):
  60. raise errors.AnsibleFilterError("|fialed expects filter to be a"
  61. " dict")
  62. retval = [get_attr(d, attribute) for d in data if (
  63. all([d[key] == filters[key] for key in filters]))]
  64. else:
  65. retval = [get_attr(d, attribute) for d in data]
  66. return retval
  67. def oo_select_keys(data, keys):
  68. ''' This returns a list, which contains the value portions for the keys
  69. Ex: data = { 'a':1, 'b':2, 'c':3 }
  70. keys = ['a', 'c']
  71. returns [1, 3]
  72. '''
  73. if not issubclass(type(data), dict):
  74. raise errors.AnsibleFilterError("|failed expects to filter on a dict")
  75. if not issubclass(type(keys), list):
  76. raise errors.AnsibleFilterError("|failed expects first param is a list")
  77. # Gather up the values for the list of keys passed in
  78. retval = [data[key] for key in keys]
  79. return retval
  80. def oo_prepend_strings_in_list(data, prepend):
  81. ''' This takes a list of strings and prepends a string to each item in the
  82. list
  83. Ex: data = ['cart', 'tree']
  84. prepend = 'apple-'
  85. returns ['apple-cart', 'apple-tree']
  86. '''
  87. if not issubclass(type(data), list):
  88. raise errors.AnsibleFilterError("|failed expects first param is a list")
  89. if not all(isinstance(x, basestring) for x in data):
  90. raise errors.AnsibleFilterError("|failed expects first param is a list"
  91. " of strings")
  92. retval = [prepend + s for s in data]
  93. return retval
  94. def oo_ami_selector(data, image_name):
  95. ''' This takes a list of amis and an image name and attempts to return
  96. the latest ami.
  97. '''
  98. if not issubclass(type(data), list):
  99. raise errors.AnsibleFilterError("|failed expects first param is a list")
  100. if not data:
  101. return None
  102. else:
  103. if image_name is None or not image_name.endswith('_*'):
  104. ami = sorted(data, key=itemgetter('name'), reverse=True)[0]
  105. return ami['ami_id']
  106. else:
  107. ami_info = [(ami, ami['name'].split('_')[-1]) for ami in data]
  108. ami = sorted(ami_info, key=itemgetter(1), reverse=True)[0][0]
  109. return ami['ami_id']
  110. def oo_ec2_volume_definition(data, host_type, docker_ephemeral=False):
  111. ''' This takes a dictionary of volume definitions and returns a valid ec2
  112. volume definition based on the host_type and the values in the
  113. dictionary.
  114. The dictionary should look similar to this:
  115. { 'master':
  116. { 'root':
  117. { 'volume_size': 10, 'device_type': 'gp2',
  118. 'iops': 500
  119. }
  120. },
  121. 'node':
  122. { 'root':
  123. { 'volume_size': 10, 'device_type': 'io1',
  124. 'iops': 1000
  125. },
  126. 'docker':
  127. { 'volume_size': 40, 'device_type': 'gp2',
  128. 'iops': 500, 'ephemeral': 'true'
  129. }
  130. }
  131. }
  132. '''
  133. if not issubclass(type(data), dict):
  134. raise errors.AnsibleFilterError("|failed expects first param is a dict")
  135. if host_type not in ['master', 'node']:
  136. raise errors.AnsibleFilterError("|failed expects either master or node"
  137. " host type")
  138. root_vol = data[host_type]['root']
  139. root_vol['device_name'] = '/dev/sda1'
  140. root_vol['delete_on_termination'] = True
  141. if root_vol['device_type'] != 'io1':
  142. root_vol.pop('iops', None)
  143. if host_type == 'node':
  144. docker_vol = data[host_type]['docker']
  145. docker_vol['device_name'] = '/dev/xvdb'
  146. docker_vol['delete_on_termination'] = True
  147. if docker_vol['device_type'] != 'io1':
  148. docker_vol.pop('iops', None)
  149. if docker_ephemeral:
  150. docker_vol.pop('device_type', None)
  151. docker_vol.pop('delete_on_termination', None)
  152. docker_vol['ephemeral'] = 'ephemeral0'
  153. return [root_vol, docker_vol]
  154. return [root_vol]
  155. # disabling pylint checks for too-few-public-methods and no-self-use since we
  156. # need to expose a FilterModule object that has a filters method that returns
  157. # a mapping of filter names to methods.
  158. # pylint: disable=too-few-public-methods, no-self-use
  159. class FilterModule(object):
  160. ''' FilterModule '''
  161. def filters(self):
  162. ''' returns a mapping of filters to methods '''
  163. return {
  164. "oo_select_keys": oo_select_keys,
  165. "oo_collect": oo_collect,
  166. "oo_flatten": oo_flatten,
  167. "oo_len": oo_len,
  168. "oo_pdb": oo_pdb,
  169. "oo_prepend_strings_in_list": oo_prepend_strings_in_list,
  170. "oo_ami_selector": oo_ami_selector,
  171. "oo_ec2_volume_definition": oo_ec2_volume_definition
  172. }