From 11630044d235e0c6e1ffd2b12ff8906613ccdac6 Mon Sep 17 00:00:00 2001
From: xiaofengw-vmware <42736879+xiaofengw-vmware@users.noreply.github.com>
Date: Thu, 14 Jan 2021 07:18:28 +0800
Subject: [VMware] Support cloudinit raw data feature (#691)
This feature will modify VMware datasource to read from meta data and user data which are specified by VMware vSphere user. If meta data/user data are found in cloud-init configuration directory, datasource will parse the meta data/network and user data from the configuration file, otherwise it will continue to parse them from traditional customization configuration file as before. The supported meta data file is in json or yaml format.
---
cloudinit/sources/DataSourceOVF.py | 162 ++++++++++++++++++++++++++++++++++---
1 file changed, 150 insertions(+), 12 deletions(-)
(limited to 'cloudinit/sources/DataSourceOVF.py')
diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py
index 741c140a..94d9f1b9 100644
--- a/cloudinit/sources/DataSourceOVF.py
+++ b/cloudinit/sources/DataSourceOVF.py
@@ -16,6 +16,7 @@ from xml.dom import minidom
from cloudinit import dmi
from cloudinit import log as logging
+from cloudinit import safeyaml
from cloudinit import sources
from cloudinit import subp
from cloudinit import util
@@ -47,6 +48,7 @@ LOG = logging.getLogger(__name__)
CONFGROUPNAME_GUESTCUSTOMIZATION = "deployPkg"
GUESTCUSTOMIZATION_ENABLE_CUST_SCRIPTS = "enable-custom-scripts"
+VMWARE_IMC_DIR = "/var/run/vmware-imc"
class DataSourceOVF(sources.DataSource):
@@ -99,9 +101,7 @@ class DataSourceOVF(sources.DataSource):
if not self.vmware_customization_supported:
LOG.debug("Skipping the check for "
"VMware Customization support")
- elif not util.get_cfg_option_bool(
- self.sys_cfg, "disable_vmware_customization", True):
-
+ else:
search_paths = (
"/usr/lib/vmware-tools", "/usr/lib64/vmware-tools",
"/usr/lib/open-vm-tools", "/usr/lib64/open-vm-tools")
@@ -119,7 +119,9 @@ class DataSourceOVF(sources.DataSource):
# When the VM is powered on, the "VMware Tools" daemon
# copies the customization specification file to
# /var/run/vmware-imc directory. cloud-init code needs
- # to search for the file in that directory.
+ # to search for the file in that directory which indicates
+ # that required metadata and userdata files are now
+ # present.
max_wait = get_max_wait_from_cfg(self.ds_cfg)
vmwareImcConfigFilePath = util.log_time(
logfunc=LOG.debug,
@@ -129,26 +131,83 @@ class DataSourceOVF(sources.DataSource):
else:
LOG.debug("Did not find the customization plugin.")
+ md_path = None
if vmwareImcConfigFilePath:
+ imcdirpath = os.path.dirname(vmwareImcConfigFilePath)
+ cf = ConfigFile(vmwareImcConfigFilePath)
+ self._vmware_cust_conf = Config(cf)
LOG.debug("Found VMware Customization Config File at %s",
vmwareImcConfigFilePath)
- nicspath = wait_for_imc_cfg_file(
- filename="nics.txt", maxwait=10, naplen=5)
+ try:
+ (md_path, ud_path, nicspath) = collect_imc_file_paths(
+ self._vmware_cust_conf)
+ except FileNotFoundError as e:
+ _raise_error_status(
+ "File(s) missing in directory",
+ e,
+ GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
+ vmwareImcConfigFilePath,
+ self._vmware_cust_conf)
else:
LOG.debug("Did not find VMware Customization Config File")
- else:
- LOG.debug("Customization for VMware platform is disabled.")
- if vmwareImcConfigFilePath:
+ # Honor disable_vmware_customization setting on metadata absent
+ if not md_path:
+ if util.get_cfg_option_bool(self.sys_cfg,
+ "disable_vmware_customization",
+ True):
+ LOG.debug(
+ "Customization for VMware platform is disabled.")
+ # reset vmwareImcConfigFilePath to None to avoid
+ # customization for VMware platform
+ vmwareImcConfigFilePath = None
+
+ use_raw_data = bool(vmwareImcConfigFilePath and md_path)
+ if use_raw_data:
+ set_gc_status(self._vmware_cust_conf, "Started")
+ LOG.debug("Start to load cloud-init meta data and user data")
+ try:
+ (md, ud, cfg, network) = load_cloudinit_data(md_path, ud_path)
+
+ if network:
+ self._network_config = network
+ else:
+ self._network_config = (
+ self.distro.generate_fallback_config()
+ )
+
+ except safeyaml.YAMLError as e:
+ _raise_error_status(
+ "Error parsing the cloud-init meta data",
+ e,
+ GuestCustErrorEnum.GUESTCUST_ERROR_WRONG_META_FORMAT,
+ vmwareImcConfigFilePath,
+ self._vmware_cust_conf)
+ except Exception as e:
+ _raise_error_status(
+ "Error loading cloud-init configuration",
+ e,
+ GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
+ vmwareImcConfigFilePath,
+ self._vmware_cust_conf)
+
+ self._vmware_cust_found = True
+ found.append('vmware-tools')
+
+ util.del_dir(imcdirpath)
+ set_customization_status(
+ GuestCustStateEnum.GUESTCUST_STATE_DONE,
+ GuestCustErrorEnum.GUESTCUST_ERROR_SUCCESS)
+ set_gc_status(self._vmware_cust_conf, "Successful")
+
+ elif vmwareImcConfigFilePath:
+ # Load configuration from vmware_imc
self._vmware_nics_to_enable = ""
try:
- cf = ConfigFile(vmwareImcConfigFilePath)
- self._vmware_cust_conf = Config(cf)
set_gc_status(self._vmware_cust_conf, "Started")
(md, ud, cfg) = read_vmware_imc(self._vmware_cust_conf)
self._vmware_nics_to_enable = get_nics_to_enable(nicspath)
- imcdirpath = os.path.dirname(vmwareImcConfigFilePath)
product_marker = self._vmware_cust_conf.marker_id
hasmarkerfile = check_marker_exists(
product_marker, os.path.join(self.paths.cloud_dir, 'data'))
@@ -684,4 +743,83 @@ def _raise_error_status(prefix, error, event, config_file, conf):
util.del_dir(os.path.dirname(config_file))
raise error
+
+def load_cloudinit_data(md_path, ud_path):
+ """
+ Load the cloud-init meta data, user data, cfg and network from the
+ given files
+
+ @return: 4-tuple of configuration
+ metadata, userdata, cfg={}, network
+
+ @raises: FileNotFoundError if md_path or ud_path are absent
+ """
+ LOG.debug('load meta data from: %s: user data from: %s',
+ md_path, ud_path)
+ md = {}
+ ud = None
+ network = None
+
+ md = safeload_yaml_or_dict(util.load_file(md_path))
+
+ if 'network' in md:
+ network = md['network']
+
+ if ud_path:
+ ud = util.load_file(ud_path).replace("\r", "")
+ return md, ud, {}, network
+
+
+def safeload_yaml_or_dict(data):
+ '''
+ The meta data could be JSON or YAML. Since YAML is a strict superset of
+ JSON, we will unmarshal the data as YAML. If data is None then a new
+ dictionary is returned.
+ '''
+ if not data:
+ return {}
+ return safeyaml.load(data)
+
+
+def collect_imc_file_paths(cust_conf):
+ '''
+ collect all the other imc files.
+
+ metadata is preferred to nics.txt configuration data.
+
+ If metadata file exists because it is specified in customization
+ configuration, then metadata is required and userdata is optional.
+
+ @return a 3-tuple containing desired configuration file paths if present
+ Expected returns:
+ 1. user provided metadata and userdata (md_path, ud_path, None)
+ 2. user provided metadata (md_path, None, None)
+ 3. user-provided network config (None, None, nics_path)
+ 4. No config found (None, None, None)
+ '''
+ md_path = None
+ ud_path = None
+ nics_path = None
+ md_file = cust_conf.meta_data_name
+ if md_file:
+ md_path = os.path.join(VMWARE_IMC_DIR, md_file)
+ if not os.path.exists(md_path):
+ raise FileNotFoundError("meta data file is not found: %s"
+ % md_path)
+
+ ud_file = cust_conf.user_data_name
+ if ud_file:
+ ud_path = os.path.join(VMWARE_IMC_DIR, ud_file)
+ if not os.path.exists(ud_path):
+ raise FileNotFoundError("user data file is not found: %s"
+ % ud_path)
+ else:
+ nics_path = os.path.join(VMWARE_IMC_DIR, "nics.txt")
+ if not os.path.exists(nics_path):
+ LOG.debug('%s does not exist.', nics_path)
+ nics_path = None
+
+ return md_path, ud_path, nics_path
+
+
# vi: ts=4 expandtab
--
cgit v1.2.3
From 6efe16d8f28b89423f7e6e60fc0d4ab1f385f4d8 Mon Sep 17 00:00:00 2001
From: xiaofengw-vmware <42736879+xiaofengw-vmware@users.noreply.github.com>
Date: Thu, 28 Jan 2021 04:38:47 +0800
Subject: [VMware] change default max wait time to 15s (#774)
If cloud-init is enabled on VMware platform, cloud-init will wait until
its configuration file is ready and currently the max wait is 90
seconds by default. With our test, this configuration file should be
ready within 1 second, so change it to 15 seconds for better
performance. Also update the documentation about how to change the
default value in cloud-init configuration file.
---
cloudinit/sources/DataSourceOVF.py | 2 +-
doc/rtd/topics/datasources/ovf.rst | 9 +++++++++
2 files changed, 10 insertions(+), 1 deletion(-)
(limited to 'cloudinit/sources/DataSourceOVF.py')
diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py
index 94d9f1b9..bbeada0b 100644
--- a/cloudinit/sources/DataSourceOVF.py
+++ b/cloudinit/sources/DataSourceOVF.py
@@ -416,7 +416,7 @@ class DataSourceOVFNet(DataSourceOVF):
def get_max_wait_from_cfg(cfg):
- default_max_wait = 90
+ default_max_wait = 15
max_wait_cfg_option = 'vmware_cust_file_max_wait'
max_wait = default_max_wait
diff --git a/doc/rtd/topics/datasources/ovf.rst b/doc/rtd/topics/datasources/ovf.rst
index 6256e624..85b0c377 100644
--- a/doc/rtd/topics/datasources/ovf.rst
+++ b/doc/rtd/topics/datasources/ovf.rst
@@ -13,6 +13,15 @@ source code tree in doc/sources/ovf
Configuration
-------------
+The following configuration can be set for the datasource in system
+configuration (in `/etc/cloud/cloud.cfg` or `/etc/cloud/cloud.cfg.d/`).
+
+The settings that may be configured are:
+
+ * vmware_cust_file_max_wait: the maximum amount of clock time in seconds that
+ should be spent waiting for vmware customization files. (default: 15)
+
+
On VMware platforms, VMTools use is required for OVF datasource configuration
settings as well as vCloud and vSphere admin configuration. User could change
the VMTools configuration options with command::
--
cgit v1.2.3
From 108611aee26e09bec683e6cf1b8e03bec9362de9 Mon Sep 17 00:00:00 2001
From: xiaofengw-vmware <42736879+xiaofengw-vmware@users.noreply.github.com>
Date: Thu, 8 Jul 2021 23:14:33 +0800
Subject: VMware: new "allow_raw_data" switch (#939)
Add a new switch allow_raw_data to control raw data feature, update
the documentation. Fix bugs about max_wait.
---
cloudinit/sources/DataSourceOVF.py | 35 +++++++++----
doc/rtd/topics/datasources/ovf.rst | 4 ++
tests/unittests/test_datasource/test_ovf.py | 79 ++++++++++++++++++++++++++---
3 files changed, 100 insertions(+), 18 deletions(-)
(limited to 'cloudinit/sources/DataSourceOVF.py')
diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py
index bbeada0b..9e83dccc 100644
--- a/cloudinit/sources/DataSourceOVF.py
+++ b/cloudinit/sources/DataSourceOVF.py
@@ -98,9 +98,20 @@ class DataSourceOVF(sources.DataSource):
found.append(seed)
elif system_type and 'vmware' in system_type.lower():
LOG.debug("VMware Virtualization Platform found")
+ allow_vmware_cust = False
+ allow_raw_data = False
if not self.vmware_customization_supported:
LOG.debug("Skipping the check for "
"VMware Customization support")
+ else:
+ allow_vmware_cust = not util.get_cfg_option_bool(
+ self.sys_cfg, "disable_vmware_customization", True)
+ allow_raw_data = util.get_cfg_option_bool(
+ self.ds_cfg, "allow_raw_data", True)
+
+ if not (allow_vmware_cust or allow_raw_data):
+ LOG.debug(
+ "Customization for VMware platform is disabled.")
else:
search_paths = (
"/usr/lib/vmware-tools", "/usr/lib64/vmware-tools",
@@ -148,19 +159,21 @@ class DataSourceOVF(sources.DataSource):
GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
vmwareImcConfigFilePath,
self._vmware_cust_conf)
- else:
- LOG.debug("Did not find VMware Customization Config File")
-
- # Honor disable_vmware_customization setting on metadata absent
- if not md_path:
- if util.get_cfg_option_bool(self.sys_cfg,
- "disable_vmware_customization",
- True):
+ # Don't handle the customization for below 2 cases:
+ # 1. meta data is found, allow_raw_data is False.
+ # 2. no meta data is found, allow_vmware_cust is False.
+ if md_path and not allow_raw_data:
LOG.debug(
- "Customization for VMware platform is disabled.")
+ "Customization using raw data is disabled.")
# reset vmwareImcConfigFilePath to None to avoid
# customization for VMware platform
vmwareImcConfigFilePath = None
+ if md_path is None and not allow_vmware_cust:
+ LOG.debug(
+ "Customization using VMware config is disabled.")
+ vmwareImcConfigFilePath = None
+ else:
+ LOG.debug("Did not find VMware Customization Config File")
use_raw_data = bool(vmwareImcConfigFilePath and md_path)
if use_raw_data:
@@ -429,7 +442,7 @@ def get_max_wait_from_cfg(cfg):
LOG.warning("Failed to get '%s', using %s",
max_wait_cfg_option, default_max_wait)
- if max_wait <= 0:
+ if max_wait < 0:
LOG.warning("Invalid value '%s' for '%s', using '%s' instead",
max_wait, max_wait_cfg_option, default_max_wait)
max_wait = default_max_wait
@@ -440,6 +453,8 @@ def get_max_wait_from_cfg(cfg):
def wait_for_imc_cfg_file(filename, maxwait=180, naplen=5,
dirpath="/var/run/vmware-imc"):
waited = 0
+ if maxwait <= naplen:
+ naplen = 1
while waited < maxwait:
fileFullPath = os.path.join(dirpath, filename)
diff --git a/doc/rtd/topics/datasources/ovf.rst b/doc/rtd/topics/datasources/ovf.rst
index 43ee45ba..bd5df860 100644
--- a/doc/rtd/topics/datasources/ovf.rst
+++ b/doc/rtd/topics/datasources/ovf.rst
@@ -18,6 +18,10 @@ configuration (in `/etc/cloud/cloud.cfg` or `/etc/cloud/cloud.cfg.d/`).
The settings that may be configured are:
+ * disable_vmware_customization: disable or enable the vmware customization
+ based on vmware customization files. (default: True)
+ * allow_raw_data: enable or disable the vmware customization based on raw
+ cloud-init data including metadata and userdata. (default: True)
* vmware_cust_file_max_wait: the maximum amount of clock time in seconds that
should be spent waiting for vmware customization files. (default: 15)
diff --git a/tests/unittests/test_datasource/test_ovf.py b/tests/unittests/test_datasource/test_ovf.py
index dce01f5d..e2718077 100644
--- a/tests/unittests/test_datasource/test_ovf.py
+++ b/tests/unittests/test_datasource/test_ovf.py
@@ -138,18 +138,17 @@ class TestDatasourceOVF(CiTestCase):
self.assertIn(
'DEBUG: No system-product-name found', self.logs.getvalue())
- def test_get_data_no_vmware_customization_disabled(self):
- """When cloud-init workflow for vmware is disabled via sys_cfg and
- no meta data provided, log a message.
+ def test_get_data_vmware_customization_disabled(self):
+ """When vmware customization is disabled via sys_cfg and
+ allow_raw_data is disabled via ds_cfg, log a message.
"""
paths = Paths({'cloud_dir': self.tdir})
ds = self.datasource(
- sys_cfg={'disable_vmware_customization': True}, distro={},
- paths=paths)
+ sys_cfg={'disable_vmware_customization': True,
+ 'datasource': {'OVF': {'allow_raw_data': False}}},
+ distro={}, paths=paths)
conf_file = self.tmp_path('test-cust', self.tdir)
conf_content = dedent("""\
- [CUSTOM-SCRIPT]
- SCRIPT-NAME = test-script
[MISC]
MARKER-ID = 12345345
""")
@@ -168,7 +167,71 @@ class TestDatasourceOVF(CiTestCase):
'DEBUG: Customization for VMware platform is disabled.',
self.logs.getvalue())
- def test_get_data_vmware_customization_disabled(self):
+ def test_get_data_vmware_customization_sys_cfg_disabled(self):
+ """When vmware customization is disabled via sys_cfg and
+ no meta data is found, log a message.
+ """
+ paths = Paths({'cloud_dir': self.tdir})
+ ds = self.datasource(
+ sys_cfg={'disable_vmware_customization': True,
+ 'datasource': {'OVF': {'allow_raw_data': True}}},
+ distro={}, paths=paths)
+ conf_file = self.tmp_path('test-cust', self.tdir)
+ conf_content = dedent("""\
+ [MISC]
+ MARKER-ID = 12345345
+ """)
+ util.write_file(conf_file, conf_content)
+ retcode = wrap_and_call(
+ 'cloudinit.sources.DataSourceOVF',
+ {'dmi.read_dmi_data': 'vmware',
+ 'transport_iso9660': NOT_FOUND,
+ 'transport_vmware_guestinfo': NOT_FOUND,
+ 'util.del_dir': True,
+ 'search_file': self.tdir,
+ 'wait_for_imc_cfg_file': conf_file},
+ ds.get_data)
+ self.assertFalse(retcode, 'Expected False return from ds.get_data')
+ self.assertIn(
+ 'DEBUG: Customization using VMware config is disabled.',
+ self.logs.getvalue())
+
+ def test_get_data_allow_raw_data_disabled(self):
+ """When allow_raw_data is disabled via ds_cfg and
+ meta data is found, log a message.
+ """
+ paths = Paths({'cloud_dir': self.tdir})
+ ds = self.datasource(
+ sys_cfg={'disable_vmware_customization': False,
+ 'datasource': {'OVF': {'allow_raw_data': False}}},
+ distro={}, paths=paths)
+
+ # Prepare the conf file
+ conf_file = self.tmp_path('test-cust', self.tdir)
+ conf_content = dedent("""\
+ [CLOUDINIT]
+ METADATA = test-meta
+ """)
+ util.write_file(conf_file, conf_content)
+ # Prepare the meta data file
+ metadata_file = self.tmp_path('test-meta', self.tdir)
+ util.write_file(metadata_file, "This is meta data")
+ retcode = wrap_and_call(
+ 'cloudinit.sources.DataSourceOVF',
+ {'dmi.read_dmi_data': 'vmware',
+ 'transport_iso9660': NOT_FOUND,
+ 'transport_vmware_guestinfo': NOT_FOUND,
+ 'util.del_dir': True,
+ 'search_file': self.tdir,
+ 'wait_for_imc_cfg_file': conf_file,
+ 'collect_imc_file_paths': [self.tdir + '/test-meta', '', '']},
+ ds.get_data)
+ self.assertFalse(retcode, 'Expected False return from ds.get_data')
+ self.assertIn(
+ 'DEBUG: Customization using raw data is disabled.',
+ self.logs.getvalue())
+
+ def test_get_data_vmware_customization_enabled(self):
"""When cloud-init workflow for vmware is enabled via sys_cfg log a
message.
"""
--
cgit v1.2.3
From f0ab1e64852d50f4fe0de84e0bca0ee8bb516a9f Mon Sep 17 00:00:00 2001
From: PengpengSun <40026211+PengpengSun@users.noreply.github.com>
Date: Wed, 21 Jul 2021 00:49:37 +0800
Subject: VMware: add network-config support in ovf-env.xml (#947)
Details:
1. Support guest set network config through guestinfo.ovfEnv using OVF
2. 'network-config' Property is optional
3. 'network-config' Property's value has to be base64 encoded
Added unittests and updated ovf-env.xml example
---
cloudinit/sources/DataSourceOVF.py | 14 ++++-
doc/sources/ovf/example/ovf-env.xml | 8 +++
tests/unittests/test_datasource/test_ovf.py | 97 +++++++++++++++++++++++++++++
3 files changed, 117 insertions(+), 2 deletions(-)
(limited to 'cloudinit/sources/DataSourceOVF.py')
diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py
index 9e83dccc..e909f058 100644
--- a/cloudinit/sources/DataSourceOVF.py
+++ b/cloudinit/sources/DataSourceOVF.py
@@ -358,8 +358,11 @@ class DataSourceOVF(sources.DataSource):
if contents:
break
if contents:
- (md, ud, cfg) = read_ovf_environment(contents)
+ read_network = ('com.vmware.guestinfo' == name)
+ (md, ud, cfg) = read_ovf_environment(contents, read_network)
self.environment = contents
+ if 'network-config' in md and md['network-config']:
+ self._network_config = md['network-config']
found.append(name)
# There was no OVF transports found
@@ -507,13 +510,14 @@ def read_vmware_imc(config):
# This will return a dict with some content
# meta-data, user-data, some config
-def read_ovf_environment(contents):
+def read_ovf_environment(contents, read_network=False):
props = get_properties(contents)
md = {}
cfg = {}
ud = None
cfg_props = ['password']
md_props = ['seedfrom', 'local-hostname', 'public-keys', 'instance-id']
+ network_props = ['network-config']
for (prop, val) in props.items():
if prop == 'hostname':
prop = "local-hostname"
@@ -521,6 +525,12 @@ def read_ovf_environment(contents):
md[prop] = val
elif prop in cfg_props:
cfg[prop] = val
+ elif prop in network_props and read_network:
+ try:
+ network_config = base64.b64decode(val.encode())
+ md[prop] = safeload_yaml_or_dict(network_config).get('network')
+ except Exception:
+ LOG.debug("Ignore network-config in wrong format")
elif prop == "user-data":
try:
ud = base64.b64decode(val.encode())
diff --git a/doc/sources/ovf/example/ovf-env.xml b/doc/sources/ovf/example/ovf-env.xml
index 13e8f104..4ef4ee63 100644
--- a/doc/sources/ovf/example/ovf-env.xml
+++ b/doc/sources/ovf/example/ovf-env.xml
@@ -41,6 +41,14 @@
-->
+
+
diff --git a/tests/unittests/test_datasource/test_ovf.py b/tests/unittests/test_datasource/test_ovf.py
index e2718077..9f52b504 100644
--- a/tests/unittests/test_datasource/test_ovf.py
+++ b/tests/unittests/test_datasource/test_ovf.py
@@ -83,6 +83,103 @@ class TestReadOvfEnv(CiTestCase):
self.assertEqual({'password': "passw0rd"}, cfg)
self.assertIsNone(ud)
+ def test_with_b64_network_config_enable_read_network(self):
+ network_config = dedent("""\
+ network:
+ version: 2
+ ethernets:
+ nics:
+ nameservers:
+ addresses:
+ - 127.0.0.53
+ search:
+ - eng.vmware.com
+ - vmware.com
+ match:
+ name: eth*
+ gateway4: 10.10.10.253
+ dhcp4: false
+ addresses:
+ - 10.10.10.1/24
+ """)
+ network_config_b64 = base64.b64encode(network_config.encode()).decode()
+ props = {"network-config": network_config_b64,
+ "password": "passw0rd",
+ "instance-id": "inst-001"}
+ env = fill_properties(props)
+ md, ud, cfg = dsovf.read_ovf_environment(env, True)
+ self.assertEqual("inst-001", md["instance-id"])
+ self.assertEqual({'password': "passw0rd"}, cfg)
+ self.assertEqual(
+ {'version': 2, 'ethernets':
+ {'nics':
+ {'nameservers':
+ {'addresses': ['127.0.0.53'],
+ 'search': ['eng.vmware.com', 'vmware.com']},
+ 'match': {'name': 'eth*'},
+ 'gateway4': '10.10.10.253',
+ 'dhcp4': False,
+ 'addresses': ['10.10.10.1/24']}}},
+ md["network-config"])
+ self.assertIsNone(ud)
+
+ def test_with_non_b64_network_config_enable_read_network(self):
+ network_config = dedent("""\
+ network:
+ version: 2
+ ethernets:
+ nics:
+ nameservers:
+ addresses:
+ - 127.0.0.53
+ search:
+ - eng.vmware.com
+ - vmware.com
+ match:
+ name: eth*
+ gateway4: 10.10.10.253
+ dhcp4: false
+ addresses:
+ - 10.10.10.1/24
+ """)
+ props = {"network-config": network_config,
+ "password": "passw0rd",
+ "instance-id": "inst-001"}
+ env = fill_properties(props)
+ md, ud, cfg = dsovf.read_ovf_environment(env, True)
+ self.assertEqual({"instance-id": "inst-001"}, md)
+ self.assertEqual({'password': "passw0rd"}, cfg)
+ self.assertIsNone(ud)
+
+ def test_with_b64_network_config_disable_read_network(self):
+ network_config = dedent("""\
+ network:
+ version: 2
+ ethernets:
+ nics:
+ nameservers:
+ addresses:
+ - 127.0.0.53
+ search:
+ - eng.vmware.com
+ - vmware.com
+ match:
+ name: eth*
+ gateway4: 10.10.10.253
+ dhcp4: false
+ addresses:
+ - 10.10.10.1/24
+ """)
+ network_config_b64 = base64.b64encode(network_config.encode()).decode()
+ props = {"network-config": network_config_b64,
+ "password": "passw0rd",
+ "instance-id": "inst-001"}
+ env = fill_properties(props)
+ md, ud, cfg = dsovf.read_ovf_environment(env)
+ self.assertEqual({"instance-id": "inst-001"}, md)
+ self.assertEqual({'password': "passw0rd"}, cfg)
+ self.assertIsNone(ud)
+
class TestMarkerFiles(CiTestCase):
--
cgit v1.2.3
From 5ea2c669d6e8a9ab30f3107bee45cecc5fa1b081 Mon Sep 17 00:00:00 2001
From: PengpengSun <40026211+PengpengSun@users.noreply.github.com>
Date: Fri, 17 Sep 2021 01:43:59 +0800
Subject: VMware: Fix typo introduced in #947 and add test (#1019)
---
cloudinit/sources/DataSourceOVF.py | 2 +-
tests/unittests/test_datasource/test_ovf.py | 43 +++++++++++++++++++++++++++++
2 files changed, 44 insertions(+), 1 deletion(-)
(limited to 'cloudinit/sources/DataSourceOVF.py')
diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py
index e909f058..3e436dfa 100644
--- a/cloudinit/sources/DataSourceOVF.py
+++ b/cloudinit/sources/DataSourceOVF.py
@@ -358,7 +358,7 @@ class DataSourceOVF(sources.DataSource):
if contents:
break
if contents:
- read_network = ('com.vmware.guestinfo' == name)
+ read_network = ('com.vmware.guestInfo' == name)
(md, ud, cfg) = read_ovf_environment(contents, read_network)
self.environment = contents
if 'network-config' in md and md['network-config']:
diff --git a/tests/unittests/test_datasource/test_ovf.py b/tests/unittests/test_datasource/test_ovf.py
index 9f52b504..2ca10781 100644
--- a/tests/unittests/test_datasource/test_ovf.py
+++ b/tests/unittests/test_datasource/test_ovf.py
@@ -518,6 +518,49 @@ class TestDatasourceOVF(CiTestCase):
'vmware (%s/seed/ovf-env.xml)' % self.tdir,
ds.subplatform)
+ def test_get_data_vmware_guestinfo_with_network_config(self):
+ network_config = dedent("""\
+ network:
+ version: 2
+ ethernets:
+ nics:
+ nameservers:
+ addresses:
+ - 127.0.0.53
+ search:
+ - vmware.com
+ match:
+ name: eth*
+ gateway4: 10.10.10.253
+ dhcp4: false
+ addresses:
+ - 10.10.10.1/24
+ """)
+ network_config_b64 = base64.b64encode(network_config.encode()).decode()
+ props = {"network-config": network_config_b64,
+ "password": "passw0rd",
+ "instance-id": "inst-001"}
+ env = fill_properties(props)
+ paths = Paths({'cloud_dir': self.tdir, 'run_dir': self.tdir})
+ ds = self.datasource(sys_cfg={}, distro={}, paths=paths)
+ with mock.patch(MPATH + 'transport_vmware_guestinfo',
+ return_value=env):
+ with mock.patch(MPATH + 'transport_iso9660',
+ return_value=NOT_FOUND):
+ self.assertTrue(ds.get_data())
+ self.assertEqual('inst-001', ds.metadata['instance-id'])
+ self.assertEqual(
+ {'version': 2, 'ethernets':
+ {'nics':
+ {'nameservers':
+ {'addresses': ['127.0.0.53'],
+ 'search': ['vmware.com']},
+ 'match': {'name': 'eth*'},
+ 'gateway4': '10.10.10.253',
+ 'dhcp4': False,
+ 'addresses': ['10.10.10.1/24']}}},
+ ds.network_config)
+
def test_get_data_cloudinit_metadata_json(self):
"""Test metadata can be loaded to cloud-init metadata and network.
The metadata format is json.
--
cgit v1.2.3
From 76166caff42b82aa55c6bcd9528f2c1e3575232a Mon Sep 17 00:00:00 2001
From: xiaofengw-vmware <42736879+xiaofengw-vmware@users.noreply.github.com>
Date: Tue, 12 Oct 2021 11:54:31 +0800
Subject: VMWARE: search the deployPkg plugin in multiarch dir (#1061)
Due to multiarch, the libdeployPkgPlugin.so is deployed into dir
/usr/lib//open-vm-tools, we need to add this path
into search_paths.
LP: #1944946
---
cloudinit/sources/DataSourceOVF.py | 4 +++-
tests/unittests/test_ds_identify.py | 24 ++++++++++++++++++++++++
tools/ds-identify | 5 +++++
3 files changed, 32 insertions(+), 1 deletion(-)
(limited to 'cloudinit/sources/DataSourceOVF.py')
diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py
index 3e436dfa..08a205f1 100644
--- a/cloudinit/sources/DataSourceOVF.py
+++ b/cloudinit/sources/DataSourceOVF.py
@@ -115,7 +115,9 @@ class DataSourceOVF(sources.DataSource):
else:
search_paths = (
"/usr/lib/vmware-tools", "/usr/lib64/vmware-tools",
- "/usr/lib/open-vm-tools", "/usr/lib64/open-vm-tools")
+ "/usr/lib/open-vm-tools", "/usr/lib64/open-vm-tools",
+ "/usr/lib/x86_64-linux-gnu/open-vm-tools",
+ "/usr/lib/aarch64-linux-gnu/open-vm-tools")
plugin = "libdeployPkgPlugin.so"
deployPkgPluginPath = None
diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py
index 8617d7bd..43603ea5 100644
--- a/tests/unittests/test_ds_identify.py
+++ b/tests/unittests/test_ds_identify.py
@@ -534,6 +534,30 @@ class TestDsIdentify(DsIdentifyBase):
return self._check_via_dict(
cust64, RC_FOUND, dslist=[cust64.get('ds'), DS_NONE])
+ def test_ovf_on_vmware_iso_found_open_vm_tools_x86_64_linux_gnu(self):
+ """OVF is identified when open-vm-tools installed in
+ /usr/lib/x86_64-linux-gnu."""
+ cust64 = copy.deepcopy(VALID_CFG['OVF-vmware-customization'])
+ p32 = 'usr/lib/vmware-tools/plugins/vmsvc/libdeployPkgPlugin.so'
+ x86 = 'usr/lib/x86_64-linux-gnu/open-vm-tools/plugins/vmsvc/' \
+ 'libdeployPkgPlugin.so'
+ cust64['files'][x86] = cust64['files'][p32]
+ del cust64['files'][p32]
+ return self._check_via_dict(
+ cust64, RC_FOUND, dslist=[cust64.get('ds'), DS_NONE])
+
+ def test_ovf_on_vmware_iso_found_open_vm_tools_aarch64_linux_gnu(self):
+ """OVF is identified when open-vm-tools installed in
+ /usr/lib/aarch64-linux-gnu."""
+ cust64 = copy.deepcopy(VALID_CFG['OVF-vmware-customization'])
+ p32 = 'usr/lib/vmware-tools/plugins/vmsvc/libdeployPkgPlugin.so'
+ aarch64 = 'usr/lib/aarch64-linux-gnu/open-vm-tools/plugins/vmsvc/' \
+ 'libdeployPkgPlugin.so'
+ cust64['files'][aarch64] = cust64['files'][p32]
+ del cust64['files'][p32]
+ return self._check_via_dict(
+ cust64, RC_FOUND, dslist=[cust64.get('ds'), DS_NONE])
+
def test_ovf_on_vmware_iso_found_by_cdrom_with_matching_fs_label(self):
"""OVF is identified by well-known iso9660 labels."""
ovf_cdrom_by_label = copy.deepcopy(VALID_CFG['OVF'])
diff --git a/tools/ds-identify b/tools/ds-identify
index 63d2f0c8..c2f710e9 100755
--- a/tools/ds-identify
+++ b/tools/ds-identify
@@ -899,11 +899,16 @@ ovf_vmware_guest_customization() {
# we have to have the plugin to do vmware customization
local found="" pkg="" pre="${PATH_ROOT}/usr/lib"
+ local x86="x86_64-linux-gnu" aarch="aarch64-linux-gnu"
local ppath="plugins/vmsvc/libdeployPkgPlugin.so"
for pkg in vmware-tools open-vm-tools; do
if [ -f "$pre/$pkg/$ppath" -o -f "${pre}64/$pkg/$ppath" ]; then
found="$pkg"; break;
fi
+ # search in multiarch dir
+ if [ -f "$pre/$x86/$pkg/$ppath" -o -f "$pre/$aarch/$pkg/$ppath" ]; then
+ found="$pkg"; break;
+ fi
done
[ -n "$found" ] || return 1
# vmware customization is disabled by default
--
cgit v1.2.3
From a0a68a24c34ee268962e7a3c3844c59ab4036bf9 Mon Sep 17 00:00:00 2001
From: Thomas Weißschuh
Date: Tue, 19 Oct 2021 02:09:40 +0200
Subject: VMware: read network-config from ISO (#1066)
There is no reason for the ISO missing this functionality.
As discussed in https://github.com/canonical/cloud-init/pull/947/files#r707338489
---
cloudinit/sources/DataSourceOVF.py | 3 +--
doc/sources/ovf/example/ovf-env.xml | 2 +-
tests/unittests/test_datasource/test_ovf.py | 10 ++++++++--
tools/.github-cla-signers | 1 +
4 files changed, 11 insertions(+), 5 deletions(-)
(limited to 'cloudinit/sources/DataSourceOVF.py')
diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py
index 08a205f1..5257a534 100644
--- a/cloudinit/sources/DataSourceOVF.py
+++ b/cloudinit/sources/DataSourceOVF.py
@@ -360,8 +360,7 @@ class DataSourceOVF(sources.DataSource):
if contents:
break
if contents:
- read_network = ('com.vmware.guestInfo' == name)
- (md, ud, cfg) = read_ovf_environment(contents, read_network)
+ (md, ud, cfg) = read_ovf_environment(contents, True)
self.environment = contents
if 'network-config' in md and md['network-config']:
self._network_config = md['network-config']
diff --git a/doc/sources/ovf/example/ovf-env.xml b/doc/sources/ovf/example/ovf-env.xml
index 4ef4ee63..e5f4e262 100644
--- a/doc/sources/ovf/example/ovf-env.xml
+++ b/doc/sources/ovf/example/ovf-env.xml
@@ -42,7 +42,7 @@