Pull out JSON string from stdout

When there is a custom message in `.bashrc` on certain fedora based
distros, the string will be included in the stdout. This will pull out
the following JSON string, if present, and attempt to parse that.

Change-Id: I7d0d4e9b36924664d158c62baf8cdef163bd1d85
Closes-Bug: #1294851
This commit is contained in:
BK Box 2014-03-19 15:42:01 -05:00
parent 6441192a98
commit 0258742b74
3 changed files with 56 additions and 6 deletions

View File

@ -61,6 +61,11 @@ class SystemInfoNotJson(DiscoveryException):
"""Command did not produce valid JSON."""
class SystemInfoMissingJson(DiscoveryException):
"""Command did not produce stdout containing JSON."""
class SystemInfoCommandInstallFailed(DiscoveryException):
"""Failed to install package that provides system information."""

View File

@ -47,10 +47,12 @@ def system_info(ssh_client):
:param ssh_client: :class:`ssh.SSH` instance
:returns: dict -- system information from ohai-solo
:raises: SystemInfoCommandMissing, SystemInfoCommandOld, SystemInfoNotJson
SystemInfoMissingJson
SystemInfoCommandMissing if `ohai` is not installed.
SystemInfoCommandOld if `ohai` is not the latest.
SystemInfoNotJson if `ohai` does not return valid json.
SystemInfoNotJson if `ohai` does not return valid JSON.
SystemInfoMissingJson if `ohai` does not return any JSON.
"""
output = ssh_client.remote_execute("sudo -i ohai-solo")
not_found_msgs = ["command not found", "Could not find ohai"]
@ -59,10 +61,15 @@ def system_info(ssh_client):
LOG.warning("SystemInfoCommandMissing on host: [%s]", ssh_client.host)
raise errors.SystemInfoCommandMissing("ohai-solo missing on %s",
ssh_client.host)
unicode_output = unicode(output['stdout'], errors='replace')
try:
results = json.loads(unicode(output['stdout'], errors='replace'))
results = json.loads(unicode_output)
except ValueError as exc:
raise errors.SystemInfoNotJson(exc)
try:
clean_output = get_json(unicode_output)
results = json.loads(clean_output)
except ValueError as exc:
raise errors.SystemInfoNotJson(exc)
return results
@ -119,3 +126,21 @@ def remove_remote(ssh_client):
command = "cd /tmp && %s" % remove
output = ssh_client.remote_execute(command)
return output
def get_json(data):
"""Find the JSON string in data and return a string.
:param data: :string:
:returns: string -- JSON string striped of non-JSON data
:raises: SystemInfoMissingJson
SystemInfoMissingJson if `ohai` does not return any JSON.
"""
try:
first = data.index('{')
last = data.rindex('}')
return data[first:last + 1]
except ValueError as e:
context = {"ValueError": "%s" % e}
raise errors.SystemInfoMissingJson(context)

View File

@ -111,19 +111,39 @@ class TestSystemInfo(utils.TestCase):
'stdout': "{}",
'stderr': ""
}
result = ohai_solo.system_info(mock_ssh)
mock_ssh.remote_execute("sudo -i ohai-solo")
ohai_solo.system_info(mock_ssh)
mock_ssh.remote_execute.assert_called_with("sudo -i ohai-solo")
def test_system_info_with_motd(self):
mock_ssh = mock.MagicMock()
mock_ssh.remote_execute.return_value = {
'exit_code': 0,
'stdout': "Hello world\n {}",
'stderr': ""
}
ohai_solo.system_info(mock_ssh)
mock_ssh.remote_execute.assert_called_with("sudo -i ohai-solo")
def test_system_info_bad_json(self):
mock_ssh = mock.MagicMock()
mock_ssh.remote_execute.return_value = {
'exit_code': 0,
'stdout': "",
'stdout': "{Not JSON!}",
'stderr': ""
}
self.assertRaises(errors.SystemInfoNotJson, ohai_solo.system_info,
mock_ssh)
def test_system_info_missing_json(self):
mock_ssh = mock.MagicMock()
mock_ssh.remote_execute.return_value = {
'exit_code': 0,
'stdout': "No JSON!",
'stderr': ""
}
self.assertRaises(errors.SystemInfoMissingJson, ohai_solo.system_info,
mock_ssh)
def test_system_info_command_not_found(self):
mock_ssh = mock.MagicMock()
mock_ssh.remote_execute.return_value = {