yedit.py 6.9 KB

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