Fixing some v2 inventory bugs

pull/10122/head
James Cammarata 10 years ago
parent b6a34518ad
commit 4d9bf37afa

@ -32,15 +32,9 @@ from ansible.inventory.dir import InventoryDirectory
from ansible.inventory.group import Group
from ansible.inventory.host import Host
from ansible.plugins import vars_loader
from ansible.utils.path import is_executable
from ansible.utils.vars import combine_vars
# FIXME: these defs need to be somewhere else
def is_executable(path):
'''is the given path executable?'''
return (stat.S_IXUSR & os.stat(path)[stat.ST_MODE]
or stat.S_IXGRP & os.stat(path)[stat.ST_MODE]
or stat.S_IXOTH & os.stat(path)[stat.ST_MODE])
class Inventory(object):
"""
Host inventory for ansible.
@ -108,7 +102,7 @@ class Inventory(object):
if os.path.isdir(host_list):
# Ensure basedir is inside the directory
self.host_list = os.path.join(self.host_list, "")
self.parser = InventoryDirectory(filename=host_list)
self.parser = InventoryDirectory(loader=self._loader, filename=host_list)
self.groups = self.parser.groups.values()
else:
# check to see if the specified file starts with a
@ -124,10 +118,9 @@ class Inventory(object):
except:
pass
# FIXME: utils is_executable
if is_executable(host_list):
try:
self.parser = InventoryScript(filename=host_list)
self.parser = InventoryScript(loader=self._loader, filename=host_list)
self.groups = self.parser.groups.values()
except:
if not shebang_present:

@ -19,18 +19,21 @@
#############################################
import os
import ansible.constants as C
from ansible import constants as C
from ansible.errors import *
from ansible.inventory.host import Host
from ansible.inventory.group import Group
from ansible.inventory.ini import InventoryParser
from ansible.inventory.script import InventoryScript
from ansible import utils
from ansible import errors
from ansible.utils.path import is_executable
from ansible.utils.vars import combine_vars
class InventoryDirectory(object):
''' Host inventory parser for ansible using a directory of inventories. '''
def __init__(self, filename=C.DEFAULT_HOST_LIST):
def __init__(self, loader, filename=C.DEFAULT_HOST_LIST):
self.names = os.listdir(filename)
self.names.sort()
self.directory = filename
@ -38,10 +41,12 @@ class InventoryDirectory(object):
self.hosts = {}
self.groups = {}
self._loader = loader
for i in self.names:
# Skip files that end with certain extensions or characters
if any(i.endswith(ext) for ext in ("~", ".orig", ".bak", ".ini", ".retry", ".pyc", ".pyo")):
if any(i.endswith(ext) for ext in ("~", ".orig", ".bak", ".ini", ".cfg", ".retry", ".pyc", ".pyo")):
continue
# Skip hidden files
if i.startswith('.') and not i.startswith('./'):
@ -51,9 +56,9 @@ class InventoryDirectory(object):
continue
fullpath = os.path.join(self.directory, i)
if os.path.isdir(fullpath):
parser = InventoryDirectory(filename=fullpath)
elif utils.is_executable(fullpath):
parser = InventoryScript(filename=fullpath)
parser = InventoryDirectory(loader=loader, filename=fullpath)
elif is_executable(fullpath):
parser = InventoryScript(loader=loader, filename=fullpath)
else:
parser = InventoryParser(filename=fullpath)
self.parsers.append(parser)
@ -196,7 +201,7 @@ class InventoryDirectory(object):
self.groups[newparent.name].add_child_group(group)
# variables
group.vars = utils.combine_vars(group.vars, newgroup.vars)
group.vars = combine_vars(group.vars, newgroup.vars)
def _merge_hosts(self,host, newhost):
""" Merge all of instance newhost into host """
@ -218,7 +223,7 @@ class InventoryDirectory(object):
self.groups[newgroup.name].add_host(host)
# variables
host.vars = utils.combine_vars(host.vars, newhost.vars)
host.vars = combine_vars(host.vars, newhost.vars)
def get_host_variables(self, host):
""" Gets additional host variables from all inventories """

@ -34,7 +34,7 @@ class InventoryParser(object):
"""
def __init__(self, filename=C.DEFAULT_HOST_LIST):
self.filename = filename
with open(filename) as fh:
self.lines = fh.readlines()
self.groups = {}
@ -142,7 +142,7 @@ class InventoryParser(object):
try:
(k,v) = t.split("=", 1)
except ValueError, e:
raise AnsibleError("Invalid ini entry: %s - %s" % (t, str(e)))
raise AnsibleError("Invalid ini entry in %s: %s - %s" % (self.filename, t, str(e)))
if k == 'ansible_ssh_host':
host.ipv4_address = self._parse_value(v)
else:

