From 62fbbf76532cb2dc2cc9216aa4dd96182c91e6d2 Mon Sep 17 00:00:00 2001
From: Michael DeHaan <michael.dehaan@gmail.com>
Date: Mon, 13 Aug 2012 19:17:14 -0400
Subject: [PATCH] config file support

---
 MANIFEST.in                |  1 +
 examples/ansible.cfg       | 68 +++++++++++++++++++++++++++
 lib/ansible/constants.py   | 96 ++++++++++++++++++++++++++++++--------
 packaging/rpm/ansible.spec |  1 +
 4 files changed, 146 insertions(+), 20 deletions(-)
 create mode 100644 examples/ansible.cfg

diff --git a/MANIFEST.in b/MANIFEST.in
index 98592d83a21..15d0a74b3c4 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,5 +1,6 @@
 include README.md packaging/rpm/ansible.spec COPYING
 include examples/hosts
+include examples/ansible.cfg
 include packaging/distutils/setup.py
 recursive-include docs *
 recursive-include library *
diff --git a/examples/ansible.cfg b/examples/ansible.cfg
new file mode 100644
index 00000000000..29d9b4874f6
--- /dev/null
+++ b/examples/ansible.cfg
@@ -0,0 +1,68 @@
+# config file for ansible -- http://ansible.github.com
+# nearly all parameters can be overridden in ansible-playbook or with command line flags
+# ansible will read ~/.ansible.cfg or /etc/ansible.cfg, whichever it finds first
+
+[defaults]
+
+# location of inventory file, eliminates need to specify -i
+
+hostfile = /etc/ansible/hosts
+
+# location of ansible library, eliminates need to specify --module-path
+
+library = /usr/share/ansible2
+
+# default module name used in /usr/bin/ansible when -m is not specified
+
+module_name = command
+
+# home directory where temp files are stored on remote systems.  Should
+# almost always contain $HOME or be a directory writeable by all users
+
+remote_tmp = $HOME/.ansible/tmp
+
+# the default pattern for ansible-playbooks ("hosts:") 
+
+pattern = *
+
+# the default number of forks (parallelism) to be used.  Usually you
+# can crank this up.
+
+forks=5
+
+# the timeout used by various connection types.  Usually this corresponds
+# to an SSH timeout
+
+timeout=10
+
+# when using --poll or "poll:" in an ansible playbook, and not specifying
+# an explicit poll interval, use this interval
+
+poll_interval=15
+
+# when specifying --sudo to /usr/bin/ansible or "sudo:" in a playbook,
+# and not specifying "--sudo-user" or "sudo_user" respectively, sudo
+# to this user account
+
+sudo_user=root
+
+# connection to use when -c <connection_type> is not specified
+
+transport=paramiko
+
+# remote SSH port to be used when --port or "port:" or an equivalent inventory
+# variable is not specified.
+
+remote_port=22
+
+# if set, always run /usr/bin/ansible commands as this user, and assume this value
+# if "user:" is not set in a playbook.  If not set, use the current Unix user
+# as the default
+
+#remote_user=root
+
+# if set, always use this private key file for authentication, same as if passing
+# --private-key-file to ansible or ansible-playbook
+
+#private_key_file=/path/to/file
+
diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py
index b5084837f8f..c5363babac6 100644
--- a/lib/ansible/constants.py
+++ b/lib/ansible/constants.py
@@ -17,28 +17,84 @@
 
 import os
 import pwd
+import ConfigParser
+import traceback
 
-DEFAULT_HOST_LIST      = os.environ.get('ANSIBLE_HOSTS', '/etc/ansible/hosts')
-DEFAULT_MODULE_PATH    = os.environ.get('ANSIBLE_LIBRARY', '/usr/share/ansible')
-DEFAULT_REMOTE_TMP     = os.environ.get('ANSIBLE_REMOTE_TMP', '$HOME/.ansible/tmp')
+def get_config(p, section, key, env_var, default):
+    if p is not None:
+        try:
+            return p.get(section, key)
+        except:
+            if env_var is not None:
+                return os.environ.get(env_var, default)
+            return default
+    else:
+        if env_var is not None:
+            return os.environ.get(env_var, default)
+        return default
 
-DEFAULT_MODULE_NAME    = 'command'
-DEFAULT_PATTERN        = '*'
-DEFAULT_FORKS          = os.environ.get('ANSIBLE_FORKS',5)
-DEFAULT_MODULE_ARGS    = os.environ.get('ANSIBLE_MODULE_ARGS','')
-DEFAULT_TIMEOUT        = os.environ.get('ANSIBLE_TIMEOUT',10)
-DEFAULT_POLL_INTERVAL  = os.environ.get('ANSIBLE_POLL_INTERVAL',15)
-DEFAULT_REMOTE_USER    = os.environ.get('ANSIBLE_REMOTE_USER', None)
 
