Skip to content

Commit

Permalink
vmware: Fall back to vmtoolsd if vmware-rpctool errs
Browse files Browse the repository at this point in the history
This patch udpates the ds-identify script and the VMware datasource
to fall back to using the vmtoolsd program if vmware-rpctool errors.
  • Loading branch information
akutz committed Sep 18, 2023
1 parent e9cdd7e commit 56b995c
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 70 deletions.
80 changes: 57 additions & 23 deletions cloudinit/sources/DataSourceVMware.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
DATA_ACCESS_METHOD_GUESTINFO = "guestinfo"
DATA_ACCESS_METHOD_IMC = "imc"

VMTOOLSD = which("vmtoolsd")
VMWARE_RPCTOOL = which("vmware-rpctool")
REDACT = "redact"
CLEANUP_GUESTINFO = "cleanup-guestinfo"
Expand Down Expand Up @@ -237,7 +238,11 @@ def setup(self, is_new_instance):

# Reflect any possible local IPv4 or IPv6 addresses in the guest
# info.
advertise_local_ip_addrs(host_info)
try:
advertise_local_ip_addrs(host_info, self.vmware_rpctool)
except ProcessExecutionError:
self.vmware_rpctool = VMTOOLSD
advertise_local_ip_addrs(host_info, self.vmware_rpctool)

# Ensure the metadata gets updated with information about the
# host, including the network interfaces, default IP addresses,
Expand Down Expand Up @@ -313,7 +318,11 @@ def redact_keys(self):
keys_to_redact = self.metadata[CLEANUP_GUESTINFO]

if self.data_access_method == DATA_ACCESS_METHOD_GUESTINFO:
guestinfo_redact_keys(keys_to_redact, self.vmware_rpctool)
try:
guestinfo_redact_keys(keys_to_redact, self.vmware_rpctool)
except ProcessExecutionError:
self.vmware_rpctool = VMTOOLSD
guestinfo_redact_keys(keys_to_redact, self.vmware_rpctool)

def get_envvar_data_fn(self):
"""
Expand All @@ -333,9 +342,15 @@ def get_guestinfo_data_fn(self):
"""
md, ud, vd = None, None, None
if self.vmware_rpctool:
md = guestinfo("metadata", self.vmware_rpctool)
ud = guestinfo("userdata", self.vmware_rpctool)
vd = guestinfo("vendordata", self.vmware_rpctool)
try:
md = guestinfo("metadata", self.vmware_rpctool)
ud = guestinfo("userdata", self.vmware_rpctool)
vd = guestinfo("vendordata", self.vmware_rpctool)
except ProcessExecutionError:
self.vmware_rpctool = VMTOOLSD
md = guestinfo("metadata", self.vmware_rpctool)
ud = guestinfo("userdata", self.vmware_rpctool)
vd = guestinfo("vendordata", self.vmware_rpctool)

return (md, ud, vd)

Expand Down Expand Up @@ -447,7 +462,7 @@ def get_none_if_empty_val(val):
return val