@ -19,19 +19,21 @@
import os
import subprocess
import ansible.constants as C
import sys
from ansible import constants as C
from ansible.errors import *
from ansible.inventory.host import Host
from ansible.inventory.group import Group
from ansible.module_utils.basic import json_dict_bytes_to_unicode
from ansible import utils
from ansible import errors
import sys
class InventoryScript(object):
class InventoryScript:
''' Host inventory parser for ansible using external inventory scripts. '''
def __init__(self, filename=C.DEFAULT_HOST_LIST):
def __init__(self, loader, filename=C.DEFAULT_HOST_LIST):
self._loader = loader
# Support inventory scripts that are not prefixed with some
# path information but happen to be in the current working
@ -41,11 +43,11 @@ class InventoryScript(object):
try:
sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except OSError, e:
raise errors.AnsibleError("problem running %s (%s)" % (' '.join(cmd), e))
raise AnsibleError("problem running %s (%s)" % (' '.join(cmd), e))
(stdout, stderr) = sp.communicate()
if sp.returncode != 0:
raise errors.AnsibleError("Inventory script (%s) had an execution error: %s " % (filename,stderr))
raise AnsibleError("Inventory script (%s) had an execution error: %s " % (filename,stderr))
self.data = stdout
# see comment about _meta below
@ -58,7 +60,7 @@ class InventoryScript(object):
all_hosts = {}
# not passing from_remote because data from CMDB is trusted
self.raw = utils.parse_json(self.data)
self.raw = self._loader.load(self.data)
self.raw = json_dict_bytes_to_unicode(self.raw)
all = Group('all')
@ -68,7 +70,7 @@ class InventoryScript(object):
if 'failed' in self.raw:
sys.stderr.write(err + "\n")
raise errors.AnsibleError("failed to parse executable inventory script results: %s" % self.raw)
raise AnsibleError("failed to parse executable inventory script results: %s" % self.raw)
for (group_name, data) in self.raw.items():
@ -97,7 +99,7 @@ class InventoryScript(object):
if 'hosts' in data:
if not isinstance(data['hosts'], list):
raise errors.AnsibleError("You defined a group \"%s\" with bad "
raise AnsibleError("You defined a group \"%s\" with bad "
"data for the host list:\n %s" % (group_name, data))
for hostname in data['hosts']:
@ -108,7 +110,7 @@ class InventoryScript(object):
if 'vars' in data:
if not isinstance(data['vars'], dict):
raise errors.AnsibleError("You defined a group \"%s\" with bad "
raise AnsibleError("You defined a group \"%s\" with bad "
"data for variables:\n %s" % (group_name, data))
for k, v in data['vars'].iteritems():
@ -143,12 +145,12 @@ class InventoryScript(object):
try:
sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except OSError, e:
raise errors.AnsibleError("problem running %s (%s)" % (' '.join(cmd), e))
raise AnsibleError("problem running %s (%s)" % (' '.join(cmd), e))
(out, err) = sp.communicate()
if out.strip() == '':
return dict()
try:
return json_dict_bytes_to_unicode(utils.parse_json(out))
return json_dict_bytes_to_unicode(self._loader.load(out))
except ValueError:
raise errors.AnsibleError("could not parse post variable response: %s, %s" % (cmd, out))
raise AnsibleError("could not parse post variable response: %s, %s" % (cmd, out))

@ -66,7 +66,6 @@ class DataLoader():
a JSON or YAML string.
'''
#print("in load, data is: %s (%s)" % (data, type(data)))
try:
# we first try to load this data as JSON
return json.loads(data)
@ -109,8 +108,6 @@ class DataLoader():
def _safe_load(self, stream, file_name=None):
''' Implements yaml.safe_load(), except using our custom loader class. '''
#print("stream is: %s" % stream)
#print("file name is: %s" % file_name)
loader = AnsibleLoader(stream, file_name)
try:
return loader.get_single_data()

@ -0,0 +1,26 @@
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
#
# 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 <http://www.gnu.org/licenses/>.
import os
import stat
__all__ = ['is_executable']
def is_executable(path):
'''is the given path executable?'''
return (stat.S_IXUSR & os.stat(path)[stat.ST_MODE] or stat.S_IXGRP & os.stat(path)[stat.ST_MODE] or stat.S_IXOTH & os.stat(path)[stat.ST_MODE])
Loading…
Cancel
Save