# (c) 2012, Michael DeHaan # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . import ansible.constants as C from ansible.inventory.host import Host from ansible.inventory.group import Group from ansible import errors from ansible import utils import os import yaml import sys from six import iteritems class InventoryParserYaml(object): ''' Host inventory parser for ansible ''' def __init__(self, filename=C.DEFAULT_HOST_LIST): sys.stderr.write("WARNING: YAML inventory files are deprecated in 0.6 and will be removed in 0.7, to migrate" + " download and run https://github.com/ansible/ansible/blob/devel/examples/scripts/yaml_to_ini.py\n") fh = open(filename) data = fh.read() fh.close() self._hosts = {} self._parse(data) def _make_host(self, hostname): if hostname in self._hosts: return self._hosts[hostname] else: host = Host(hostname) self._hosts[hostname] = host return host # see file 'test/yaml_hosts' for syntax def _parse(self, data): # FIXME: refactor into subfunctions all = Group('all') ungrouped = Group('ungrouped') all.add_child_group(ungrouped) self.groups = dict(all=all, ungrouped=ungrouped) grouped_hosts = [] yaml = utils.parse_yaml(data) # first add all groups for item in yaml: if type(item) == dict and 'group' in item: group = Group(item['group']) for subresult in item.get('hosts',[]): if type(subresult) in [ str, unicode ]: host = self._make_host(subresult) group.add_host(host) grouped_hosts.append(host) elif type(subresult) == dict: host = self._make_host(subresult['host']) vars = subresult.get('vars',{}) if type(vars) == list: for subitem in vars: for (k,v) in subitem.items(): host.set_variable(k,v) elif type(vars) == dict: for (k,v) in subresult.get('vars',{}).items(): host.set_variable(k,v) else: raise errors.AnsibleError("unexpected type for variable") group.add_host(host) grouped_hosts.append(host) vars = item.get('vars',{}) if type(vars) == dict: for (k,v) in item.get('vars',{}).items(): group.set_variable(k,v) elif type(vars) == list: for subitem in vars: if type(subitem) != dict: raise errors.AnsibleError("expected a dictionary") for (k,v) in subitem.items(): group.set_variable(k,v) self.groups[group.name] = group all.add_child_group(group) # add host definitions for item in yaml: if type(item) in [ str, unicode ]: host = self._make_host(item) if host not in grouped_hosts: ungrouped.add_host(host) elif type(item) == dict and 'host' in item: host = self._make_host(item['host']) vars = item.get('vars', {}) if type(vars)==list: varlist, vars = vars, {} for subitem in varlist: vars.update(subitem) for (k,v) in vars.items(): host.set_variable(k,v) groups = item.get('groups', {}) if type(groups) in [ str, unicode ]: groups = [ groups ] if type(groups)==list: for subitem in groups: if subitem in self.groups: group = self.groups[subitem] else: group = Group(subitem) self.groups[group.name] = group all.add_child_group(group) group.add_host(host) grouped_hosts.append(host) if host not in grouped_hosts: ungrouped.add_host(host) # make sure ungrouped.hosts is the complement of grouped_hosts ungrouped_hosts = [host for host in ungrouped.hosts if host not in grouped_hosts] if __name__ == "__main__": if len(sys.argv) != 2: print "usage: yaml_to_ini.py /path/to/ansible/hosts" sys.exit(1) result = "" original = sys.argv[1] yamlp = InventoryParserYaml(filename=sys.argv[1]) dirname = os.path.dirname(original) group_names = [ g.name for g in yamlp.groups.values() ] for group_name in sorted(group_names): record = yamlp.groups[group_name] if group_name == 'all': continue hosts = record.hosts result = result + "[%s]\n" % record.name for h in hosts: result = result + "%s\n" % h.name result = result + "\n" groupfiledir = os.path.join(dirname, "group_vars") if not os.path.exists(groupfiledir): print "* creating: %s" % groupfiledir os.makedirs(groupfiledir) groupfile = os.path.join(groupfiledir, group_name) print "* writing group variables for %s into %s" % (group_name, groupfile) groupfh = open(groupfile, 'w') groupfh.write(yaml.dump(record.get_variables())) groupfh.close() for (host_name, host_record) in iteritems(yamlp._hosts): hostfiledir = os.path.join(dirname, "host_vars") if not os.path.exists(hostfiledir): print "* creating: %s" % hostfiledir os.makedirs(hostfiledir) hostfile = os.path.join(hostfiledir, host_record.name) print "* writing host variables for %s into %s" % (host_record.name, hostfile) hostfh = open(hostfile, 'w') hostfh.write(yaml.dump(host_record.get_variables())) hostfh.close() # also need to keep a hash of variables per each host # and variables per each group # and write those to disk newfilepath = os.path.join(dirname, "hosts.new") fdh = open(newfilepath, 'w') fdh.write(result) fdh.close() print "* COMPLETE: review your new inventory file and replace your original when ready" print "* new inventory file saved as %s" % newfilepath print "* edit group specific variables in %s/group_vars/" % dirname print "* edit host specific variables in %s/host_vars/" % dirname # now need to write this to disk as (oldname).new # and inform the user