-if DEFAULT_REMOTE_USER is None:
-    DEFAULT_REMOTE_USER = pwd.getpwuid(os.geteuid())[0]
+def load_config_file():
+    p = ConfigParser.ConfigParser()
+    path1 = os.path.expanduser("~/.ansible.cfg")
+    path2 = "/etc/ansible/ansible.cfg"
+    if os.path.exists(path1):
+        print "A1"
+        p.read(path1)
+    elif os.path.exists(path2):
+        print "A2"
+        p.read(path2)
+    else:
+        return None
+    return p
 
-DEFAULT_REMOTE_PASS    = None
-DEFAULT_PRIVATE_KEY_FILE    = os.environ.get('ANSIBLE_PRIVATE_KEY_FILE',None)
-DEFAULT_SUDO_PASS      = None
-DEFAULT_SUDO_USER      = os.environ.get('ANSIBLE_SUDO_USER','root')
-DEFAULT_REMOTE_PORT    = 22
-DEFAULT_TRANSPORT      = os.environ.get('ANSIBLE_TRANSPORT','paramiko')
-DEFAULT_TRANSPORT_OPTS = ['local', 'paramiko', 'ssh']
-DEFAULT_SUBSET         = None
+p = load_config_file()
 
+active_user   = pwd.getpwuid(os.geteuid())[0]
+
+# sections in config file
+DEFAULTS='defaults'
+
+# configurable things
+DEFAULT_HOST_LIST         = get_config(p, DEFAULTS, 'hostfile',         'ANSIBLE_HOSTS',            '/etc/ansible/hosts')
+DEFAULT_MODULE_PATH       = get_config(p, DEFAULTS, 'library',          'ANSIBLE_LIBRARY',          '/usr/share/ansible')
+DEFAULT_REMOTE_TMP        = get_config(p, DEFAULTS, 'remote_tmp',       'ANSIBLE_REMOTE_TEMP',      '$HOME/.ansible/tmp')
+DEFAULT_MODULE_NAME       = get_config(p, DEFAULTS, 'module_name',      None,                       'command')
+DEFAULT_PATTERN           = get_config(p, DEFAULTS, 'pattern',          None,                       '*')
+DEFAULT_FORKS             = get_config(p, DEFAULTS, 'fork_count',       'ANSIBLE_FORKS',            5)
+DEFAULT_MODULE_ARGS       = get_config(p, DEFAULTS, 'module_args',      'ANSIBLE_MODULE_ARGS',      '')
+DEFAULT_TIMEOUT           = get_config(p, DEFAULTS, 'timeout',          'ANSIBLE_TIMEOUT',          10)
+DEFAULT_POLL_INTERVAL     = get_config(p, DEFAULTS, 'poll_interval',    'ANSIBLE_POLL_INTERVAL',    15)
+DEFAULT_REMOTE_USER       = get_config(p, DEFAULTS, 'remote_user',      'ANSIBLE_REMOTE_USER',      active_user)
+DEFAULT_PRIVATE_KEY_FILE  = get_config(p, DEFAULTS, 'private_key_file', 'ANSIBLE_PRIVATE_KEY_FILE', None)
+DEFAULT_SUDO_USER         = get_config(p, DEFAULTS, 'sudo_user',        'ANSIBLE_SUDO_USER',        'root')
+DEFAULT_REMOTE_PORT       = get_config(p, DEFAULTS, 'remote_port',      'ANSIBLE_REMOTE_PORT',      22)
+DEFAULT_TRANSPORT         = get_config(p, DEFAULTS, 'transport',        'ANSIBLE_TRANSPORT',        'paramiko')
+
+# non-configurable things
+DEFAULT_REMOTE_PASS       = None
+DEFAULT_TRANSPORT_OPTS    = ['local', 'paramiko', 'ssh']
+DEFAULT_SUDO_PASS         = None
+DEFAULT_SUBSET            = None
+
+def get_config(parser, section, key, env_var, default):
+    try:
+        return parser.get(section, key) 
+    except:
+        if env_var is not None:
+            return os.environ.get(env_var, default)
+        return default
+
+def load_config_file():
+    config = ConfigParser.ConfigParser()
+    path1 = os.path.expanduser("~/.ansible.cfg")
+    path2 = "/etc/ansible/ansible.cfg"
+    if os.path.exists(path1):
+        config.read(path1)
+    elif os.path.exists(path2):
+        config.read(path2)
+    else: 
+        return None
+    return config
+
+print "MODULE PATH=%s" % DEFAULT_MODULE_PATH
diff --git a/packaging/rpm/ansible.spec b/packaging/rpm/ansible.spec
index b7c6a327627..5dfd25b4953 100644
--- a/packaging/rpm/ansible.spec
+++ b/packaging/rpm/ansible.spec
@@ -39,6 +39,7 @@ are transferred to managed machines automatically.
 %{__python} setup.py install -O1 --root=$RPM_BUILD_ROOT
 mkdir -p $RPM_BUILD_ROOT/etc/ansible/
 cp examples/hosts $RPM_BUILD_ROOT/etc/ansible/
+cp examples/ansible.cfg $RPM_BUILD_ROOT/etc/ansible/
 mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man1/
 cp -v docs/man/man1/*.1 $RPM_BUILD_ROOT/%{_mandir}/man1/
 mkdir -p $RPM_BUILD_ROOT/%{_datadir}/ansible