yedit.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #!/usr/bin/env python
  2. '''
  3. module for openshift cloud secrets
  4. '''
  5. import os
  6. import yaml
  7. class YeditException(Exception):
  8. ''' Exception class for Yedit '''
  9. pass
  10. class Yedit(object):
  11. ''' Class to modify yaml files '''
  12. def __init__(self, filename):
  13. self.filename = filename
  14. self.__yaml_dict = None
  15. self.get()
  16. @property
  17. def yaml_dict(self):
  18. ''' getter method for yaml_dict '''
  19. return self.__yaml_dict
  20. @yaml_dict.setter
  21. def yaml_dict(self, value):
  22. ''' setter method for yaml_dict '''
  23. self.__yaml_dict = value
  24. @staticmethod
  25. def remove_entry(data, keys):
  26. ''' remove an item from a dictionary with key notation a.b.c
  27. d = {'a': {'b': 'c'}}}
  28. keys = a.b
  29. item = c
  30. '''
  31. if "." in keys:
  32. key, rest = keys.split(".", 1)
  33. if key in data.keys():
  34. Yedit.remove_entry(data[key], rest)
  35. else:
  36. del data[keys]
  37. @staticmethod
  38. def add_entry(data, keys, item):
  39. ''' Add an item to a dictionary with key notation a.b.c
  40. d = {'a': {'b': 'c'}}}
  41. keys = a.b
  42. item = c
  43. '''
  44. if "." in keys:
  45. key, rest = keys.split(".", 1)
  46. if key not in data:
  47. data[key] = {}
  48. if not isinstance(data, dict):
  49. raise YeditException('Invalid add_entry called on a [%s] of type [%s].' % (data, type(data)))
  50. else:
  51. Yedit.add_entry(data[key], rest, item)
  52. else:
  53. data[keys] = item
  54. @staticmethod
  55. def get_entry(data, keys):
  56. ''' Get an item from a dictionary with key notation a.b.c
  57. d = {'a': {'b': 'c'}}}
  58. keys = a.b
  59. return c
  60. '''
  61. if keys and "." in keys:
  62. key, rest = keys.split(".", 1)
  63. if not isinstance(data[key], dict):
  64. raise YeditException('Invalid get_entry called on a [%s] of type [%s].' % (data, type(data)))
  65. else:
  66. return Yedit.get_entry(data[key], rest)
  67. else:
  68. return data.get(keys, None)
  69. def write(self):
  70. ''' write to file '''
  71. with open(self.filename, 'w') as yfd:
  72. yfd.write(yaml.dump(self.yaml_dict, default_flow_style=False))
  73. def read(self):
  74. ''' write to file '''
  75. # check if it exists
  76. if not self.exists():
  77. return None
  78. contents = None
  79. with open(self.filename) as yfd:
  80. contents = yfd.read()
  81. return contents
  82. def exists(self):
  83. ''' return whether file exists '''
  84. if os.path.exists(self.filename):
  85. return True
  86. return False
  87. def get(self):
  88. ''' return yaml file '''
  89. contents = self.read()
  90. if not contents:
  91. return None
  92. # check if it is yaml
  93. try:
  94. self.yaml_dict = yaml.load(contents)
  95. except yaml.YAMLError as _:
  96. # Error loading yaml
  97. return None
  98. return self.yaml_dict
  99. def delete(self, key):
  100. ''' put key, value into a yaml file '''
  101. try:
  102. entry = Yedit.get_entry(self.yaml_dict, key)
  103. except KeyError as _:
  104. entry = None
  105. if not entry:
  106. return (False, self.yaml_dict)
  107. Yedit.remove_entry(self.yaml_dict, key)
  108. self.write()
  109. return (True, self.get())
  110. def put(self, key, value):
  111. ''' put key, value into a yaml file '''
  112. try:
  113. entry = Yedit.get_entry(self.yaml_dict, key)
  114. except KeyError as _:
  115. entry = None
  116. if entry == value:
  117. return (False, self.yaml_dict)
  118. Yedit.add_entry(self.yaml_dict, key, value)
  119. self.write()
  120. return (True, self.get())
  121. def create(self, key, value):
  122. ''' create the file '''
  123. if not self.exists():
  124. self.yaml_dict = {key: value}
  125. self.write()
  126. return (True, self.get())
  127. return (False, self.get())
  128. def main():
  129. '''
  130. ansible oc module for secrets
  131. '''
  132. module = AnsibleModule(
  133. argument_spec=dict(
  134. state=dict(default='present', type='str',
  135. choices=['present', 'absent', 'list']),
  136. debug=dict(default=False, type='bool'),
  137. src=dict(default=None, type='str'),
  138. key=dict(default=None, type='str'),
  139. value=dict(default=None, type='str'),
  140. value_format=dict(default='yaml', choices=['yaml', 'json'], type='str'),
  141. ),
  142. mutually_exclusive=[["contents", "files"]],
  143. supports_check_mode=True,
  144. )
  145. state = module.params['state']
  146. yamlfile = Yedit(module.params['src'])
  147. rval = yamlfile.get()
  148. if not rval and state != 'present':
  149. module.fail_json(msg='Error opening file [%s]. Verify that the' + \
  150. ' file exists, that it is has correct permissions, and is valid yaml.')
  151. if state == 'list':
  152. module.exit_json(changed=False, results=rval, state="list")
  153. if state == 'absent':
  154. rval = yamlfile.delete(module.params['key'])
  155. module.exit_json(changed=rval[0], results=rval[1], state="absent")
  156. if state == 'present':
  157. if module.params['value_format'] == 'yaml':
  158. value = yaml.load(module.params['value'])
  159. elif module.params['value_format'] == 'json':
  160. value = json.loads(module.params['value'])
  161. if rval:
  162. rval = yamlfile.put(module.params['key'], value)
  163. module.exit_json(changed=rval[0], results=rval[1], state="present")
  164. rval = yamlfile.create(module.params['key'], value)
  165. module.exit_json(changed=rval[0], results=rval[1], state="present")
  166. module.exit_json(failed=True,
  167. changed=False,
  168. results='Unknown state passed. %s' % state,
  169. state="unknown")
  170. # pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled
  171. # import module snippets. This are required
  172. from ansible.module_utils.basic import *
  173. main()