Merge pull request #51277 from garethgreenaway/merge-2019.2

[2019.2] Merge forward from 2018.3 to 2019.2
This commit is contained in:
Pedro Algarvio 2019-01-23 07:01:29 +00:00 committed by GitHub
commit 8596ee45a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 113 additions and 19 deletions

View file

@ -87,6 +87,13 @@ the context into the included file is required:
.. code-block:: jinja
{% from 'lib.sls' import test with context %}
Includes must use full paths, like so:
.. code-block:: jinja
:caption: spam/eggs.jinja
{% include 'spam/foobar.jinja' %}
Including Context During Include/Import
---------------------------------------

View file

@ -19,8 +19,7 @@ The firewall configuration is generated by Capirca_.
.. _Capirca: https://github.com/google/capirca
Capirca is not yet available on PyPI threrefore it has to be installed
directly form Git: ``pip install -e git+git@github.com:google/capirca.git#egg=aclgen``.
To install Capirca, execute: ``pip install capirca``.
'''
from __future__ import absolute_import, print_function, unicode_literals
@ -34,7 +33,10 @@ log = logging.getLogger(__file__)
# Import third party libs
from salt.ext import six
try:
import aclgen
import capirca
import capirca.aclgen
import capirca.lib.policy
import capirca.lib.aclgenerator
HAS_CAPIRCA = True
except ImportError:
HAS_CAPIRCA = False
@ -69,10 +71,12 @@ def __virtual__():
# module globals
# ------------------------------------------------------------------------------
# define the default values for all possible term fields
# we could also extract them from the `policy` module, inspecting the `Policy`
# class, but that might be overkill & it would make the code less obvious.
# we can revisit this later if necessary.
_TERM_FIELDS = {
'action': [],
'address': [],
@ -161,7 +165,19 @@ _SERVICES = {}
if HAS_CAPIRCA:
class _Policy(aclgen.policy.Policy):
_TempTerm = capirca.lib.policy.Term
def _add_object(self, obj):
return
setattr(_TempTerm, 'AddObject', _add_object)
dumy_term = _TempTerm(None)
for item in dir(dumy_term):
if hasattr(item, '__func__') or item.startswith('_') or item != item.lower():
continue
_TERM_FIELDS[item] = getattr(dumy_term, item)
class _Policy(capirca.lib.policy.Policy):
'''
Extending the Capirca Policy class to allow inserting custom filters.
'''
@ -169,7 +185,7 @@ if HAS_CAPIRCA:
self.filters = []
self.filename = ''
class _Term(aclgen.policy.Term):
class _Term(capirca.lib.policy.Term):
'''
Extending the Capirca Term class to allow setting field valued on the fly.
'''
@ -186,10 +202,10 @@ def _import_platform_generator(platform):
for a class inheriting the `ACLGenerator` class.
'''
log.debug('Using platform: {plat}'.format(plat=platform))
for mod_name, mod_obj in inspect.getmembers(aclgen):
for mod_name, mod_obj in inspect.getmembers(capirca.aclgen):
if mod_name == platform and inspect.ismodule(mod_obj):
for plat_obj_name, plat_obj in inspect.getmembers(mod_obj): # pylint: disable=unused-variable
if inspect.isclass(plat_obj) and issubclass(plat_obj, aclgen.aclgenerator.ACLGenerator):
if inspect.isclass(plat_obj) and issubclass(plat_obj, capirca.lib.aclgenerator.ACLGenerator):
log.debug('Identified Capirca class {cls} for {plat}'.format(
cls=plat_obj,
plat=platform))
@ -366,7 +382,11 @@ def _clean_term_opts(term_opts):
# IP-type fields need to be transformed
ip_values = []
for addr in value:
ip_values.append(aclgen.policy.nacaddr.IP(addr))
if six.PY2:
addr = six.text_type(addr)
# Adding this, as ipaddress would complain about valid
# addresses not being valid. #pythonIsFun
ip_values.append(capirca.lib.policy.nacaddr.IP(addr))
value = ip_values[:]
clean_opts[field] = value
return clean_opts
@ -427,7 +447,7 @@ def _merge_list_of_dict(first, second, prepend=True):
if first and not second:
return first
# Determine overlaps
# So we don't change the position of the existing terms/filters
# So we dont change the position of the existing terms/filters
overlaps = []
merged = []
appended = []
@ -514,7 +534,7 @@ def _get_policy_object(platform,
continue # go to the next filter
filter_name = filter_.keys()[0]
filter_config = filter_.values()[0]
header = aclgen.policy.Header() # same header everywhere
header = capirca.lib.policy.Header() # same header everywhere
target_opts = [
platform,
filter_name
@ -524,7 +544,7 @@ def _get_policy_object(platform,
filter_options = _make_it_list({}, filter_name, filter_options)
# make sure the filter options are sent as list
target_opts.extend(filter_options)
target = aclgen.policy.Target(target_opts)
target = capirca.lib.policy.Target(target_opts)
header.AddObject(target)
filter_terms = []
for term_ in filter_config.get('terms', []):

View file

@ -226,6 +226,7 @@ def _resolve_user_group_names(opts):
if _info and _param in _info:
_id = _info[_param]
opts[ind] = _param + '=' + six.text_type(_id)
opts[ind] = opts[ind].replace('\\040', '\\ ')
return opts
@ -729,7 +730,7 @@ def set_fstab(
'name': name,
'device': device.replace('\\ ', '\\040'),
'fstype': fstype,
'opts': opts,
'opts': opts.replace('\\ ', '\\040'),
'dump': dump,
'pass_num': pass_num,
}

View file

@ -19,6 +19,8 @@ The firewall configuration is generated by Capirca_.
.. _Capirca: https://github.com/google/capirca
To install Capirca, execute: ``pip install capirca``.
To be able to load configuration on network devices,
it requires NAPALM_ library to be installed: ``pip install napalm``.
Please check Installation_ for complete details.
@ -34,7 +36,10 @@ log = logging.getLogger(__file__)
# Import third party libs
try:
# pylint: disable=W0611
import aclgen
import capirca
import capirca.aclgen
import capirca.lib.policy
import capirca.lib.aclgenerator
HAS_CAPIRCA = True
# pylint: enable=W0611
except ImportError:

View file

@ -2675,6 +2675,7 @@ def managed(name,
ret, 'Defaults must be formed as a dict')
if not replace and os.path.exists(name):
ret_perms = {}
# Check and set the permissions if necessary
if salt.utils.platform.is_windows():
ret = __salt__['file.check_perms'](
@ -2686,10 +2687,19 @@ def managed(name,
inheritance=win_inheritance,
reset=win_perms_reset)
else:
ret, _ = __salt__['file.check_perms'](
ret, ret_perms = __salt__['file.check_perms'](
name, ret, user, group, mode, attrs, follow_symlinks)
if __opts__['test']:
ret['comment'] = 'File {0} not updated'.format(name)
if isinstance(ret_perms, dict) and \
'lmode' in ret_perms and \
mode != ret_perms['lmode']:
ret['comment'] = ('File {0} will be updated with permissions '
'{1} from its current '
'state of {2}'.format(name,
mode,
ret_perms['lmode']))
else:
ret['comment'] = 'File {0} not updated'.format(name)
elif not ret['changes'] and ret['result']:
ret['comment'] = ('File {0} exists with proper permissions. '
'No changes made.'.format(name))

View file

@ -3,7 +3,7 @@
Network ACL
===========
Manage the firewall configuration on the network device namaged through NAPALM.
Manage the firewall configuration on the network device managed through NAPALM.
The firewall configuration is generated by Capirca_.
.. _Capirca: https://github.com/google/capirca
@ -18,7 +18,13 @@ The firewall configuration is generated by Capirca_.
Dependencies
------------
Capirca: ``pip install -e git+git@github.com:google/capirca.git#egg=aclgen``
Capirca
~~~~~~~
To install Capirca, execute: ``pip install capirca``.
NAPALM
~~~~~~
To be able to load configuration on network devices,
it requires NAPALM_ library to be installed: ``pip install napalm``.
@ -35,7 +41,10 @@ log = logging.getLogger(__file__)
# Import third party libs
try:
# pylint: disable=W0611
import aclgen
import capirca
import capirca.aclgen
import capirca.lib.policy
import capirca.lib.aclgenerator
HAS_CAPIRCA = True
# pylint: enable=W0611
except ImportError:

View file

@ -270,6 +270,8 @@ def state(name,
cmd_kw['tgt_type'] = tgt_type
cmd_kw['ssh'] = ssh
if 'roster' in kwargs:
cmd_kw['roster'] = kwargs['roster']
cmd_kw['expect_minions'] = expect_minions
if highstate:
fun = 'state.highstate'

View file

@ -149,7 +149,7 @@ def nodegroup_comp(nodegroup, nodegroups, skip=None, first_call=True):
# No compound operators found in nodegroup definition. Check for
# group type specifiers
group_type_re = re.compile('^[A-Z]@')
regex_chars = ['(', '[', '{', '\\', '?''}])']
regex_chars = ['(', '[', '{', '\\', '?', '}', ']', ')']
if not [x for x in ret if '*' in x or group_type_re.match(x)]:
# No group type specifiers and no wildcards.
# Treat this as an expression.

View file

@ -786,6 +786,28 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
(name, user=user, group=group),
ret)
if salt.utils.platform.is_windows():
mock_ret = MagicMock(return_value=ret)
comt = ('File {0} not updated'.format(name))
else:
perms = {'luser': user,
'lmode': '0644',
'lgroup': group}
mock_ret = MagicMock(return_value=(ret, perms))
comt = ('File {0} will be updated with '
'permissions 0400 from its current '
'state of 0644'.format(name))
with patch.dict(filestate.__salt__,
{'file.check_perms': mock_ret}):
with patch.object(os.path, 'exists', mock_t):
with patch.dict(filestate.__opts__, {'test': True}):
ret.update({'comment': comt})
self.assertDictEqual(filestate.managed
(name, user=user,
group=group,
mode=400), ret)
# 'directory' function tests: 1
def test_directory(self):

View file

@ -282,6 +282,24 @@ class SaltmodTestCase(TestCase, LoaderModuleMockMixin):
with patch.dict(saltmod.__salt__, {'saltutil.wheel': wheel_mock}):
self.assertDictEqual(saltmod.wheel(name), ret)
def test_state_ssh(self):
'''
Test saltmod passes roster to saltutil.cmd
'''
origcmd = saltmod.__salt__['saltutil.cmd']
cmd_kwargs = {}
cmd_args = []
def cmd_mock(*args, **kwargs):
cmd_args.extend(args)
cmd_kwargs.update(kwargs)
return origcmd(*args, **kwargs)
with patch.dict(saltmod.__salt__, {'saltutil.cmd': cmd_mock}):
ret = saltmod.state('state.sls', tgt='*', ssh=True, highstate=True, roster='my_roster')
assert 'roster' in cmd_kwargs
assert cmd_kwargs['roster'] == 'my_roster'
@skipIf(NO_MOCK, NO_MOCK_REASON)
class StatemodTests(TestCase, LoaderModuleMockMixin):