PageRenderTime 55ms CodeModel.GetById 11ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/ansible/inventory/ini.py

https://github.com/ajanthanm/ansible
Python | 204 lines | 152 code | 19 blank | 33 comment | 17 complexity | f7ace00cf22d22748cec94a3112f4396 MD5 | raw file
  1# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
  2#
  3# This file is part of Ansible
  4#
  5# Ansible is free software: you can redistribute it and/or modify
  6# it under the terms of the GNU General Public License as published by
  7# the Free Software Foundation, either version 3 of the License, or
  8# (at your option) any later version.
  9#
 10# Ansible is distributed in the hope that it will be useful,
 11# but WITHOUT ANY WARRANTY; without even the implied warranty of
 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13# GNU General Public License for more details.
 14#
 15# You should have received a copy of the GNU General Public License
 16# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
 17
 18#############################################
 19
 20import ansible.constants as C
 21from ansible.inventory.host import Host
 22from ansible.inventory.group import Group
 23from ansible.inventory.expand_hosts import detect_range
 24from ansible.inventory.expand_hosts import expand_hostname_range
 25from ansible import errors
 26from ansible import utils
 27import shlex
 28import re
 29import ast
 30
 31class InventoryParser(object):
 32    """
 33    Host inventory for ansible.
 34    """
 35
 36    def __init__(self, filename=C.DEFAULT_HOST_LIST):
 37
 38        with open(filename) as fh:
 39            self.lines = fh.readlines()
 40            self.groups = {}
 41            self.hosts = {}
 42            self._parse()
 43
 44    def _parse(self):
 45
 46        self._parse_base_groups()
 47        self._parse_group_children()
 48        self._add_allgroup_children()
 49        self._parse_group_variables()
 50        return self.groups
 51
 52    @staticmethod
 53    def _parse_value(v):
 54        if "#" not in v:
 55            try:
 56                return ast.literal_eval(v)
 57            # Using explicit exceptions.
 58            # Likely a string that literal_eval does not like. We wil then just set it.
 59            except ValueError:
 60                # For some reason this was thought to be malformed.
 61                pass
 62            except SyntaxError:
 63                # Is this a hash with an equals at the end?
 64                pass
 65        return v
 66
 67    # [webservers]
 68    # alpha
 69    # beta:2345
 70    # gamma sudo=True user=root
 71    # delta asdf=jkl favcolor=red
 72
 73    def _add_allgroup_children(self):
 74
 75        for group in self.groups.values():
 76            if group.depth == 0 and group.name != 'all':
 77                self.groups['all'].add_child_group(group)
 78
 79
 80    def _parse_base_groups(self):
 81        # FIXME: refactor
 82
 83        ungrouped = Group(name='ungrouped')
 84        all = Group(name='all')
 85        all.add_child_group(ungrouped)
 86
 87        self.groups = dict(all=all, ungrouped=ungrouped)
 88        active_group_name = 'ungrouped'
 89
 90        for line in self.lines:
 91            line = utils.before_comment(line).strip()
 92            if line.startswith("[") and line.endswith("]"):
 93                active_group_name = line.replace("[","").replace("]","")
 94                if ":vars" in line or ":children" in line:
 95                    active_group_name = active_group_name.rsplit(":", 1)[0]
 96                    if active_group_name not in self.groups:
 97                        new_group = self.groups[active_group_name] = Group(name=active_group_name)
 98                    active_group_name = None
 99                elif active_group_name not in self.groups:
100                    new_group = self.groups[active_group_name] = Group(name=active_group_name)
101            elif line.startswith(";") or line == '':
102                pass
103            elif active_group_name:
104                tokens = shlex.split(line)
105                if len(tokens) == 0:
106                    continue
107                hostname = tokens[0]
108                port = C.DEFAULT_REMOTE_PORT
109                # Three cases to check:
110                # 0. A hostname that contains a range pesudo-code and a port
111                # 1. A hostname that contains just a port
112                if hostname.count(":") > 1:
113                    # Possible an IPv6 address, or maybe a host line with multiple ranges
114                    # IPv6 with Port  XXX:XXX::XXX.port
115                    # FQDN            foo.example.com
116                    if hostname.count(".") == 1:
117                        (hostname, port) = hostname.rsplit(".", 1)
118                elif ("[" in hostname and
119                    "]" in hostname and
120                    ":" in hostname and
121                    (hostname.rindex("]") < hostname.rindex(":")) or
122                    ("]" not in hostname and ":" in hostname)):
123                        (hostname, port) = hostname.rsplit(":", 1)
124
125                hostnames = []
126                if detect_range(hostname):
127                    hostnames = expand_hostname_range(hostname)
128                else:
129                    hostnames = [hostname]
130
131                for hn in hostnames:
132                    host = None
133                    if hn in self.hosts:
134                        host = self.hosts[hn]
135                    else:
136                        host = Host(name=hn, port=port)
137                        self.hosts[hn] = host
138                    if len(tokens) > 1:
139                        for t in tokens[1:]:
140                            if t.startswith('#'):
141                                break
142                            try:
143                                (k,v) = t.split("=", 1)
144                            except ValueError, e:
145                                raise errors.AnsibleError("Invalid ini entry: %s - %s" % (t, str(e)))
146                            host.set_variable(k, self._parse_value(v))
147                    self.groups[active_group_name].add_host(host)
148
149    # [southeast:children]
150    # atlanta
151    # raleigh
152
153    def _parse_group_children(self):
154        group = None
155
156        for line in self.lines:
157            line = line.strip()
158            if line is None or line == '':
159                continue
160            if line.startswith("[") and ":children]" in line:
161                line = line.replace("[","").replace(":children]","")
162                group = self.groups.get(line, None)
163                if group is None:
164                    group = self.groups[line] = Group(name=line)
165            elif line.startswith("#") or line.startswith(";"):
166                pass
167            elif line.startswith("["):
168                group = None
169            elif group:
170                kid_group = self.groups.get(line, None)
171                if kid_group is None:
172                    raise errors.AnsibleError("child group is not defined: (%s)" % line)
173                else:
174                    group.add_child_group(kid_group)
175
176
177    # [webservers:vars]
178    # http_port=1234
179    # maxRequestsPerChild=200
180
181    def _parse_group_variables(self):
182        group = None
183        for line in self.lines:
184            line = line.strip()
185            if line.startswith("[") and ":vars]" in line:
186                line = line.replace("[","").replace(":vars]","")
187                group = self.groups.get(line, None)
188                if group is None:
189                    raise errors.AnsibleError("can't add vars to undefined group: %s" % line)
190            elif line.startswith("#") or line.startswith(";"):
191                pass
192            elif line.startswith("["):
193                group = None
194            elif line == '':
195                pass
196            elif group:
197                if "=" not in line:
198                    raise errors.AnsibleError("variables assigned to group must be in key=value form")
199                else:
200                    (k, v) = [e.strip() for e in line.split("=", 1)]
201                    group.set_variable(k, self._parse_value(v))
202
203    def get_host_variables(self, host):
204        return {}