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