Remove deepmerge dependency

This patch removes the deepmerge module as a required dependency
of this cloud-init datasource. There is still an option to use
the deepmerge module if the environment variable
CLOUD_INIT_VMWARE_GUEST_INFO_MERGE_STRATEGY is set to 'deepmerge'.
Otherwise a deep merge is performed with a recursive strategy using
Python built-ins.
diff --git a/DataSourceVMwareGuestInfo.py b/DataSourceVMwareGuestInfo.py
index 8fea17d..298be76 100644
--- a/DataSourceVMwareGuestInfo.py
+++ b/DataSourceVMwareGuestInfo.py
@@ -36,7 +36,6 @@
 from cloudinit import util
 from cloudinit import safeyaml
 
-from deepmerge import always_merger
 import netifaces
 
 # from cloud-init >= 20.3 subp is in its own module
@@ -58,6 +57,7 @@
 WAIT_ON_NETWORK_IPV4 = 'ipv4'
 WAIT_ON_NETWORK_IPV6 = 'ipv6'
 
+
 class NetworkConfigError(Exception):
     '''
     NetworkConfigError is raised when there is an issue getting or
@@ -165,7 +165,7 @@
         # Ensure the metadata gets updated with information about the
         # host, including the network interfaces, default IP addresses,
         # etc.
-        self.metadata = always_merger.merge(self.metadata, host_info)
+        self.metadata = merge_dicts(self.metadata, host_info)
 
         # Persist the instance data for versions of cloud-init that support
         # doing so. This occurs here rather than in the get_data call in
@@ -307,6 +307,7 @@
     LOG.debug("No value found for key %s", key)
     return None
 
+
 def get_guestinfo_value(key):
     '''
     Returns a guestinfo value for the specified key.
@@ -725,14 +726,49 @@
     return None
 
 
+_MERGE_STRATEGY_ENV_VAR = 'CLOUD_INIT_VMWARE_GUEST_INFO_MERGE_STRATEGY'
+_MERGE_STRATEGY_DEEPMERGE = 'deepmerge'
+
+
+def merge_dicts(a, b):
+    merge_strategy = os.getenv(_MERGE_STRATEGY_ENV_VAR)
+    if merge_strategy == _MERGE_STRATEGY_DEEPMERGE:
+        try:
+            LOG.info('merging dictionaries with deepmerge strategy')
+            return merge_dicts_with_deep_merge(a, b)
+        except Exception as err:
+            LOG.error("deep merge failed: %s" % err)
+    LOG.info('merging dictionaries with stdlib strategy')
+    return merge_dicts_with_stdlib(a, b)
+
+
+def merge_dicts_with_deep_merge(a, b):
+    from deepmerge import always_merger
+    return always_merger.merge(a, b)
+
+
+def merge_dicts_with_stdlib(a, b):
+    for key, value in a.items():
+        if isinstance(value, dict):
+            node = b.setdefault(key, {})
+            merge_dicts_with_stdlib(value, node)
+        else:
+            b[key] = value
+    return b
+
+
 def main():
     '''
     Executed when this file is used as a program.
     '''
+    try:
+        logging.setupBasicLogging()
+    except Exception:
+        pass
     metadata = {'wait-on-network': {'ipv4': True, 'ipv6': "false"},
                 'network': {'config': {'dhcp': True}}}
     host_info = wait_on_network(metadata)
-    metadata = always_merger.merge(metadata, host_info)
+    metadata = merge_dicts(metadata, host_info)
     print(util.json_dumps(metadata))
 
 
diff --git a/install.sh b/install.sh
index bf25191..6a51de1 100755
--- a/install.sh
+++ b/install.sh
@@ -59,10 +59,11 @@
 fi
 echo "using python ${PYTHON_VERSION}"
 
-# The python modules deepmerge and netifaces are required. If they are
-# already installed, an assumption is made they are the correct versions.
-# Otherwise an attempt is made to install them with pip.
-if [ -z "$(get_py_mod_dir deepmerge)" ] || [ -z "$(get_py_mod_dir netifaces)" ]; then
+# The following modules are required:
+#   * netifaces
+# If a module is already installed then it is assumed to be compatible.
+# Otherwise an attempt is made to install the module with pip.
+if [ -z "$(get_py_mod_dir netifaces)" ]; then
   echo "installing requirements"
   if [ -z "$(get_py_mod_dir pip)" ]; then
     echo "pip is required" 1>&2
diff --git a/requirements.txt b/requirements.txt
index d726390..27ad3a4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1 @@
-deepmerge >= 0.0.5
 netifaces >= 0.10.9
\ No newline at end of file