add persistent option for modprobe (#5424)

* add persistent option for modprobe

* add suggested changes + fix broken test

* change modprobe module path in tests due to rebase

* change persistent option type from bool to str with choices

* fix unused import

* add example with persistent option

* fix some minor issues after review

- move regexps compiling to __init__
- move AnsibleModule to build_module function and use this function in tests instead of AnsibleModule
- fix terminlogy issue in documentation

* fix unused-import
This commit is contained in:
Alex Groshev 2023-02-26 14:58:58 +01:00 committed by GitHub
commit 29f5033737
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 500 additions and 36 deletions

View file

@ -6,11 +6,12 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import sys
from ansible_collections.community.general.tests.unit.plugins.modules.utils import ModuleTestCase, set_module_args
from ansible_collections.community.general.tests.unit.compat.mock import patch
from ansible_collections.community.general.tests.unit.compat.mock import Mock
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.modules.modprobe import Modprobe
from ansible_collections.community.general.tests.unit.compat.mock import mock_open
from ansible_collections.community.general.plugins.modules.modprobe import Modprobe, build_module
class TestLoadModule(ModuleTestCase):
@ -40,14 +41,7 @@ class TestLoadModule(ModuleTestCase):
state='present',
))
module = AnsibleModule(
argument_spec=dict(
name=dict(type='str', required=True),
state=dict(type='str', default='present', choices=['absent', 'present']),
params=dict(type='str', default=''),
),
supports_check_mode=True,
)
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
self.module_loaded.side_effect = [True]
@ -69,14 +63,7 @@ class TestLoadModule(ModuleTestCase):
state='present',
))
module = AnsibleModule(
argument_spec=dict(
name=dict(type='str', required=True),
state=dict(type='str', default='present', choices=['absent', 'present']),
params=dict(type='str', default=''),
),
supports_check_mode=True,
)
module = build_module()
module.warn = Mock()
@ -117,14 +104,7 @@ class TestUnloadModule(ModuleTestCase):
state='absent',
))
module = AnsibleModule(
argument_spec=dict(
name=dict(type='str', required=True),
state=dict(type='str', default='present', choices=['absent', 'present']),
params=dict(type='str', default=''),
),
supports_check_mode=True,
)
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
self.module_loaded.side_effect = [False]
@ -146,14 +126,7 @@ class TestUnloadModule(ModuleTestCase):
state='absent',
))
module = AnsibleModule(
argument_spec=dict(
name=dict(type='str', required=True),
state=dict(type='str', default='present', choices=['absent', 'present']),
params=dict(type='str', default=''),
),
supports_check_mode=True,
)
module = build_module()
module.fail_json = Mock()
@ -174,3 +147,339 @@ class TestUnloadModule(ModuleTestCase):
module.fail_json.assert_called_once_with(
msg='', rc=1, stdout='', stderr='', **dummy_result
)
class TestModuleIsLoadedPersistently(ModuleTestCase):
def setUp(self):
if (sys.version_info[0] == 3 and sys.version_info[1] < 7) or (sys.version_info[0] == 2 and sys.version_info[1] < 7):
self.skipTest('open_mock doesnt support readline in earlier python versions')
super(TestModuleIsLoadedPersistently, self).setUp()
self.mock_get_bin_path = patch('ansible.module_utils.basic.AnsibleModule.get_bin_path')
self.get_bin_path = self.mock_get_bin_path.start()
def tearDown(self):
"""Teardown."""
super(TestModuleIsLoadedPersistently, self).tearDown()
self.mock_get_bin_path.stop()
def test_module_is_loaded(self):
set_module_args(dict(
name='dummy',
state='present',
persistent='present'
))
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
modprobe = Modprobe(module)
with patch('ansible_collections.community.general.plugins.modules.modprobe.open', mock_open(read_data='dummy')) as mocked_file:
with patch('ansible_collections.community.general.plugins.modules.modprobe.Modprobe.modules_files'):
modprobe.modules_files = ['/etc/modules-load.d/dummy.conf']
assert modprobe.module_is_loaded_persistently
mocked_file.assert_called_once_with('/etc/modules-load.d/dummy.conf')
def test_module_is_not_loaded_empty_file(self):
set_module_args(dict(
name='dummy',
state='present',
persistent='present'
))
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
modprobe = Modprobe(module)
with patch('ansible_collections.community.general.plugins.modules.modprobe.open', mock_open(read_data='')) as mocked_file:
with patch('ansible_collections.community.general.plugins.modules.modprobe.Modprobe.modules_files'):
modprobe.modules_files = ['/etc/modules-load.d/dummy.conf']
assert not modprobe.module_is_loaded_persistently
mocked_file.assert_called_once_with('/etc/modules-load.d/dummy.conf')
def test_module_is_not_loaded_no_files(self):
set_module_args(dict(
name='dummy',
state='present',
persistent='present'
))
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
modprobe = Modprobe(module)
with patch('ansible_collections.community.general.plugins.modules.modprobe.Modprobe.modules_files'):
modprobe.modules_files = []
assert not modprobe.module_is_loaded_persistently
class TestPermanentParams(ModuleTestCase):
def setUp(self):
if (sys.version_info[0] == 3 and sys.version_info[1] < 7) or (sys.version_info[0] == 2 and sys.version_info[1] < 7):
self.skipTest('open_mock doesnt support readline in earlier python versions')
super(TestPermanentParams, self).setUp()
self.mock_get_bin_path = patch('ansible.module_utils.basic.AnsibleModule.get_bin_path')
self.get_bin_path = self.mock_get_bin_path.start()
def tearDown(self):
"""Teardown."""
super(TestPermanentParams, self).tearDown()
self.mock_get_bin_path.stop()
def test_module_permanent_params_exist(self):
files_content = [
'options dummy numdummies=4\noptions dummy dummy_parameter1=6',
'options dummy dummy_parameter2=5 #Comment\noptions notdummy notdummy_param=5'
]
mock_files_content = [mock_open(read_data=content).return_value for content in files_content]
set_module_args(dict(
name='dummy',
state='present',
persistent='present'
))
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
modprobe = Modprobe(module)
with patch('ansible_collections.community.general.plugins.modules.modprobe.open', mock_open()) as mocked_file:
mocked_file.side_effect = mock_files_content
with patch('ansible_collections.community.general.plugins.modules.modprobe.Modprobe.modprobe_files'):
modprobe.modprobe_files = ['/etc/modprobe.d/dummy1.conf', '/etc/modprobe.d/dummy2.conf']
assert modprobe.permanent_params == set(['numdummies=4', 'dummy_parameter1=6', 'dummy_parameter2=5'])
def test_module_permanent_params_empty(self):
files_content = [
'',
''
]
mock_files_content = [mock_open(read_data=content).return_value for content in files_content]
set_module_args(dict(
name='dummy',
state='present',
persistent='present'
))
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
modprobe = Modprobe(module)
with patch('ansible_collections.community.general.plugins.modules.modprobe.open', mock_open(read_data='')) as mocked_file:
mocked_file.side_effect = mock_files_content
with patch('ansible_collections.community.general.plugins.modules.modprobe.Modprobe.modprobe_files'):
modprobe.modprobe_files = ['/etc/modprobe.d/dummy1.conf', '/etc/modprobe.d/dummy2.conf']
assert modprobe.permanent_params == set()
class TestCreateModuleFIle(ModuleTestCase):
def setUp(self):
super(TestCreateModuleFIle, self).setUp()
self.mock_get_bin_path = patch('ansible.module_utils.basic.AnsibleModule.get_bin_path')
self.get_bin_path = self.mock_get_bin_path.start()
def tearDown(self):
"""Teardown."""
super(TestCreateModuleFIle, self).tearDown()
self.mock_get_bin_path.stop()
def test_create_file(self):
set_module_args(dict(
name='dummy',
state='present',
persistent='present'
))
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
modprobe = Modprobe(module)
with patch('ansible_collections.community.general.plugins.modules.modprobe.open', mock_open()) as mocked_file:
modprobe.create_module_file()
mocked_file.assert_called_once_with('/etc/modules-load.d/dummy.conf', 'w')
mocked_file().write.assert_called_once_with('dummy\n')
class TestCreateModuleOptionsFIle(ModuleTestCase):
def setUp(self):
super(TestCreateModuleOptionsFIle, self).setUp()
self.mock_get_bin_path = patch('ansible.module_utils.basic.AnsibleModule.get_bin_path')
self.get_bin_path = self.mock_get_bin_path.start()
def tearDown(self):
"""Teardown."""
super(TestCreateModuleOptionsFIle, self).tearDown()
self.mock_get_bin_path.stop()
def test_create_file(self):
set_module_args(dict(
name='dummy',
state='present',
params='numdummies=4',
persistent='present'
))
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
modprobe = Modprobe(module)
with patch('ansible_collections.community.general.plugins.modules.modprobe.open', mock_open()) as mocked_file:
modprobe.create_module_options_file()
mocked_file.assert_called_once_with('/etc/modprobe.d/dummy.conf', 'w')
mocked_file().write.assert_called_once_with('options dummy numdummies=4\n')
class TestDisableOldParams(ModuleTestCase):
def setUp(self):
super(TestDisableOldParams, self).setUp()
self.mock_get_bin_path = patch('ansible.module_utils.basic.AnsibleModule.get_bin_path')
self.get_bin_path = self.mock_get_bin_path.start()
def tearDown(self):
"""Teardown."""
super(TestDisableOldParams, self).tearDown()
self.mock_get_bin_path.stop()
def test_disable_old_params_file_changed(self):
mock_data = 'options dummy numdummies=4'
set_module_args(dict(
name='dummy',
state='present',
params='numdummies=4',
persistent='present'
))
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
modprobe = Modprobe(module)
with patch('ansible_collections.community.general.plugins.modules.modprobe.open', mock_open(read_data=mock_data)) as mocked_file:
with patch('ansible_collections.community.general.plugins.modules.modprobe.Modprobe.modprobe_files'):
modprobe.modprobe_files = ['/etc/modprobe.d/dummy1.conf']
modprobe.disable_old_params()
mocked_file.assert_called_with('/etc/modprobe.d/dummy1.conf', 'w')
mocked_file().write.assert_called_once_with('#options dummy numdummies=4')
def test_disable_old_params_file_unchanged(self):
mock_data = 'options notdummy numdummies=4'
set_module_args(dict(
name='dummy',
state='present',
params='numdummies=4',
persistent='present'
))
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
modprobe = Modprobe(module)
with patch('ansible_collections.community.general.plugins.modules.modprobe.open', mock_open(read_data=mock_data)) as mocked_file:
with patch('ansible_collections.community.general.plugins.modules.modprobe.Modprobe.modprobe_files'):
modprobe.modprobe_files = ['/etc/modprobe.d/dummy1.conf']
modprobe.disable_old_params()
mocked_file.assert_called_once_with('/etc/modprobe.d/dummy1.conf')
class TestDisableModulePermanent(ModuleTestCase):
def setUp(self):
super(TestDisableModulePermanent, self).setUp()
self.mock_get_bin_path = patch('ansible.module_utils.basic.AnsibleModule.get_bin_path')
self.get_bin_path = self.mock_get_bin_path.start()
def tearDown(self):
"""Teardown."""
super(TestDisableModulePermanent, self).tearDown()
self.mock_get_bin_path.stop()
def test_disable_module_permanent_file_changed(self):
set_module_args(dict(
name='dummy',
state='present',
params='numdummies=4',
persistent='present'
))
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
modprobe = Modprobe(module)
with patch('ansible_collections.community.general.plugins.modules.modprobe.open', mock_open(read_data='dummy')) as mocked_file:
with patch('ansible_collections.community.general.plugins.modules.modprobe.Modprobe.modules_files'):
modprobe.modules_files = ['/etc/modules-load.d/dummy.conf']
modprobe.disable_module_permanent()
mocked_file.assert_called_with('/etc/modules-load.d/dummy.conf', 'w')
mocked_file().write.assert_called_once_with('#dummy')
def test_disable_module_permanent_file_unchanged(self):
set_module_args(dict(
name='dummy',
state='present',
params='numdummies=4',
persistent='present'
))
module = build_module()
self.get_bin_path.side_effect = ['modprobe']
modprobe = Modprobe(module)
with patch('ansible_collections.community.general.plugins.modules.modprobe.open', mock_open(read_data='notdummy')) as mocked_file:
with patch('ansible_collections.community.general.plugins.modules.modprobe.Modprobe.modules_files'):
modprobe.modules_files = ['/etc/modules-load.d/dummy.conf']
modprobe.disable_module_permanent()
mocked_file.assert_called_once_with('/etc/modules-load.d/dummy.conf')