From fe7adb52cda101d8849e9b3dc08470a383a058cf Mon Sep 17 00:00:00 2001 From: Julian Sy Date: Sat, 13 Feb 2016 07:01:48 -0500 Subject: [PATCH] Pkg installation to ssh_remote Added methods in InstanceInteropHelper class to help reduce duplicating code install_packages() installs a given list of packages update_repository() updates the package repository get_os_distrib() grabs the name of the OS Distro Also refactored NotImplementedException to be able to modify the exception message when passed in a message template also refactored NotImplementedException Modified Change-Id: I8381f7e6c088cb82837fdc873c78722989630b59 Closes-Bug: #1498496 --- sahara/exceptions.py | 5 +- sahara/tests/unit/test_exceptions.py | 2 + sahara/tests/unit/utils/test_ssh_remote.py | 117 ++++++++++++++++++++- sahara/utils/ssh_remote.py | 47 +++++++++ 4 files changed, 169 insertions(+), 2 deletions(-) diff --git a/sahara/exceptions.py b/sahara/exceptions.py index ed08099d..d6b916fa 100644 --- a/sahara/exceptions.py +++ b/sahara/exceptions.py @@ -214,7 +214,10 @@ class NotImplementedException(SaharaException): code = "NOT_IMPLEMENTED" message_template = _("Feature '%s' is not implemented") - def __init__(self, feature): + def __init__(self, feature, message_template=None): + if message_template: + self.message_template = message_template + formatted_message = self.message_template % feature super(NotImplementedException, self).__init__(formatted_message) diff --git a/sahara/tests/unit/test_exceptions.py b/sahara/tests/unit/test_exceptions.py index 9e2bfdf3..6629baad 100644 --- a/sahara/tests/unit/test_exceptions.py +++ b/sahara/tests/unit/test_exceptions.py @@ -139,6 +139,8 @@ class TestExceptions(base.SaharaTestCase): self._validate_exc( exc.NotImplementedException, "Feature 'bond' is not implemented", "bond") + self._validate_exc( + exc.NotImplementedException, "feature", "feature", "%s") def test_incorrect_state(self): self._validate_exc(exc.IncorrectStateError, "message", "message") diff --git a/sahara/tests/unit/utils/test_ssh_remote.py b/sahara/tests/unit/utils/test_ssh_remote.py index 2d9a3821..a26ee23e 100644 --- a/sahara/tests/unit/utils/test_ssh_remote.py +++ b/sahara/tests/unit/utils/test_ssh_remote.py @@ -29,6 +29,97 @@ class TestEscapeQuotes(testtools.TestCase): self.assertEqual(r'echo \"\\\"Hello, world!\\\"\"', s) +class TestGetOsDistrib(testtools.TestCase): + @mock.patch('sahara.utils.ssh_remote._execute_command', + return_value=[1, 'Ubuntu']) + def test_get_os_distrib(self, p_execute_command): + d = ssh_remote._get_os_distrib() + p_execute_command.assert_called_once_with( + ('printf "import platform\nprint(platform.linux_distribution(' + 'full_distribution_name=0)[0])" | python'), + run_as_root=False) + self.assertEqual('ubuntu', d) + + +class TestInstallPackages(testtools.TestCase): + @mock.patch('sahara.utils.ssh_remote._get_os_distrib') + @mock.patch('sahara.utils.ssh_remote._execute_command') + def test_install_packages(self, p_execute_command, p_get_os_distrib): + packages = ('git', 'emacs', 'tree') + + # test ubuntu + p_get_os_distrib.return_value = 'ubuntu' + ssh_remote._install_packages(packages) + p_execute_command.assert_called_with( + 'RUNLEVEL=1 apt-get install -y git emacs tree', run_as_root=True) + + # test centos + p_get_os_distrib.return_value = 'centos' + ssh_remote._install_packages(packages) + p_execute_command.assert_called_with( + 'yum install -y git emacs tree', + run_as_root=True) + + # test fedora + p_get_os_distrib.return_value = 'fedora' + ssh_remote._install_packages(packages) + p_execute_command.assert_called_with( + 'yum install -y git emacs tree', + run_as_root=True) + + # test redhat + p_get_os_distrib.return_value = 'redhat' + ssh_remote._install_packages(packages) + p_execute_command.assert_called_with( + 'yum install -y git emacs tree', + run_as_root=True) + + @mock.patch('sahara.utils.ssh_remote._get_os_distrib', + return_value='windows me') + def test_install_packages_bad(self, p_get_os_distrib): + with testtools.ExpectedException( + ex.NotImplementedException, + 'Package Installation is not implemented for OS windows me.*'): + ssh_remote._install_packages(('git', 'emacs', 'tree')) + + +class TestUpdateRepository(testtools.TestCase): + @mock.patch('sahara.utils.ssh_remote._get_os_distrib') + @mock.patch('sahara.utils.ssh_remote._execute_command') + def test_update_repository(self, p_execute_command, p_get_os_distrib): + # test ubuntu + p_get_os_distrib.return_value = 'ubuntu' + ssh_remote._update_repository() + p_execute_command.assert_called_with( + 'apt-get update', run_as_root=True) + + # test centos + p_get_os_distrib.return_value = 'centos' + ssh_remote._update_repository() + p_execute_command.assert_called_with( + 'yum clean all', run_as_root=True) + + # test fedora + p_get_os_distrib.return_value = 'fedora' + ssh_remote._update_repository() + p_execute_command.assert_called_with( + 'yum clean all', run_as_root=True) + + # test redhat + p_get_os_distrib.return_value = 'redhat' + ssh_remote._update_repository() + p_execute_command.assert_called_with( + 'yum clean all', run_as_root=True) + + @mock.patch('sahara.utils.ssh_remote._get_os_distrib', + return_value='windows me') + def test_update_repository_bad(self, p_get_os_distrib): + with testtools.ExpectedException( + ex.NotImplementedException, + 'Repository Update is not implemented for OS windows me.*'): + ssh_remote._update_repository() + + class FakeCluster(object): def __init__(self, priv_key): self.management_private_key = priv_key @@ -72,7 +163,6 @@ class TestInstanceInteropHelper(base.SaharaTestCase): 'sahara.utils.openstack.neutron.NeutronClient.get_router', return_value='fakerouter') p_neutron_router.start() - # During tests subprocesses are not used (because _sahara-subprocess # is not installed in /bin and Mock objects cannot be pickled). p_start_subp = mock.patch('sahara.utils.procutils.start_subprocess', @@ -180,3 +270,28 @@ class TestInstanceInteropHelper(base.SaharaTestCase): self.assertRaises(ex.SystemError, remote.execute_command, '/bin/true') # Test HTTP self.assertRaises(ex.SystemError, remote.get_http_client, 8080) + + @mock.patch('sahara.utils.ssh_remote.InstanceInteropHelper._run_s') + def test_get_os_distrib(self, p_run_s): + instance = FakeInstance('inst4', '123', '10.0.0.4', 'user4', 'key4') + remote = ssh_remote.InstanceInteropHelper(instance) + + remote.get_os_distrib() + p_run_s.assert_called_with(ssh_remote._get_os_distrib, None) + + @mock.patch('sahara.utils.ssh_remote.InstanceInteropHelper._run_s') + def test_install_packages(self, p_run_s): + instance = FakeInstance('inst5', '123', '10.0.0.5', 'user5', 'key5') + remote = ssh_remote.InstanceInteropHelper(instance) + + remote.install_packages(['pkg1', 'pkg2']) + p_run_s.assert_called_once_with( + ssh_remote._install_packages, None, ['pkg1', 'pkg2']) + + @mock.patch('sahara.utils.ssh_remote.InstanceInteropHelper._run_s') + def test_update_repository(self, p_run_s): + instance = FakeInstance('inst6', '123', '10.0.0.6', 'user6', 'key6') + remote = ssh_remote.InstanceInteropHelper(instance) + + remote.update_repository() + p_run_s.assert_called_once_with(ssh_remote._update_repository, None) diff --git a/sahara/utils/ssh_remote.py b/sahara/utils/ssh_remote.py index 0bdbdbe9..9de047a2 100644 --- a/sahara/utils/ssh_remote.py +++ b/sahara/utils/ssh_remote.py @@ -352,6 +352,42 @@ def _read_file_from(remote_file, run_as_root=False): 'rm %s' % fl, run_as_root=True, raise_when_error=False) +def _get_os_distrib(): + return _execute_command( + ('printf "import platform\nprint(platform.linux_distribution(' + 'full_distribution_name=0)[0])" | python'), + run_as_root=False)[1].lower() + + +def _install_packages(packages): + distrib = _get_os_distrib() + if distrib == 'ubuntu': + cmd = 'RUNLEVEL=1 apt-get install -y %(pkgs)s' + elif distrib in ('redhat', 'centos', 'fedora'): + cmd = 'yum install -y %(pkgs)s' + else: + raise ex.NotImplementedException( + _('Package Installation'), + _('%(fmt)s is not implemented for OS %(distrib)s') % { + 'fmt': '%s', 'distrib': distrib}) + cmd = cmd % {'pkgs': ' '.join(packages)} + _execute_command(cmd, run_as_root=True) + + +def _update_repository(): + distrib = _get_os_distrib() + if distrib == 'ubuntu': + cmd = 'apt-get update' + elif distrib in ('redhat', 'centos', 'fedora'): + cmd = 'yum clean all' + else: + raise ex.NotImplementedException( + _('Repository Update'), + _('%(fmt)s is not implemented for OS %(distrib)s') % { + 'fmt': '%s', 'distrib': distrib}) + _execute_command(cmd, run_as_root=True) + + def _replace_remote_string(remote_file, old_str, new_str): old_str = old_str.replace("\'", "\''") new_str = new_str.replace("\'", "\''") @@ -766,6 +802,17 @@ class InstanceInteropHelper(remote.Remote): self._log_command('Reading file "%s"' % remote_file) return self._run_s(_read_file_from, timeout, remote_file, run_as_root) + def get_os_distrib(self, timeout=None): + return self._run_s(_get_os_distrib, timeout) + + def install_packages(self, packages, timeout=None): + self._log_command('Installing packages "%s"' % list(packages)) + self._run_s(_install_packages, timeout, packages) + + def update_repository(self, timeout=None): + self._log_command('Updating repository') + self._run_s(_update_repository, timeout) + def replace_remote_string(self, remote_file, old_str, new_str, timeout=None): self._log_command('In file "%s" replacing string "%s" '