diff --git a/docs/source/index.rst b/docs/source/index.rst index 76b1b4d3..d7fec078 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -31,8 +31,8 @@ About ----- With **img-proof** you can now test custom images in a cloud framework agnostic way -with one tool and one API. In the first release, **img-proof** supports the -openSUSE and SLES distributions. It also supports the three largest +with one tool and one API. **img-proof** supports the RHEL, Fedora, +openSUSE, and SLES distributions. It also supports the three largest cloud frameworks (AWS, Azure and GCE). However, it is intended to be distribution agnostic and framework transparent so both are easily extensible. @@ -80,6 +80,8 @@ includes tests such as soft reboot (e.g. "shutdown -r now") and update. The current supported distributions are: +* RHEL +* Fedora * SLES * openSUSE_Leap diff --git a/img_proof/ipa_cloud.py b/img_proof/ipa_cloud.py index 4e95dd6d..46fbd3f2 100644 --- a/img_proof/ipa_cloud.py +++ b/img_proof/ipa_cloud.py @@ -40,6 +40,8 @@ NOT_IMPLEMENTED, TEST_PATHS ) +from img_proof.ipa_rhel import RHEL +from img_proof.ipa_fedora import Fedora from img_proof.ipa_opensuse_leap import openSUSE_Leap from img_proof.ipa_sles import SLES from img_proof.ipa_exceptions import ( @@ -376,7 +378,11 @@ def _save_results(self): def _set_distro(self): """Determine distro for image and create instance of class.""" - if self.distro_name == 'sles': + if self.distro_name == 'rhel': + self.distro = RHEL() + elif self.distro_name == 'fedora': + self.distro = Fedora() + elif self.distro_name == 'sles': self.distro = SLES() elif self.distro_name == 'opensuse_leap': self.distro = openSUSE_Leap() diff --git a/img_proof/ipa_exceptions.py b/img_proof/ipa_exceptions.py index b42c16c9..168e8064 100644 --- a/img_proof/ipa_exceptions.py +++ b/img_proof/ipa_exceptions.py @@ -65,6 +65,10 @@ class IpaResultsException(IpaException): """Results subcommand exception.""" +class IpaRedHatException(IpaDistroException): + """Generic Exception for Red Hat distro modules.""" + + class IpaSLESException(IpaDistroException): """Generic Exception for distro modules.""" diff --git a/img_proof/ipa_fedora.py b/img_proof/ipa_fedora.py new file mode 100644 index 00000000..5e264e2d --- /dev/null +++ b/img_proof/ipa_fedora.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +"""Fedora distro module and sync points.""" + +# Copyright (c) 2020 Neal Gompa. All rights reserved. +# +# This file is part of img_proof. img_proof provides an api and command line +# utilities for testing images in the Public Cloud. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from img_proof.ipa_redhat import RedHat + + +class Fedora(RedHat): + """Fedora distro class.""" diff --git a/img_proof/ipa_redhat.py b/img_proof/ipa_redhat.py new file mode 100644 index 00000000..545671d8 --- /dev/null +++ b/img_proof/ipa_redhat.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +"""Red Hat distro family module and sync points.""" + +# Copyright (c) 2020 Neal Gompa. All rights reserved. +# +# This file is part of img_proof. img_proof provides an api and command line +# utilities for testing images in the Public Cloud. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from img_proof.ipa_distro import Distro +from img_proof.ipa_exceptions import IpaRedHatException + + +class RedHat(Distro): + """Red Hat distro class.""" + + def get_install_cmd(self): + """Return install package command for Red Hat distributions.""" + return 'dnf --assumeyes --nogpgcheck install' + + def get_refresh_repo_cmd(self): + """Return refresh repo command for Red Hat distributions.""" + return 'dnf --assumeyes makecache' + + def get_stop_ssh_service_cmd(self): + """ + Return command to stop SSH service for Red Hat distributions. + + SSH stop command determined by init system. + """ + if self.init_system == 'systemd': + return 'systemctl stop sshd.service' + elif self.init_system == 'init': + return 'service sshd stop' + else: + raise IpaRedHatException( + 'The init system for this Red Hat system cannot be determined.' + ) + + def get_update_cmd(self): + """Return command to update Red Hat distribution instance.""" + return 'dnf --assumeyes upgrade' diff --git a/img_proof/ipa_rhel.py b/img_proof/ipa_rhel.py new file mode 100644 index 00000000..11208323 --- /dev/null +++ b/img_proof/ipa_rhel.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +"""RHEL distro module and sync points.""" + +# Copyright (c) 2020 Neal Gompa. All rights reserved. +# +# This file is part of img_proof. img_proof provides an api and command line +# utilities for testing images in the Public Cloud. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from img_proof.ipa_redhat import RedHat + + +class RHEL(RedHat): + """RHEL distro class.""" diff --git a/tests/test_ipa_fedora_distro.py b/tests/test_ipa_fedora_distro.py new file mode 100644 index 00000000..b384e9b7 --- /dev/null +++ b/tests/test_ipa_fedora_distro.py @@ -0,0 +1,39 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +"""img_proof Fedora distro unit tests.""" + +# Copyright (c) 2020 Neal Gompa. All rights reserved. +# +# This file is part of img_proof. img_proof provides an api and command line +# utilities for testing images in the Public Cloud. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from img_proof.ipa_fedora import Fedora + +from unittest.mock import MagicMock, patch + + +def test_fedora_set_init_system(): + """Test Fedora set init system method.""" + client = MagicMock() + fedora = Fedora() + + with patch('img_proof.ipa_utils.execute_ssh_command', + MagicMock(return_value='systemd')) as mocked: + fedora._set_init_system(client) + + assert fedora.init_system == 'systemd' + mocked.assert_called_once_with(client, 'ps -p 1 -o comm=') diff --git a/tests/test_ipa_redhat_distro.py b/tests/test_ipa_redhat_distro.py new file mode 100644 index 00000000..2f8b3afc --- /dev/null +++ b/tests/test_ipa_redhat_distro.py @@ -0,0 +1,161 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +"""img_proof Red Hat distro unit tests.""" + +# Copyright (c) 2020 Neal Gompa. All rights reserved. +# +# This file is part of img_proof. img_proof provides an api and command line +# utilities for testing images in the Public Cloud. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import pytest + +from img_proof.ipa_exceptions import IpaDistroException, IpaRedHatException +from img_proof.ipa_redhat import RedHat + +from unittest.mock import MagicMock, patch + + +def test_redhat_get_stop_ssh_cmd(): + """Test Red Hat get stop ssh cmd method.""" + redhat = RedHat() + + redhat.init_system = 'systemd' + assert redhat.get_stop_ssh_service_cmd() == 'systemctl stop sshd.service' + + redhat.init_system = 'init' + assert redhat.get_stop_ssh_service_cmd() == 'service sshd stop' + + redhat.init_system = 'fake' + with pytest.raises(IpaRedHatException) as error: + redhat.get_stop_ssh_service_cmd() + assert str(error.value) == \ + 'The init system for this Red Hat system cannot be determined.' + + +def test_redhat_install_package(): + """Test install package method for Red Hat distro.""" + client = MagicMock() + redhat = RedHat() + + with patch('img_proof.ipa_utils.execute_ssh_command', + MagicMock(return_value='')) as mocked: + redhat.install_package(client, 'python') + + mocked.assert_called_once_with( + client, + "sudo sh -c 'dnf --assumeyes --nogpgcheck install python'" + ) + + +@patch('img_proof.ipa_distro.time') +def test_redhat_reboot(mock_time): + """Test soft reboot method for Red Hat distro.""" + client = MagicMock() + channel = MagicMock() + transport = MagicMock() + transport.open_session.return_value = channel + client.get_transport.return_value = transport + redhat = RedHat() + redhat.init_system = 'systemd' + + redhat.reboot(client) + + channel.exec_command.assert_called_once_with( + "sudo sh -c '(sleep 1 && systemctl stop sshd.service " + "&& shutdown -r now &)' && exit" + ) + + +def test_redhat_reboot_exception(): + """Test soft reboot method exception for Red Hat distro.""" + client = MagicMock() + client.get_transport.side_effect = Exception('ERROR!') + redhat = RedHat() + redhat.init_system = 'systemd' + + with pytest.raises(IpaDistroException): + redhat.reboot(client) + + +def test_redhat_update(): + """Test update method for Red Hat distro.""" + client = MagicMock() + redhat = RedHat() + + with patch('img_proof.ipa_utils.execute_ssh_command', + MagicMock(return_value='Update finished!')) as mocked: + output = redhat.update(client) + + mocked.assert_called_once_with( + client, + "sudo sh -c 'dnf --assumeyes makecache;dnf --assumeyes upgrade'" + ) + assert output == 'Update finished!' + + +def test_redhat_update_exception(): + """Test update method exception for Red Hat distro.""" + client = MagicMock() + redhat = RedHat() + + with patch('img_proof.ipa_utils.execute_ssh_command', MagicMock( + side_effect=Exception('ERROR!'))) as mocked: + pytest.raises( + IpaDistroException, + redhat.update, + client + ) + + mocked.assert_called_once_with( + client, + "sudo sh -c 'dnf --assumeyes makecache;dnf --assumeyes upgrade'" + ) + + +def test_redhat_refresh(): + """Test refresh method for Red Hat distro.""" + client = MagicMock() + redhat = RedHat() + + with patch('img_proof.ipa_utils.execute_ssh_command', + MagicMock(return_value='Refresh finished!')) as mocked: + output = redhat.repo_refresh(client) + + mocked.assert_called_once_with( + client, + "sudo sh -c 'dnf --assumeyes makecache'" + ) + assert output == 'Refresh finished!' + + +def test_redhat_refresh_exception(): + """Test refresh method exception for Red Hat distro.""" + client = MagicMock() + redhat = RedHat() + + with patch('img_proof.ipa_utils.execute_ssh_command', MagicMock( + side_effect=Exception('ERROR!'))) as mocked: + pytest.raises( + IpaDistroException, + redhat.repo_refresh, + client + ) + + mocked.assert_called_once_with( + client, + "sudo sh -c 'dnf --assumeyes makecache'" + ) diff --git a/tests/test_ipa_rhel_distro.py b/tests/test_ipa_rhel_distro.py new file mode 100644 index 00000000..a1c1fa45 --- /dev/null +++ b/tests/test_ipa_rhel_distro.py @@ -0,0 +1,39 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +"""img_proof RHEL distro unit tests.""" + +# Copyright (c) 2020 Neal Gompa. All rights reserved. +# +# This file is part of img_proof. img_proof provides an api and command line +# utilities for testing images in the Public Cloud. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from img_proof.ipa_rhel import RHEL + +from unittest.mock import MagicMock, patch + + +def test_rhel_set_init_system(): + """Test RHEL set init system method.""" + client = MagicMock() + rhel = RHEL() + + with patch('img_proof.ipa_utils.execute_ssh_command', + MagicMock(return_value='systemd')) as mocked: + rhel._set_init_system(client) + + assert rhel.init_system == 'systemd' + mocked.assert_called_once_with(client, 'ps -p 1 -o comm=')