From 7fd3bcea47dafbf10ff71091e881000618becfd7 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Tue, 27 Nov 2018 14:58:59 -0600 Subject: [PATCH] Add remove parameter to host.present state --- salt/states/host.py | 18 ++++++++-- tests/unit/states/test_host.py | 60 ++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/salt/states/host.py b/salt/states/host.py index 6acab55d8e..fbedefdd65 100644 --- a/salt/states/host.py +++ b/salt/states/host.py @@ -67,7 +67,7 @@ from salt.ext import six import salt.utils.validate.net -def present(name, ip): # pylint: disable=C0103 +def present(name, ip, remove=False): # pylint: disable=C0103 ''' Ensures that the named host is present with the given ip @@ -77,6 +77,12 @@ def present(name, ip): # pylint: disable=C0103 ip The ip addr(s) to apply to the host. Can be a single IP or a list of IP addresses. + + remove : False + Remove any entries which don't match those configured in the ``ip`` + option. + + .. versionadded:: 2018.3.4 ''' ret = {'name': name, 'changes': {}, @@ -101,7 +107,15 @@ def present(name, ip): # pylint: disable=C0103 if name in aliases: # Found match for hostname, but the corresponding IP is not in # our list, so we need to remove it. - to_remove.add((addr, name)) + if remove: + to_remove.add((addr, name)) + else: + ret.setdefault('warnings', []).append( + 'Host {0} present for IP address {1}. To get rid of ' + 'this warning, either run this state with \'remove\' ' + 'set to True to remove {0} from {1}, or add {1} to ' + 'the \'ip\' argument.'.format(name, addr) + ) else: if name in aliases: # No changes needed for this IP address and hostname diff --git a/tests/unit/states/test_host.py b/tests/unit/states/test_host.py index a4e6fa285e..7da308b118 100644 --- a/tests/unit/states/test_host.py +++ b/tests/unit/states/test_host.py @@ -104,6 +104,26 @@ class HostTestCase(TestCase, LoaderModuleMockMixin): ret = host.present(hostname, ip_str) assert ret['result'] is True assert 'Added host {0} ({1})'.format(hostname, ip_str) in ret['comment'] + assert 'Host {0} present for IP address {1}'.format(hostname, ip_list[0]) in ret['warnings'][0] + assert ret['changes'] == { + 'added': { + ip_str: [hostname], + }, + }, ret['changes'] + expected = [call(ip_str, hostname)] + assert add_host.mock_calls == expected, add_host.mock_calls + assert rm_host.mock_calls == [], rm_host.mock_calls + + # Case 3a: Repeat the above with remove=True + add_host.reset_mock() + rm_host.reset_mock() + with patch.dict(host.__salt__, + {'hosts.list_hosts': list_hosts, + 'hosts.add_host': add_host, + 'hosts.rm_host': rm_host}): + ret = host.present(hostname, ip_str, remove=True) + assert ret['result'] is True + assert 'Added host {0} ({1})'.format(hostname, ip_str) in ret['comment'] assert 'Removed host {0} ({1})'.format(hostname, ip_list[0]) in ret['comment'] assert ret['changes'] == { 'added': { @@ -135,6 +155,27 @@ class HostTestCase(TestCase, LoaderModuleMockMixin): assert ret['result'] is True assert 'Added host {0} ({1})'.format(hostname, ip_list[0]) in ret['comment'] assert 'Added host {0} ({1})'.format(hostname, ip_list[1]) in ret['comment'] + assert ret['changes'] == { + 'added': { + ip_list[0]: [hostname], + ip_list[1]: [hostname], + }, + }, ret['changes'] + expected = sorted([call(x, hostname) for x in ip_list]) + assert sorted(add_host.mock_calls) == expected, add_host.mock_calls + assert rm_host.mock_calls == [], rm_host.mock_calls + + # Case 4a: Repeat the above with remove=True + add_host.reset_mock() + rm_host.reset_mock() + with patch.dict(host.__salt__, + {'hosts.list_hosts': list_hosts, + 'hosts.add_host': add_host, + 'hosts.rm_host': rm_host}): + ret = host.present(hostname, ip_list, remove=True) + assert ret['result'] is True + assert 'Added host {0} ({1})'.format(hostname, ip_list[0]) in ret['comment'] + assert 'Added host {0} ({1})'.format(hostname, ip_list[1]) in ret['comment'] assert 'Removed host {0} ({1})'.format(hostname, cur_ip) in ret['comment'] assert ret['changes'] == { 'added': { @@ -168,6 +209,25 @@ class HostTestCase(TestCase, LoaderModuleMockMixin): ret = host.present(hostname, ip_list) assert ret['result'] is True assert 'Added host {0} ({1})'.format(hostname, ip_list[1]) in ret['comment'] + assert ret['changes'] == { + 'added': { + ip_list[1]: [hostname], + }, + }, ret['changes'] + expected = [call(ip_list[1], hostname)] + assert add_host.mock_calls == expected, add_host.mock_calls + assert rm_host.mock_calls == [], rm_host.mock_calls + + # Case 5a: Repeat the above with remove=True + add_host.reset_mock() + rm_host.reset_mock() + with patch.dict(host.__salt__, + {'hosts.list_hosts': list_hosts, + 'hosts.add_host': add_host, + 'hosts.rm_host': rm_host}): + ret = host.present(hostname, ip_list, remove=True) + assert ret['result'] is True + assert 'Added host {0} ({1})'.format(hostname, ip_list[1]) in ret['comment'] assert 'Removed host {0} ({1})'.format(hostname, cur_ip) in ret['comment'] assert ret['changes'] == { 'added': {