load_user_files.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #!/usr/bin/python
  2. class LoadVarDir(object):
  3. def __init__(self, module):
  4. self.module = module
  5. self.path = self.module.params["path"]
  6. self.fact = self.module.params["fact"]
  7. self.data_bag = self.module.params["databag"]
  8. # Chef => Ansible mapping
  9. self.mapping = {"comment": "comment",
  10. "force": "force",
  11. "gid": "group",
  12. "groups": "groups",
  13. "home": "home",
  14. "manage_home": "move_home",
  15. "non_unique": "non_unique",
  16. "password": "password",
  17. "shell": "shell",
  18. "action": "state",
  19. "system": "system",
  20. "uid": "uid",
  21. "ssh_keys": "keys"
  22. }
  23. self.file_data = {}
  24. def parse_yaml(self, data, path_hint=None):
  25. ''' convert a yaml string to a data structure. Also supports JSON, ssssssh!!!'''
  26. stripped_data = data.lstrip()
  27. loaded = None
  28. if stripped_data.startswith("{") or stripped_data.startswith("["):
  29. # since the line starts with { or [ we can infer this is a JSON document.
  30. try:
  31. loaded = json.loads(data)
  32. except ValueError, ve:
  33. if path_hint:
  34. self.module.fail_json(msg=path_hint + ": " + str(ve))
  35. else:
  36. self.module.fail_json(msg=str(ve))
  37. else:
  38. # else this is pretty sure to be a YAML document
  39. loaded = yaml.load(data, Loader=Loader)
  40. return loaded
  41. def parse_yaml_from_file(self, path, vault_password=None):
  42. ''' convert a yaml file to a data structure '''
  43. data = None
  44. try:
  45. data = open(path).read()
  46. except IOError:
  47. self.module.fail_json(msg="file could not read: %s" % path)
  48. try:
  49. return self.parse_yaml(data, path_hint=path)
  50. except yaml.YAMLError, exc:
  51. self.module.fail_json(msg="Syntax error in yaml file '%s'" % path)
  52. def main(self):
  53. self._check_variable()
  54. result = {"changed": False, "msg": "Hi", self.fact: self.file_data}
  55. self.module.exit_json(**result)
  56. def _read_from_file(self, file_path, databag):
  57. data = self.parse_yaml_from_file(file_path, vault_password="")
  58. if data and type(data) != dict:
  59. self.module.fail_json(msg="%s must be stored as a dictionary/hash".format(file_path))
  60. elif data is None:
  61. data = {}
  62. if databag:
  63. data = self.convert_chef_user_data_bag(data)
  64. return data
  65. def convert_chef_user_data_bag(self, data):
  66. print "data=", data
  67. if len(data) == 0:
  68. return data
  69. else:
  70. new_data = {}
  71. user_name = data.pop("id") # Should fail if no id
  72. # Loop and only pick item in our map and translate it to ansible ignore the rest
  73. for mapping_key in self.mapping:
  74. data_bag_item_value = data.pop(mapping_key, None)
  75. if data_bag_item_value:
  76. ansible_key = self.mapping.get(mapping_key)
  77. new_data.update({ansible_key: data_bag_item_value})
  78. # Check for an action
  79. chef_action = new_data.get("state", False)
  80. if chef_action:
  81. if chef_action == "create":
  82. new_data["state"] = "present"
  83. elif chef_action == "remove":
  84. new_data["state"] = "absent"
  85. chef_groups = new_data.get("groups", False)
  86. primary_group = new_data.get("group", False)
  87. if primary_group in chef_groups:
  88. # Databag issue for smart-os Issue
  89. chef_groups = [group_item for group_item in chef_groups if group_item != primary_group]
  90. new_data["groups"] = ",".join(chef_groups)
  91. return {user_name: new_data}
  92. def _check_variable(self):
  93. for path_item in self.path:
  94. try:
  95. path = path_item.get("path")
  96. path = os.path.expanduser(path)
  97. databag = path_item.get("databag", self.data_bag)
  98. #print "all={} type={} path={} databag={}".format(path_item, type(path_item), path, databag)
  99. except Exception as E:
  100. self.module.fail_json(msg="Path is a list but is malformed could not get 'path' got '{}'. Error '{}'".
  101. format(path_item, E))
  102. self._follow_path(path, databag)
  103. def _follow_path(self, path, databag):
  104. if os.path.exists(path):
  105. if os.path.isdir(path):
  106. for root, dirs, files in os.walk(path, topdown=False):
  107. for filename in files:
  108. self.file_data.update(self._read_from_file(path + "/" + filename, databag))
  109. else:
  110. self.file_data.update(self._read_from_file(path, databag))
  111. else:
  112. self.module.fail_json(msg="Failed to find path '{}'.".format(path))
  113. def main():
  114. module = AnsibleModule(
  115. argument_spec=dict(
  116. name=dict(default=None, aliases=["path"], required=True, type='list'),
  117. fact=dict(default="var_dir", required=False),
  118. databag=dict(default=False, type='bool')
  119. ),
  120. supports_check_mode=False
  121. )
  122. if not ansible_client_found:
  123. module.fail_json(msg="Ansible is not installed or ansible python library is not in path. Can't import 'ansible.utils '")
  124. LoadVarDir(module).main()
  125. # import module snippets
  126. from ansible.module_utils.basic import *
  127. try:
  128. import yaml
  129. except ImportError:
  130. ansible_client_found = False
  131. else:
  132. ansible_client_found = True
  133. try:
  134. from yaml import CSafeLoader as Loader
  135. except ImportError:
  136. from yaml import SafeLoader as Loader
  137. main()