#!/usr/bin/python class LoadVarDir(object): def __init__(self, module): self.module = module self.path = self.module.params["path"] self.fact = self.module.params["fact"] self.data_bag = self.module.params["databag"] self.extract_extra_keys = self.module.params["extract_extra_keys"] # Chef => Ansible mapping self.mapping = {"comment": "comment", "force": "force", "gid": "group", "groups": "groups", "home": "home", "manage_home": "move_home", "non_unique": "non_unique", "password": "password", "shell": "shell", "action": "state", "system": "system", "uid": "uid", "ssh_keys": "keys" } self.file_data = {} def parse_yaml(self, data, path_hint=None): ''' convert a yaml string to a data structure. Also supports JSON, ssssssh!!!''' stripped_data = data.lstrip() loaded = None if stripped_data.startswith("{") or stripped_data.startswith("["): # since the line starts with { or [ we can infer this is a JSON document. try: loaded = json.loads(data) except ValueError as ve: if path_hint: self.module.fail_json(msg=path_hint + ": " + str(ve)) else: self.module.fail_json(msg=str(ve)) else: # else this is pretty sure to be a YAML document loaded = yaml.load(data, Loader=Loader) return loaded def parse_yaml_from_file(self, path, vault_password=None): ''' convert a yaml file to a data structure ''' data = None try: data = open(path).read() except IOError: self.module.fail_json(msg="file could not read: %s" % path) try: return self.parse_yaml(data, path_hint=path) except yaml.YAMLError as exc: self.module.fail_json(msg="Syntax error in yaml file '%s'" % path) def main(self): self._check_variable() result = {"changed": False, "msg": "Hi", self.fact: self.file_data} self.module.exit_json(**result) def _read_from_file(self, file_path, databag): data = self.parse_yaml_from_file(file_path, vault_password="") if data and type(data) != dict: self.module.fail_json(msg="%s must be stored as a dictionary/hash".format(file_path)) elif data is None: data = {} if databag: data = self.convert_chef_user_data_bag(data) return data def convert_chef_user_data_bag(self, data): print(("data=", data)) if len(data) == 0: return data else: new_data = {} user_name = data.pop("id") # Should fail if no id # Loop and only pick item in our map and translate it to ansible ignore the rest for mapping_key in self.mapping: data_bag_item_value = data.pop(mapping_key, None) if data_bag_item_value: ansible_key = self.mapping.get(mapping_key) new_data.update({ansible_key: data_bag_item_value}) if self.extract_extra_keys: for key, value in data.iteritems(): new_data.update({key: value}) # Check for an action chef_action = new_data.get("state", False) if chef_action: if chef_action == "create": new_data["state"] = "present" elif chef_action == "remove": new_data["state"] = "absent" chef_groups = new_data.get("groups", False) primary_group = new_data.get("group", False) if primary_group in chef_groups: # Databag issue for smart-os Issue chef_groups = [group_item for group_item in chef_groups if group_item != primary_group] new_data["groups"] = ",".join(chef_groups) return {user_name: new_data} def _check_variable(self): for path_item in self.path: try: path = path_item.get("path") path = os.path.expanduser(path) databag = path_item.get("databag", self.data_bag) #print "all={} type={} path={} databag={}".format(path_item, type(path_item), path, databag) except Exception as E: self.module.fail_json(msg="Path is a list but is malformed could not get 'path' got '{}'. Error '{}'". format(path_item, E)) self._follow_path(path, databag) def _follow_path(self, path, databag): if os.path.exists(path): if os.path.isdir(path): for root, dirs, files in os.walk(path, topdown=False): for filename in files: self.file_data.update(self._read_from_file(path + "/" + filename, databag)) else: self.file_data.update(self._read_from_file(path, databag)) else: self.module.fail_json(msg="Failed to find path '{}'.".format(path)) def main(): module = AnsibleModule( argument_spec=dict( name=dict(default=None, aliases=["path"], required=True, type='list'), fact=dict(default="var_dir", required=False), databag=dict(default=False, type='bool'), extract_extra_keys=dict(default=True, required=False) ), supports_check_mode=False ) if not ansible_client_found: module.fail_json(msg="Ansible is not installed or ansible python library is not in path. Can't import 'ansible.utils '") LoadVarDir(module).main() # import module snippets from ansible.module_utils.basic import * try: import yaml except ImportError: ansible_client_found = False else: ansible_client_found = True try: from yaml import CSafeLoader as Loader except ImportError: from yaml import SafeLoader as Loader main()