def advertise_local_ip_addrs(host_info):
def advertise_local_ip_addrs(host_info, vmware_rpctool=VMWARE_RPCTOOL):
"""
advertise_local_ip_addrs gets the local IP address information from
the provided host_info map and sets the addresses in the guestinfo
Expand All @@ -460,12 +475,12 @@ def advertise_local_ip_addrs(host_info):
# info.
local_ipv4 = host_info.get(LOCAL_IPV4)
if local_ipv4:
guestinfo_set_value(LOCAL_IPV4, local_ipv4)
guestinfo_set_value(LOCAL_IPV4, local_ipv4, vmware_rpctool)
LOG.info("advertised local ipv4 address %s in guestinfo", local_ipv4)

local_ipv6 = host_info.get(LOCAL_IPV6)
if local_ipv6:
guestinfo_set_value(LOCAL_IPV6, local_ipv6)
guestinfo_set_value(LOCAL_IPV6, local_ipv6, vmware_rpctool)
LOG.info("advertised local ipv6 address %s in guestinfo", local_ipv6)


Expand Down Expand Up @@ -523,30 +538,39 @@ def guestinfo_get_value(key, vmware_rpctool=VMWARE_RPCTOOL):
"""
Returns a guestinfo value for the specified key.
"""
LOG.debug("Getting guestinfo value for key %s", key)
LOG.debug(
"Getting guestinfo value for key %s with %s", key, vmware_rpctool
)

args = [vmware_rpctool]
if vmware_rpctool == VMTOOLSD:
args.append("--cmd")
args.append("info-get " + get_guestinfo_key_name(key))

try:
(stdout, stderr) = subp(
[
vmware_rpctool,
"info-get " + get_guestinfo_key_name(key),
]
)
(stdout, stderr) = subp(args)
if stderr == NOVAL:
LOG.debug("No value found for key %s", key)
elif not stdout:
if not stdout:
LOG.error("Failed to get guestinfo value for key %s", key)
return handle_returned_guestinfo_val(key, stdout)
except ProcessExecutionError as error:
# No matter the tool used to access the data, if NOVAL was returned on
# stderr, do not raise an exception.
if error.stderr == NOVAL:
LOG.debug("No value found for key %s", key)
else:
# Any other result gets logged as an error, and if the tool was
# VMWARE_RPCTOOL, then raise the exception so the caller can try
# again with VMTOOLSD.
util.logexc(
LOG,
"Failed to get guestinfo value for key %s: %s",
key,
error,
)
if vmware_rpctool == VMWARE_RPCTOOL:
raise error
except Exception:
util.logexc(
LOG,
Expand All @@ -571,24 +595,34 @@ def guestinfo_set_value(key, value, vmware_rpctool=VMWARE_RPCTOOL):
if value == "":
value = " "

LOG.debug("Setting guestinfo key=%s to value=%s", key, value)
LOG.debug(
"Setting guestinfo key=%s to value=%s with %s",
key,
value,
vmware_rpctool,
)

args = [vmware_rpctool]
if vmware_rpctool == VMTOOLSD:
args.append("--cmd")
args.append("info-set %s %s" % (get_guestinfo_key_name(key), value))

try:
subp(
[
vmware_rpctool,
"info-set %s %s" % (get_guestinfo_key_name(key), value),
]
)
subp(args)
return True
except ProcessExecutionError as error:
# Any error result gets logged as an error, and if the tool was
# VMWARE_RPCTOOL, then raise the exception so the caller can try
# again with VMTOOLSD.
util.logexc(
LOG,
"Failed to set guestinfo key=%s to value=%s: %s",
key,
value,
error,
)
if vmware_rpctool == VMWARE_RPCTOOL:
raise error
except Exception:
util.logexc(
LOG,
Expand Down
93 changes: 74 additions & 19 deletions tests/unittests/test_ds_identify.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,8 @@ def test_vmware_envvar_activated_by_vendordata(self):

def test_vmware_guestinfo_no_data(self):
"""VMware: guestinfo transport no data"""
self._test_ds_not_found("VMware-GuestInfo-NoData")
self._test_ds_not_found("VMware-GuestInfo-NoData-Rpctool")
self._test_ds_not_found("VMware-GuestInfo-NoData-Vmtoolsd")

def test_vmware_guestinfo_no_virt_id(self):
"""VMware: guestinfo transport fails if no virt id"""
Expand Down Expand Up @@ -1800,6 +1801,11 @@ def _print_run_output(rc, out, err, cfg, files):
"ret": 0,
"out": "/usr/bin/vmware-rpctool",
},
{
"name": "vmware_has_vmtoolsd",
"ret": 1,
"out": "/usr/bin/vmtoolsd",
},
],
"files": {
# Setup vmware customization enabled
Expand Down Expand Up @@ -1917,7 +1923,7 @@ def _print_run_output(rc, out, err, cfg, files):
MOCK_VIRT_IS_VMWARE,
],
},
"VMware-GuestInfo-NoData": {
"VMware-GuestInfo-NoData-Rpctool": {
"ds": "VMware",
"policy_dmi": POLICY_FOUND_ONLY,
"mocks": [
Expand All @@ -1927,15 +1933,49 @@ def _print_run_output(rc, out, err, cfg, files):
"out": "/usr/bin/vmware-rpctool",
},
{
"name": "vmware_rpctool_guestinfo_metadata",
"name": "vmware_has_vmtoolsd",
"ret": 1,
"out": "/usr/bin/vmtoolsd",
},
{
"name": "vmware_guestinfo_metadata",
"ret": 1,
},
{
"name": "vmware_guestinfo_userdata",
"ret": 1,
},
{
"name": "vmware_guestinfo_vendordata",
"ret": 1,
},
MOCK_VIRT_IS_VMWARE,
],
},
"VMware-GuestInfo-NoData-Vmtoolsd": {
"ds": "VMware",
"policy_dmi": POLICY_FOUND_ONLY,
"mocks": [
{
"name": "vmware_has_rpctool",
"ret": 1,
"out": "/usr/bin/vmware-rpctool",
},
{
"name": "vmware_has_vmtoolsd",
"ret": 0,
"out": "/usr/bin/vmtoolsd",
},
{
"name": "vmware_guestinfo_metadata",
"ret": 1,
},
{
"name": "vmware_rpctool_guestinfo_userdata",
"name": "vmware_guestinfo_userdata",
"ret": 1,
},
{
"name": "vmware_rpctool_guestinfo_vendordata",
"name": "vmware_guestinfo_vendordata",
"ret": 1,
},
MOCK_VIRT_IS_VMWARE,
Expand All @@ -1950,16 +1990,16 @@ def _print_run_output(rc, out, err, cfg, files):
"out": "/usr/bin/vmware-rpctool",
},
{
"name": "vmware_rpctool_guestinfo_metadata",
"name": "vmware_guestinfo_metadata",
"ret": 0,
"out": "---",
},
{
"name": "vmware_rpctool_guestinfo_userdata",
"name": "vmware_guestinfo_userdata",
"ret": 1,
},
{
"name": "vmware_rpctool_guestinfo_vendordata",
"name": "vmware_guestinfo_vendordata",
"ret": 1,
},
],
Expand All @@ -1969,20 +2009,25 @@ def _print_run_output(rc, out, err, cfg, files):
"mocks": [
{
"name": "vmware_has_rpctool",
"ret": 0,
"ret": 1,
"out": "/usr/bin/vmware-rpctool",
},
{
"name": "vmware_rpctool_guestinfo_metadata",
"name": "vmware_has_vmtoolsd",
"ret": 0,
"out": "/usr/bin/vmtoolsd",
},
{
"name": "vmware_guestinfo_metadata",
"ret": 0,
"out": "---",
},
{
"name": "vmware_rpctool_guestinfo_userdata",
"name": "vmware_guestinfo_userdata",
"ret": 1,
},
{
"name": "vmware_rpctool_guestinfo_vendordata",
"name": "vmware_guestinfo_vendordata",
"ret": 1,
},
MOCK_VIRT_IS_VMWARE,
Expand All @@ -1997,16 +2042,21 @@ def _print_run_output(rc, out, err, cfg, files):
"out": "/usr/bin/vmware-rpctool",
},
{
"name": "vmware_rpctool_guestinfo_metadata",
"name": "vmware_has_vmtoolsd",
"ret": 1,
"out": "/usr/bin/vmtoolsd",
},
{
"name": "vmware_guestinfo_metadata",
"ret": 1,
},
{
"name": "vmware_rpctool_guestinfo_userdata",
"name": "vmware_guestinfo_userdata",
"ret": 0,
"out": "---",
},
{
"name": "vmware_rpctool_guestinfo_vendordata",
"name": "vmware_guestinfo_vendordata",
"ret": 1,
},
MOCK_VIRT_IS_VMWARE,
Expand All @@ -2017,19 +2067,24 @@ def _print_run_output(rc, out, err, cfg, files):
"mocks": [
{
"name": "vmware_has_rpctool",
"ret": 0,
"ret": 1,
"out": "/usr/bin/vmware-rpctool",
},
{
"name": "vmware_rpctool_guestinfo_metadata",
"name": "vmware_has_vmtoolsd",
"ret": 0,
"out": "/usr/bin/vmtoolsd",
},
{
"name": "vmware_guestinfo_metadata",
"ret": 1,
},
{
"name": "vmware_rpctool_guestinfo_userdata",
"name": "vmware_guestinfo_userdata",
"ret": 1,
},
{
"name": "vmware_rpctool_guestinfo_vendordata",
"name": "vmware_guestinfo_vendordata",
"ret": 0,
"out": "---",
},
Expand Down
Loading

0 comments on commit 56b995c

Please sign in to comment.