Merge pull request #22 from akutz/feature/env-var-support

Support data access via env vars
diff --git a/.gitignore b/.gitignore
index 2d0bb33..8ee179a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,6 @@
 /metadata.json
 /test.sh
 /userdata.yaml
-.DS_Store
\ No newline at end of file
+.DS_Store
+*.pyc
+/__pycache__
\ No newline at end of file
diff --git a/DataSourceVMwareGuestInfo.py b/DataSourceVMwareGuestInfo.py
index c9db71d..9fe83ac 100644
--- a/DataSourceVMwareGuestInfo.py
+++ b/DataSourceVMwareGuestInfo.py
@@ -23,7 +23,9 @@
 import copy
 from distutils.spawn import find_executable
 import json
+import os
 import socket
+import string
 import zlib
 
 from cloudinit import log as logging
@@ -37,6 +39,7 @@
 LOG = logging.getLogger(__name__)
 NOVAL = "No value found"
 VMTOOLSD = find_executable("vmtoolsd")
+VMX_GUESTINFO = "VMX_GUESTINFO"
 
 
 class NetworkConfigError(Exception):
@@ -90,7 +93,7 @@
 
     def __init__(self, sys_cfg, distro, paths, ud_proc=None):
         sources.DataSource.__init__(self, sys_cfg, distro, paths, ud_proc)
-        if not VMTOOLSD:
+        if not get_data_access_method():
             LOG.error("Failed to find vmtoolsd")
 
     def get_data(self):
@@ -103,7 +106,7 @@
         that the get_data functions in newer versions of cloud-init do,
         such as calling persist_instance_data.
         """
-        if not VMTOOLSD:
+        if not get_data_access_method():
             LOG.error("vmtoolsd is required to fetch guestinfo value")
             return False
 
@@ -231,24 +234,37 @@
     Returns a guestinfo value for the specified key.
     '''
     LOG.debug("Getting guestinfo value for key %s", key)
-    try:
-        (stdout, stderr) = util.subp(
-            [VMTOOLSD, "--cmd", "info-get guestinfo." + key])
-        if stderr == NOVAL:
-            LOG.debug("No value found for key %s", key)
-        elif not stdout:
-            LOG.error("Failed to get guestinfo value for key %s", key)
-        else:
-            return stdout.rstrip()
-    except util.ProcessExecutionError as error:
-        if error.stderr == NOVAL:
+
+    data_access_method = get_data_access_method()
+
+    if data_access_method == VMX_GUESTINFO:
+        env_key = ("vmx.guestinfo." + key).upper().replace(".", "_", -1)
+        val = os.environ.get(env_key, "")
+        if val == "":
             LOG.debug("No value found for key %s", key)
         else:
+            return val
+
+    if data_access_method == VMTOOLSD:
+        try:
+            (stdout, stderr) = util.subp(
+                [VMTOOLSD, "--cmd", "info-get guestinfo." + key])
+            if stderr == NOVAL:
+                LOG.debug("No value found for key %s", key)
+            elif not stdout:
+                LOG.error("Failed to get guestinfo value for key %s", key)
+            else:
+                return stdout.rstrip()
+        except util.ProcessExecutionError as error:
+            if error.stderr == NOVAL:
+                LOG.debug("No value found for key %s", key)
+            else:
+                util.logexc(
+                    LOG, "Failed to get guestinfo value for key %s: %s", key, error)
+        except Exception:
             util.logexc(
-                LOG, "Failed to get guestinfo value for key %s: %s", key, error)
-    except Exception:
-        util.logexc(
-            LOG, "Unexpected error while trying to get guestinfo value for key %s", key)
+                LOG, "Unexpected error while trying to get guestinfo value for key %s", key)
+
     return None
 
 
@@ -397,6 +413,8 @@
     return ipv4, ipv6
 
 # patched socket.getfqdn() - see https://bugs.python.org/issue5004
+
+
 def getfqdn(name=''):
     """Get fully qualified domain name from name.
      An empty argument is interpreted as meaning the local host.
@@ -405,7 +423,8 @@
     if not name or name == '0.0.0.0':
         name = socket.gethostname()
     try:
-        addrs = socket.getaddrinfo(name, None, 0, socket.SOCK_DGRAM, 0, socket.AI_CANONNAME)
+        addrs = socket.getaddrinfo(
+            name, None, 0, socket.SOCK_DGRAM, 0, socket.AI_CANONNAME)
     except socket.error:
         pass
     else:
@@ -415,6 +434,7 @@
                 break
     return name
 
+
 def get_host_info():
     '''
     Returns host information such as the host name and network interfaces.
@@ -494,6 +514,14 @@
     return host_info
 
 
+def get_data_access_method():
+    if os.environ.get(VMX_GUESTINFO, ""):
+        return VMX_GUESTINFO
+    if VMTOOLSD:
+        return VMTOOLSD
+    return None
+
+
 def main():
     '''
     Executed when this file is used as a program.