Added code to set the install directory for ohai-solo

Added options to the ohai_solo install, remove and execute methods to
allow installation of ohai-solo to somewhere other than /opt. This is
required because it lets us get around some change control policies.

Change-Id: I72d051f78c5316e6077891978c65a60ece1dd4de
This commit is contained in:
Cian Brennan 2015-04-28 15:09:47 +01:00
parent c5c9a9d88e
commit a21e120146
4 changed files with 131 additions and 30 deletions

View File

@ -4,5 +4,5 @@ paramiko>=1.13.0 # py33 support
pbr>=0.5.21,<1.0
python-novaclient>=2.15.0 # py33 support
pythonwhois>=2.1.0 # py33 support
six>=1.4.0
six>=1.8.0
tldextract>=1.2

View File

@ -6,6 +6,6 @@ paramiko>=1.12.0 # ecdsa added
pbr>=0.5.21,<1.0
python-novaclient>=2.6.0.1 # breaks before
pythonwhois>=2.4.3
six>=1.4.0 # urllib introduced
six>=1.8.0 # six.moves.shlex introduced
tldextract>=1.2
argparse

View File

@ -51,10 +51,12 @@ def get_systeminfo(ipaddress, config, interactive=False):
return system_info(client)
def system_info(client, with_install=False):
def system_info(client, with_install=False, install_dir=None):
"""Run ohai-solo on a remote system and gather the output.
:param client: :class:`ssh.SSH` instance
:param with_install Will install ohai-solo if set to True
:param install_dir string containing directory to install to
:returns: dict -- system information from ohai-solo
:raises: SystemInfoCommandMissing, SystemInfoCommandOld, SystemInfoNotJson
SystemInfoMissingJson
@ -65,37 +67,46 @@ def system_info(client, with_install=False):
SystemInfoMissingJson if `ohai` does not return any JSON.
"""
if with_install:
perform_install(client)
perform_install(client, install_dir=install_dir)
if client.is_windows():
raise errors.UnsupportedPlatform(
"ohai-solo is a linux-only sytem info provider. "
"Target platform was %s", client.platform_info['dist'])
else:
command = "unset GEM_CACHE GEM_HOME GEM_PATH && sudo ohai-solo"
output = client.execute(command, escalate=True, allow_many=False)
not_found_msgs = ["command not found", "Could not find ohai"]
if any(m in k for m in not_found_msgs
for k in list(output.values()) if isinstance(k,
six.string_types)):
LOG.warning("SystemInfoCommandMissing on host: [%s]", client.host)
raise errors.SystemInfoCommandMissing("ohai-solo missing on %s" %
client.host)
# use string formatting to handle unicode
unicode_output = "%s" % output['stdout']
ohai_solo_prefix = (install_dir or '/opt')
ohai_solo_command = six.moves.shlex_quote("%s/ohai-solo/bin/ohai-solo"
% ohai_solo_prefix)
command = ("unset GEM_CACHE GEM_HOME GEM_PATH && "
"sudo %s" % ohai_solo_command)
output = client.execute(command, escalate=True, allow_many=False)
not_found_msgs = ["command not found", "Could not find ohai"]
if any(m in k for m in not_found_msgs
for k in list(output.values()) if isinstance(k,
six.string_types)):
LOG.warning("SystemInfoCommandMissing on host: [%s]", client.host)
raise errors.SystemInfoCommandMissing("ohai-solo missing on %s" %
client.host)
# use string formatting to handle unicode
unicode_output = "%s" % output['stdout']
try:
results = json.loads(unicode_output)
except ValueError as exc:
try:
results = json.loads(unicode_output)
clean_output = get_json(unicode_output)
results = json.loads(clean_output)
except ValueError as exc:
try:
clean_output = get_json(unicode_output)
results = json.loads(clean_output)
except ValueError as exc:
raise errors.SystemInfoNotJson(exc)
return results
raise errors.SystemInfoNotJson(exc)
return results
def perform_install(client):
"""Install ohai-solo on remote system."""
def perform_install(client, install_dir=None):
"""Install ohai-solo on remote system.
:param client: :class:`ssh.SSH` instance
:param install_dir string containing directory to install to
"""
LOG.info("Installing (or updating) ohai-solo on device %s at %s:%d",
client.host, client.host, client.port)
@ -119,6 +130,10 @@ def perform_install(client):
# Run install
command = "bash install.sh"
if install_dir:
command = "%s -t -i %s" % (command,
six.moves.shlex_quote(install_dir))
install_output = client.execute(command, cwd='/tmp',
with_exit_code=True,
escalate=True, allow_many=False)
@ -137,9 +152,10 @@ def perform_install(client):
return install_output
def remove_remote(client):
def remove_remote(client, install_dir=None):
"""Remove ohai-solo from specifc remote system.
:param install_dir string containing directory ohai-solo was installed in
Currently supports:
- ubuntu [10.x, 12.x]
- debian [6.x, 7.x]
@ -152,7 +168,10 @@ def remove_remote(client):
"Target platform was %s", client.platform_info['dist'])
else:
platform_info = client.platform_info
if client.is_debian():
if install_dir is not None:
install_dir = six.moves.shlex_quote("%s/ohai-solo/" % install_dir)
remove = 'rm -rf %s' % install_dir
elif client.is_debian():
remove = "dpkg --purge ohai-solo"
elif client.is_fedora():
remove = "yum -y erase ohai-solo"

View File

@ -68,6 +68,39 @@ class TestOhaiInstall(utils.TestCase):
mock.call('rm install.sh', cwd='/tmp', escalate=True,
allow_many=False)])
def test_perform_install_with_install_dir(self):
response = {'exit_code': 0, 'stdout': 'installed remote'}
self.mock_remotesshclient.execute.return_value = response
result = ohai_solo.perform_install(self.mock_remotesshclient,
install_dir='/home/bob')
self.assertEqual(result, response)
self.assertEqual(self.mock_remotesshclient.execute.call_count, 3)
self.mock_remotesshclient.execute.assert_has_calls([
mock.call('wget -N http://readonly.configdiscovery.'
'rackspace.com/install.sh', cwd='/tmp',
escalate=True, allow_many=False),
mock.call('bash install.sh -t -i /home/bob', cwd='/tmp',
with_exit_code=True, escalate=True, allow_many=False),
mock.call('rm install.sh', cwd='/tmp', escalate=True,
allow_many=False)])
def test_perform_install_with_install_dir_and_spaces(self):
response = {'exit_code': 0, 'stdout': 'installed remote'}
self.mock_remotesshclient.execute.return_value = response
result = ohai_solo.perform_install(self.mock_remotesshclient,
install_dir='/srv/a diff * dir')
self.assertEqual(result, response)
self.assertEqual(self.mock_remotesshclient.execute.call_count, 3)
self.mock_remotesshclient.execute.assert_has_calls([
mock.call('wget -N http://readonly.configdiscovery.'
'rackspace.com/install.sh', cwd='/tmp',
escalate=True, allow_many=False),
mock.call('bash install.sh -t -i \'/srv/a diff * dir\'',
cwd='/tmp', with_exit_code=True, escalate=True,
allow_many=False),
mock.call('rm install.sh', cwd='/tmp', escalate=True,
allow_many=False)])
def test_install_linux_remote_failed(self):
response = {'exit_code': 1, 'stdout': "", "stderr": "FAIL"}
self.mock_remotesshclient.execute.return_value = response
@ -108,6 +141,28 @@ class TestOhaiRemove(utils.TestCase):
self.assertRaises(errors.UnsupportedPlatform,
ohai_solo.remove_remote, self.mock_remotesshclient)
def test_remove_remote_with_install_dir(self):
self.mock_remotesshclient.is_debian.return_value = True
self.mock_remotesshclient.is_fedora.return_value = False
response = {'exit_code': 0, 'foo': 'bar'}
self.mock_remotesshclient.execute.return_value = response
result = ohai_solo.remove_remote(self.mock_remotesshclient,
install_dir='/home/srv')
self.assertEqual(result, response)
self.mock_remotesshclient.execute.assert_called_once_with(
'rm -rf /home/srv/ohai-solo/', cwd='/tmp', escalate=True)
def test_remove_remote_with_install_dir_and_spaces(self):
self.mock_remotesshclient.is_debian.return_value = True
self.mock_remotesshclient.is_fedora.return_value = False
response = {'exit_code': 0, 'foo': 'bar'}
self.mock_remotesshclient.execute.return_value = response
result = ohai_solo.remove_remote(self.mock_remotesshclient,
install_dir='/srv/a dir')
self.assertEqual(result, response)
self.mock_remotesshclient.execute.assert_called_once_with(
'rm -rf \'/srv/a dir/ohai-solo/\'', cwd='/tmp', escalate=True)
class TestSystemInfo(utils.TestCase):
@ -124,7 +179,34 @@ class TestSystemInfo(utils.TestCase):
}
ohai_solo.system_info(self.mock_remotesshclient)
self.mock_remotesshclient.execute.assert_called_with(
"unset GEM_CACHE GEM_HOME GEM_PATH && sudo ohai-solo",
"unset GEM_CACHE GEM_HOME GEM_PATH && "
"sudo /opt/ohai-solo/bin/ohai-solo",
escalate=True, allow_many=False)
def test_system_info_with_install_dir(self):
self.mock_remotesshclient.execute.return_value = {
'exit_code': 0,
'stdout': "{}",
'stderr': ""
}
ohai_solo.system_info(self.mock_remotesshclient,
install_dir='/home/user')
self.mock_remotesshclient.execute.assert_called_with(
"unset GEM_CACHE GEM_HOME GEM_PATH && "
"sudo /home/user/ohai-solo/bin/ohai-solo",
escalate=True, allow_many=False)
def test_system_info_with_install_dir_with_spaces(self):
self.mock_remotesshclient.execute.return_value = {
'exit_code': 0,
'stdout': "{}",
'stderr': ""
}
ohai_solo.system_info(self.mock_remotesshclient,
install_dir='/sys/omg * " lol/')
self.mock_remotesshclient.execute.assert_called_with(
"unset GEM_CACHE GEM_HOME GEM_PATH && "
'sudo \'/sys/omg * " lol//ohai-solo/bin/ohai-solo\'',
escalate=True, allow_many=False)
def test_system_info_with_motd(self):
@ -135,7 +217,8 @@ class TestSystemInfo(utils.TestCase):
}
ohai_solo.system_info(self.mock_remotesshclient)
self.mock_remotesshclient.execute.assert_called_with(
"unset GEM_CACHE GEM_HOME GEM_PATH && sudo ohai-solo",
"unset GEM_CACHE GEM_HOME GEM_PATH && "
"sudo /opt/ohai-solo/bin/ohai-solo",
escalate=True, allow_many=False)
def test_system_info_bad_json(self):
@ -174,6 +257,5 @@ class TestSystemInfo(utils.TestCase):
self.assertRaises(errors.SystemInfoCommandMissing,
ohai_solo.system_info, self.mock_remotesshclient)
if __name__ == "__main__":
unittest.main()