Merge pull request #47552 from twangboy/fix_46981

Show GPO settings, raise error if trying to set gpo managed settings
This commit is contained in:
Nicole Thomas 2018-05-25 16:41:21 -04:00 committed by GitHub
commit 799fce979d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 145 additions and 22 deletions

View file

@ -0,0 +1,17 @@
===========================
In Progress: Salt 2017.7.7 Release Notes
===========================
Version 2017.7.7 is an **unreleased** bugfix release for :ref:`2017.7.0 <release-2017-7-0>`.
This release is still in progress and has not been released yet.
New win_snmp behavior
---------------------
`win_snmp.get_community_names` now returns the SNMP settings actually in effect
on the box. If settings are managed via GroupPolicy, those settings will be
returned. Otherwise, normal settings are returned.
`win_snmp.set_community_names` now raises a CommandExecutionError when SNMP
settings are being managed by GroupPolicy

View file

@ -9,17 +9,21 @@ from __future__ import absolute_import
import logging
# Import salt libs
from salt.exceptions import SaltInvocationError
from salt.exceptions import SaltInvocationError, CommandExecutionError
import salt.utils
# Import 3rd party libs
from salt.ext import six
_HKEY = 'HKLM'
_SNMP_KEY = r'SYSTEM\CurrentControlSet\Services\SNMP\Parameters'
_AGENT_KEY = r'{0}\RFC1156Agent'.format(_SNMP_KEY)
_COMMUNITIES_KEY = r'{0}\ValidCommunities'.format(_SNMP_KEY)
_SNMP_GPO_KEY = r'SOFTWARE\Policies\SNMP\Parameters'
_COMMUNITIES_GPO_KEY = r'{0}\ValidCommunities'.format(_SNMP_GPO_KEY)
_PERMISSION_TYPES = {'None': 1,
'Notify': 2,
'Read Only': 4,
@ -285,6 +289,21 @@ def get_community_names():
'''
Get the current accepted SNMP community names and their permissions.
If community names are being managed by Group Policy, those values will be
returned instead like this:
.. code-block:: bash
TestCommunity:
Managed by GPO
Community names managed normally will denote the permission instead:
.. code-block:: bash
TestCommunity:
Read Only
Returns:
dict: A dictionary of community names and permissions.
@ -295,25 +314,69 @@ def get_community_names():
salt '*' win_snmp.get_community_names
'''
ret = dict()
current_values = __salt__['reg.list_values'](
_HKEY, _COMMUNITIES_KEY, include_default=False)
# The communities are stored as the community name with a numeric permission
# value. Convert the numeric value to the text equivalent, as present in the
# Windows SNMP service GUI.
if isinstance(current_values, list):
for current_value in current_values:
# Look in GPO settings first
if __salt__['reg.key_exists'](_HKEY, _COMMUNITIES_GPO_KEY):
# Ignore error values
if not isinstance(current_value, dict):
continue
_LOG.debug('Loading communities from Group Policy settings')
permissions = str()
for permission_name in _PERMISSION_TYPES:
if current_value['vdata'] == _PERMISSION_TYPES[permission_name]:
permissions = permission_name
break
ret[current_value['vname']] = permissions
current_values = __salt__['reg.list_values'](
_HKEY, _COMMUNITIES_GPO_KEY, include_default=False)
# GPO settings are different in that they do not designate permissions
# They are a numbered list of communities like so:
#
# {1: "community 1",
# 2: "community 2"}
#
# Denote that it is being managed by Group Policy.
#
# community 1:
# Managed by GPO
# community 2:
# Managed by GPO
if isinstance(current_values, list):
for current_value in current_values:
# Ignore error values
if not isinstance(current_value, dict):
continue
ret[current_value['vdata']] = 'Managed by GPO'
if not ret:
_LOG.debug('Loading communities from SNMP settings')
current_values = __salt__['reg.list_values'](
_HKEY, _COMMUNITIES_KEY, include_default=False)
# The communities are stored as the community name with a numeric
# permission value. Like this (4 = Read Only):
#
# {"community 1": 4,
# "community 2": 4}
#
# Convert the numeric value to the text equivalent, as present in the
# Windows SNMP service GUI.
#
# community 1:
# Read Only
# community 2:
# Read Only
if isinstance(current_values, list):
for current_value in current_values:
# Ignore error values
if not isinstance(current_value, dict):
continue
permissions = str()
for permission_name in _PERMISSION_TYPES:
if current_value['vdata'] == _PERMISSION_TYPES[permission_name]:
permissions = permission_name
break
ret[current_value['vname']] = permissions
if not ret:
_LOG.debug('Unable to find existing communities.')
@ -324,6 +387,11 @@ def set_community_names(communities):
'''
Manage the SNMP accepted community names and their permissions.
.. note::
Settings managed by Group Policy will always take precedence over those
set using the SNMP interface. Therefore if this function finds Group
Policy settings it will raise a CommandExecutionError
Args:
communities (dict): A dictionary of SNMP community names and
permissions. The possible permissions can be found via
@ -332,6 +400,10 @@ def set_community_names(communities):
Returns:
bool: True if successful, otherwise False
Raises:
CommandExecutionError:
If SNMP settings are being managed by Group Policy
CLI Example:
.. code-block:: bash
@ -340,6 +412,11 @@ def set_community_names(communities):
'''
values = dict()
if __salt__['reg.key_exists'](_HKEY, _COMMUNITIES_GPO_KEY):
_LOG.debug('Communities on this system are managed by Group Policy')
raise CommandExecutionError(
'Communities on this system are managed by Group Policy')
current_communities = get_community_names()
if communities == current_communities:

View file

@ -11,6 +11,7 @@ from __future__ import absolute_import
# Import Salt Libs
import salt.modules.win_snmp as win_snmp
from salt.exceptions import CommandExecutionError
# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin
@ -70,19 +71,47 @@ class WinSnmpTestCase(TestCase, LoaderModuleMockMixin):
'''
Test - Get the current accepted SNMP community names and their permissions.
'''
mock_value = MagicMock(return_value=[{'vdata': 16,
'vname': 'TestCommunity'}])
with patch.dict(win_snmp.__salt__, {'reg.list_values': mock_value}):
mock_ret = MagicMock(return_value=[{'vdata': 16,
'vname': 'TestCommunity'}])
mock_false = MagicMock(return_value=False)
with patch.dict(win_snmp.__salt__, {'reg.list_values': mock_ret,
'reg.key_exists': mock_false}):
self.assertEqual(win_snmp.get_community_names(),
COMMUNITY_NAMES)
def test_get_community_names_gpo(self):
'''
Test - Get the current accepted SNMP community names and their permissions.
'''
mock_ret = MagicMock(return_value=[{'vdata': 'TestCommunity',
'vname': 1}])
mock_false = MagicMock(return_value=True)
with patch.dict(win_snmp.__salt__, {'reg.list_values': mock_ret,
'reg.key_exists': mock_false}):
self.assertEqual(win_snmp.get_community_names(),
{'TestCommunity': 'Managed by GPO'})
def test_set_community_names(self):
'''
Test - Manage the SNMP accepted community names and their permissions.
'''
mock_value = MagicMock(return_value=True)
mock_true = MagicMock(return_value=True)
kwargs = {'communities': COMMUNITY_NAMES}
with patch.dict(win_snmp.__salt__, {'reg.set_value': mock_value}), \
mock_false = MagicMock(return_value=False)
with patch.dict(win_snmp.__salt__, {'reg.set_value': mock_true,
'reg.key_exists': mock_false}), \
patch('salt.modules.win_snmp.get_community_names',
MagicMock(return_value=COMMUNITY_NAMES)):
self.assertTrue(win_snmp.set_community_names(**kwargs))
def test_set_community_names_gpo(self):
'''
Test - Manage the SNMP accepted community names and their permissions.
'''
mock_true = MagicMock(return_value=True)
kwargs = {'communities': COMMUNITY_NAMES}
with patch.dict(win_snmp.__salt__, {'reg.set_value': mock_true,
'reg.key_exists': mock_true}), \
patch('salt.modules.win_snmp.get_community_names',
MagicMock(return_value=COMMUNITY_NAMES)):
self.assertRaises(CommandExecutionError, win_snmp.set_community_names, **kwargs)