Renamed project/datasource; Install script

This patch refactors the name of the project, datasource,
and adds an install script that can be curl bashed on
Linux distributions that do not yet have a proper package
for this datasource.
diff --git a/DataSourceVMwareGuestInfo.py b/DataSourceVMwareGuestInfo.py
new file mode 100644
index 0000000..8131253
--- /dev/null
+++ b/DataSourceVMwareGuestInfo.py
@@ -0,0 +1,153 @@
+# vi: ts=4 expandtab
+#
+# Copyright (C) 2018 VMware Inc.
+#
+# Authors: Anish Swaminathan <anishs@vmware.com>
+#          Andrew Kutz <akutz@vmware.com>
+#
+import os
+import base64
+import zlib
+import json
+
+from cloudinit import log as logging
+from cloudinit import sources
+from cloudinit import util
+from cloudinit import safeyaml
+
+from distutils.spawn import find_executable
+
+LOG = logging.getLogger(__name__)
+
+# This cloud-init datasource was designed for use with CentOS 7,
+# which uses cloud-init 0.7.9. However, this datasource should
+# work with any Linux distribution for which cloud-init is 
+# avaialble.
+#
+# The documentation for cloud-init 0.7.9's datasource is 
+# available at http://bit.ly/cloudinit-datasource-0-7-9. The
+# current documentation for cloud-init is found at
+# https://cloudinit.readthedocs.io/en/latest/.
+#
+# Setting the hostname:
+#     The hostname is set by way of the metadata key "local-hostname".
+#
+# Setting the instance ID:
+#     The instance ID may be set by way of the metadata key "instance-id".
+#     However, if this value is absent then then the instance ID is
+#     read from the file /sys/class/dmi/id/product_uuid.
+#
+# Configuring the network:
+#     The network is configured by setting the metadata key "network"
+#     with a value consistent with Network Config Versions 1 or 2,
+#     depending on the Linux distro's version of cloud-init:
+#
+#         Network Config Version 1 - http://bit.ly/cloudinit-net-conf-v1
+#         Network Config Version 2 - http://bit.ly/cloudinit-net-conf-v2
+#
+#     For example, CentOS 7's official cloud-init package is version
+#     0.7.9 and does not support Network Config Version 2. However,
+#     this datasource still supports supplying Network Config Version 2
+#     data as long as the Linux distro's cloud-init package is new
+#     enough to parse the data.
+#
+#     The metadata key "network.encoding" may be used to indicate the
+#     format of the metadata key "network". Valid encodings are base64
+#     and gzip+base64.
+class DataSourceVMwareGuestInfo(sources.DataSource):
+    def __init__(self, sys_cfg, distro, paths, ud_proc=None):
+        sources.DataSource.__init__(self, sys_cfg, distro, paths, ud_proc)
+        self.vmtoolsd = find_executable("vmtoolsd")
+        if not self.vmtoolsd:
+            LOG.error("Failed to find vmtoolsd")
+
+    def get_data(self):
+        if not self.vmtoolsd:
+            LOG.error("vmtoolsd is required to fetch guestinfo value")
+            return False
+
+        # Get the JSON metadata. Can be plain-text, base64, or gzip+base64.
+        metadata = self._get_encoded_guestinfo_data('metadata')
+        if metadata:
+            self.metadata = json.loads(metadata)
+
+        # Get the YAML userdata. Can be plain-text, base64, or gzip+base64.
+        self.userdata_raw = self._get_encoded_guestinfo_data('userdata')
+
+        # Get the YAML vendordata. Can be plain-text, base64, or gzip+base64.
+        self.vendordata_raw = self._get_encoded_guestinfo_data('vendordata')
+
+        return True
+
+    @property
+    def network_config(self):
+        # Pull the network configuration out of the metadata.
+        if self.metadata and 'network' in self.metadata:
+            data = self._get_encoded_metadata('network')
+            if data:
+                # Load the YAML-formatted network data into an object
+                # and return it.
+                net_config = safeyaml.load(data)
+                LOG.debug("Loaded network config: %s", net_config)
+                return net_config
+        return None
+
+    def get_instance_id(self):
+        # Pull the instance ID out of the metadata if present. Otherwise
+        # read the file /sys/class/dmi/id/product_uuid for the instance ID.
+        if self.metadata and 'instance-id' in self.metadata:
+            return self.metadata['instance-id']
+        with open('/sys/class/dmi/id/product_uuid', 'r') as id_file:
+            return str(id_file.read()).rstrip()
+
+    def _get_encoded_guestinfo_data(self, key):
+        data = self._get_guestinfo_value(key)
+        if not data:
+            return None
+        enc_type = self._get_guestinfo_value(key + '.encoding')
+        return self._get_encoded_data('guestinfo.' + key, enc_type, data)
+
+    def _get_encoded_metadata(self, key):
+        if not self.metadata or not key in self.metadata:
+            return None
+        data = self.metadata[key]
+        enc_type = self.metadata.get(key + '.encoding')
+        return self._get_encoded_data('metadata.' + key, enc_type, data)
+
+    def _get_encoded_data(self, key, enc_type, data):
+        LOG.debug("Getting encoded data for key=%s, enc=%s", key, enc_type)
+        if enc_type == "gzip+base64" or enc_type == "gz+b64":
+            LOG.debug("Decoding %s format %s", enc_type, key)
+            return zlib.decompress(base64.b64decode(data), zlib.MAX_WBITS | 16)
+        elif enc_type == "base64" or enc_type == "b64":
+            LOG.debug("Decoding %s format %s", enc_type, key)
+            return base64.b64decode(data)
+        else:
+            LOG.debug("Plain-text data %s", key)
+            return data
+
+    def _get_guestinfo_value(self, key):
+        NOVAL = "No value found"
+        LOG.debug("Getting guestinfo value for key %s", key)
+        try:
+            (stdout, stderr) = util.subp([self.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,"Unexpected error while trying to get guestinfo value for key %s", key)
+        return None
+
+def get_datasource_list(depends):
+    """
+    Return a list of data sources that match this set of dependencies
+    """
+    return [DataSourceVMwareGuestInfo]