modify_yaml.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. # vim: expandtab:tabstop=4:shiftwidth=4
  4. ''' modify_yaml ansible module '''
  5. import yaml
  6. DOCUMENTATION = '''
  7. ---
  8. module: modify_yaml
  9. short_description: Modify yaml key value pairs
  10. author: Andrew Butcher
  11. requirements: [ ]
  12. '''
  13. EXAMPLES = '''
  14. - modify_yaml:
  15. dest: /etc/origin/master/master-config.yaml
  16. yaml_key: 'kubernetesMasterConfig.masterCount'
  17. yaml_value: 2
  18. '''
  19. # pylint: disable=missing-docstring
  20. def set_key(yaml_data, yaml_key, yaml_value):
  21. changes = []
  22. ptr = yaml_data
  23. final_key = yaml_key.split('.')[-1]
  24. for key in yaml_key.split('.'):
  25. # Key isn't present and we're not on the final key. Set to empty dictionary.
  26. if key not in ptr and key != final_key:
  27. ptr[key] = {}
  28. ptr = ptr[key]
  29. # Current key is the final key. Update value.
  30. elif key == final_key:
  31. if (key in ptr and module.safe_eval(ptr[key]) != yaml_value) or (key not in ptr): # noqa: F405
  32. ptr[key] = yaml_value
  33. changes.append((yaml_key, yaml_value))
  34. else:
  35. # Next value is None and we're not on the final key.
  36. # Turn value into an empty dictionary.
  37. if ptr[key] is None and key != final_key:
  38. ptr[key] = {}
  39. ptr = ptr[key]
  40. return changes
  41. def main():
  42. ''' Modify key (supplied in jinja2 dot notation) in yaml file, setting
  43. the key to the desired value.
  44. '''
  45. # disabling pylint errors for global-variable-undefined and invalid-name
  46. # for 'global module' usage, since it is required to use ansible_facts
  47. # pylint: disable=global-variable-undefined, invalid-name,
  48. # redefined-outer-name
  49. global module
  50. module = AnsibleModule( # noqa: F405
  51. argument_spec=dict(
  52. dest=dict(required=True),
  53. yaml_key=dict(required=True),
  54. yaml_value=dict(required=True),
  55. backup=dict(required=False, default=True, type='bool'),
  56. ),
  57. supports_check_mode=True,
  58. )
  59. dest = module.params['dest']
  60. yaml_key = module.params['yaml_key']
  61. yaml_value = module.safe_eval(module.params['yaml_value'])
  62. backup = module.params['backup']
  63. # Represent null values as an empty string.
  64. # pylint: disable=missing-docstring, unused-argument
  65. def none_representer(dumper, data):
  66. return yaml.ScalarNode(tag=u'tag:yaml.org,2002:null', value=u'')
  67. yaml.add_representer(type(None), none_representer)
  68. try:
  69. with open(dest) as yaml_file:
  70. yaml_data = yaml.safe_load(yaml_file.read())
  71. changes = set_key(yaml_data, yaml_key, yaml_value)
  72. if len(changes) > 0:
  73. if backup:
  74. module.backup_local(dest)
  75. with open(dest, 'w') as yaml_file:
  76. yaml_string = yaml.dump(yaml_data, default_flow_style=False)
  77. yaml_string = yaml_string.replace('\'\'', '""')
  78. yaml_file.write(yaml_string)
  79. return module.exit_json(changed=(len(changes) > 0), changes=changes)
  80. # ignore broad-except error to avoid stack trace to ansible user
  81. # pylint: disable=broad-except
  82. except Exception as e:
  83. return module.fail_json(msg=str(e))
  84. # ignore pylint errors related to the module_utils import
  85. # pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, wrong-import-position
  86. # import module snippets
  87. from ansible.module_utils.basic import * # noqa: F402,F403
  88. if __name__ == '__main__':
  89. main()