diff --git a/salt-shaptools.changes b/salt-shaptools.changes index b7a85add..c646ae9f 100644 --- a/salt-shaptools.changes +++ b/salt-shaptools.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri Mar 27 18:06:32 UTC 2020 - Simranpal Singh + +- Version 0.3.4 + * Add new salt module and state to extract the sar files using SAPCAR + ------------------------------------------------------------------- Fri Mar 20 14:49:04 UTC 2020 - Xabier Arbulu diff --git a/salt-shaptools.spec b/salt-shaptools.spec index 6f6f6bc6..5bf6af08 100644 --- a/salt-shaptools.spec +++ b/salt-shaptools.spec @@ -19,7 +19,7 @@ # See also https://en.opensuse.org/openSUSE:Specfile_guidelines Name: salt-shaptools -Version: 0.3.3 +Version: 0.3.4 Release: 0 Summary: Salt modules and states for SAP Applications and SLE-HA components management diff --git a/salt/modules/sapcarmod.py b/salt/modules/sapcarmod.py new file mode 100644 index 00000000..7f9ff188 --- /dev/null +++ b/salt/modules/sapcarmod.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +''' +Module to provide SAP tools functionality to Salt + +.. versionadded:: pending + +:maintainer: Simranpal Singh +:maturity: alpha +:depends: ``shaptools`` Python module +:platform: all + +:configuration: This module requires the shaptools package +''' + + +# Import Python libs +from __future__ import absolute_import, unicode_literals + +from salt import exceptions + +# Import third party libs +try: + from shaptools import saputils + HAS_SAPUTILS = True +except ImportError: # pragma: no cover + HAS_SAPUTILS = False + +__virtualname__ = 'sapcar' + + +def __virtual__(): # pragma: no cover + ''' + Only load this module if shaptools python module is installed + ''' + if HAS_SAPUTILS: + return __virtualname__ + return ( + False, + 'The sapcar execution module failed to load: the shaptools python' + ' library is not available.') + + +def extract( + sapcar_exe, + sar_file, + output_dir=None, + options=None): + ''' + Extract a SAP sar archive + + sapcar_exe_file + Path to the SAPCAR executable file. SAPCAR is a SAP tool to extract SAP SAR format archives + sar_file + Path to the sar file to be extracted + output_dir + Location where to extract the SAR file + options: + Additional parameters to the SAPCAR tool + ''' + try: + return saputils.extract_sapcar_file( + sapcar_exe=sapcar_exe, sar_file=sar_file, output_dir=output_dir, options=options) + except saputils.SapUtilsError as err: + raise exceptions.CommandExecutionError(err) diff --git a/salt/states/sapcarmod.py b/salt/states/sapcarmod.py new file mode 100644 index 00000000..92d02955 --- /dev/null +++ b/salt/states/sapcarmod.py @@ -0,0 +1,86 @@ +''' +State module to provide SAP utilities functionality to Salt + +.. versionadded:: pending + +:maintainer: Simranpal Singh +:maturity: alpha +:depends: python-shaptools +:platform: all + +:configuration: This module requires the python-shaptools module + +:usage: + +.. code-block:: yaml + extract_sap_car_file: + sapcar.extracted: + - name: home/sapuser/saprouter_600-80003478.sar + - sapcar_exe: ./SAPCAR.exe + - output_dir: home/sapuser/saprouter_inst + - options: "-manifest SIGNATURE.SMF" +''' + + +# Import python libs +from __future__ import absolute_import, unicode_literals + +# Import salt libs +from salt import exceptions +from salt.ext import six + + +__virtualname__ = 'sapcar' + + +def __virtual__(): # pragma: no cover + ''' + Only load this module if sapcar python module is installed + ''' + return 'sapcar.extract' in __salt__ + + +def extracted( + name, + sapcar_exe, + output_dir=None, + options=None): + """ + Extract a SAPCAR sar archive + + name + SAR file name to be extracted + sapcar_exe + Path to the SAPCAR executable file. SAPCAR is a SAP tool to extract SAP SAR format archives + output_dir + Location where to extract the SAR file. If not provided, use current directory as name + options: + Additional parameters to the SAPCAR tool + """ + ret = {'name': name, + 'changes': {}, + 'result': False, + 'comment': ''} + + if __opts__['test']: + ret['result'] = None + ret['comment'] = '{} would be extracted'.format(name) + ret['changes']['output_dir'] = output_dir + return ret + + try: + # Here starts the actual process + __salt__['sapcar.extract']( + sapcar_exe=sapcar_exe, + sar_file=name, + output_dir=output_dir, + options=options) + + ret['changes']['output_dir'] = output_dir + ret['comment'] = '{} file extracted'.format(name) + ret['result'] = True + return ret + + except exceptions.CommandExecutionError as err: + ret['comment'] = six.text_type(err) + return ret \ No newline at end of file diff --git a/tests/run.sh b/tests/run.sh index e15f46f8..fc415054 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -2,4 +2,4 @@ cp salt/modules/*.py ../salt/salt/modules/ cp salt/states/*.py ../salt/salt/states/ cp tests/unit/modules/*.py ../salt/tests/unit/modules/ cp tests/unit/states/*.py ../salt/tests/unit/states/ -py.test -vv ../salt/tests/unit/modules/test_hanamod.py ../salt/tests/unit/states/test_hanamod.py ../salt/tests/unit/modules/test_crmshmod.py ../salt/tests/unit/modules/test_saptunemod.py ../salt/tests/unit/states/test_crmshmod.py ../salt/tests/unit/modules/test_drbdmod.py ../salt/tests/unit/states/test_drbdmod.py ../salt/tests/unit/states/test_saptunemod.py ../salt/tests/unit/modules/test_netweavermod.py ../salt/tests/unit/states/test_netweavermod.py --cov=salt.modules.hanamod --cov=salt.states.hanamod --cov=salt.modules.crmshmod --cov=salt.states.crmshmod --cov=salt.modules.drbdmod --cov=salt.modules.saptunemod --cov=salt.states.saptunemod --cov=salt.states.drbdmod --cov=salt.modules.netweavermod --cov=salt.states.netweavermod --cov-config .coveragerc --cov-report term --cov-report xml --cov-report html +py.test -vv ../salt/tests/unit/modules/test_hanamod.py ../salt/tests/unit/states/test_hanamod.py ../salt/tests/unit/modules/test_crmshmod.py ../salt/tests/unit/modules/test_saptunemod.py ../salt/tests/unit/modules/test_sapcarmod.py ../salt/tests/unit/states/test_crmshmod.py ../salt/tests/unit/modules/test_drbdmod.py ../salt/tests/unit/states/test_drbdmod.py ../salt/tests/unit/states/test_saptunemod.py ../salt/tests/unit/modules/test_netweavermod.py ../salt/tests/unit/states/test_netweavermod.py ../salt/tests/unit/states/test_sapcarmod.py --cov=salt.modules.hanamod --cov=salt.states.hanamod --cov=salt.modules.crmshmod --cov=salt.states.crmshmod --cov=salt.modules.drbdmod --cov=salt.modules.saptunemod --cov=salt.modules.sapcarmod --cov=salt.states.saptunemod --cov=salt.states.drbdmod --cov=salt.modules.netweavermod --cov=salt.states.netweavermod --cov=salt.states.sapcarmod --cov-config .coveragerc --cov-report term --cov-report xml --cov-report html diff --git a/tests/unit/modules/test_sapcarmod.py b/tests/unit/modules/test_sapcarmod.py new file mode 100644 index 00000000..67707b88 --- /dev/null +++ b/tests/unit/modules/test_sapcarmod.py @@ -0,0 +1,60 @@ + +# -*- coding: utf-8 -*- +''' + :codeauthor: Simranpal Singh +''' + +# Import Python Libs +from __future__ import absolute_import, print_function, unicode_literals +import pytest + +from salt import exceptions + +# Import Salt Testing Libs +from tests.support.mixins import LoaderModuleMockMixin +from tests.support.unit import TestCase, skipIf +from tests.support import mock +from tests.support.mock import ( + MagicMock, + patch, + mock_open, + NO_MOCK, + NO_MOCK_REASON +) + +# Import Salt Libs +import salt.modules.sapcarmod as sapcarmod + + +@skipIf(NO_MOCK, NO_MOCK_REASON) +class SapcarModuleTest(TestCase, LoaderModuleMockMixin): + ''' + This class contains a set of functions that test salt.modules.sapcarmod. + ''' + + def setup_loader_modules(self): + return {sapcarmod: {}} + + @patch('salt.modules.sapcarmod.saputils.extract_sapcar_file') + def test_extract_return(self, mock_extract): + ''' + Test extract method - return + ''' + mock_extract.return_value = 0 + assert sapcarmod.extract('/sapmedia/SAPCAR','/sapmedia/IMDB_SERVER_LINUX.SAR', '/sapmedia/HANA', '-v') == 0 + mock_extract.assert_called_once_with( + sapcar_exe='/sapmedia/SAPCAR', sar_file='/sapmedia/IMDB_SERVER_LINUX.SAR', + output_dir='/sapmedia/HANA', options='-v') + + @patch('salt.modules.sapcarmod.saputils.extract_sapcar_file') + def test_extract_raise(self, mock_extract): + ''' + Test extract method - raise + ''' + mock_extract.side_effect = sapcarmod.saputils.SapUtilsError('error') + with pytest.raises(exceptions.CommandExecutionError) as err: + sapcarmod.extract('/sapmedia/SAPCAR','/sapmedia/IMDB_SERVER_LINUX.SAR', '/sapmedia/HANA', '-v') + mock_extract.assert_called_once_with( + sapcar_exe='/sapmedia/SAPCAR', sar_file='/sapmedia/IMDB_SERVER_LINUX.SAR', + output_dir='/sapmedia/HANA', options='-v') + \ No newline at end of file diff --git a/tests/unit/states/test_sapcarmod.py b/tests/unit/states/test_sapcarmod.py new file mode 100644 index 00000000..a7083954 --- /dev/null +++ b/tests/unit/states/test_sapcarmod.py @@ -0,0 +1,90 @@ + +# -*- coding: utf-8 -*- +''' + :codeauthor: Simranpal Singh +''' +# Import Python libs +from __future__ import absolute_import, unicode_literals, print_function + +from salt import exceptions + +# Import Salt Testing Libs +from tests.support.mixins import LoaderModuleMockMixin +from tests.support.unit import skipIf, TestCase +from tests.support import mock +from tests.support.mock import ( + NO_MOCK, + NO_MOCK_REASON, + MagicMock, + patch +) + +# Import Salt Libs +import salt.states.sapcarmod as sapcar + + +@skipIf(NO_MOCK, NO_MOCK_REASON) +class SapcarmodTestCase(TestCase, LoaderModuleMockMixin): + ''' + Test cases for salt.states.sapcarmod + ''' + def setup_loader_modules(self): + return {sapcar: {'__opts__': {'test': False}}} + + def test_available_test(self): + ''' + Test to check extracted in test mode + ''' + + ret = {'name': '/sapmedia/IMDB_SERVER_LINUX.SAR', + 'changes': {'output_dir': '/sapmedia'}, + 'result': None, + 'comment': '/sapmedia/IMDB_SERVER_LINUX.SAR would be extracted'} + + with patch.dict(sapcar.__opts__, {'test': True}): + assert sapcar.extracted( + name='/sapmedia/IMDB_SERVER_LINUX.SAR', output_dir='/sapmedia', + sapcar_exe='/sapmedia/SAPCAR') + + def test_extracted_basic(self): + ''' + Test to check extracted when sapcar successfully extracts a sar file + ''' + + expected_ret = { + 'name': '/sapmedia/IMDB_SERVER_LINUX.SAR', + 'changes': {'output_dir': '/sapmedia'}, + 'result': True, + 'comment': '/sapmedia/IMDB_SERVER_LINUX.SAR file extracted' + } + + mock_extract = MagicMock() + with patch.dict(sapcar.__salt__, { + 'sapcar.extract': mock_extract}): + assert sapcar.extracted( + name='/sapmedia/IMDB_SERVER_LINUX.SAR', output_dir='/sapmedia', + sapcar_exe='/sapmedia/SAPCAR') == expected_ret + mock_extract.assert_called_once_with( + sapcar_exe='/sapmedia/SAPCAR', sar_file='/sapmedia/IMDB_SERVER_LINUX.SAR', + output_dir='/sapmedia', options=None) + + def test_extracted_error_exception(self): + ''' + Test to check extracted when sapcar fails to extracts a sar file + ''' + + expected_ret = { + 'changes': {}, + 'result': False, + 'name': '/sapmedia/IMDB_SERVER_LINUX.SAR', + 'comment': 'sapcar error' + } + + mock_extract = MagicMock(side_effect=exceptions.CommandExecutionError('sapcar error')) + with patch.dict(sapcar.__salt__, { + 'sapcar.extract': mock_extract}): + assert sapcar.extracted( + '/sapmedia/IMDB_SERVER_LINUX.SAR','/sapmedia/SAPCAR', options='-v') == expected_ret + mock_extract.assert_called_once_with( + sapcar_exe='/sapmedia/SAPCAR', sar_file='/sapmedia/IMDB_SERVER_LINUX.SAR', + output_dir=None, options='-v')