-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
269 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
"""Module to maintain ietf:snmp. | ||
:codeauthor: Criteo Network team | ||
:maturity: new | ||
:platform: SONiC, Arista EOS, Juniper JunOS | ||
""" | ||
|
||
import logging | ||
|
||
from salt.exceptions import CommandExecutionError | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
def __virtual__(): | ||
return _get_os() in ["eos", "junos", "sonic"] | ||
|
||
|
||
## | ||
# Some utils | ||
## | ||
|
||
|
||
def _get_os(): | ||
return __salt__["grains.get"]("nos", __salt__["grains.get"]("os")) | ||
|
||
|
||
def _apply_template(template_name, context, saltenv): | ||
"""Define a helper to generate config from template file.""" | ||
template_content = __salt__["cp.get_file_str"](template_name, saltenv=saltenv) | ||
context["deep_get"] = __utils__["jinja_filters.deep_get"] | ||
|
||
if not template_content: | ||
raise CommandExecutionError("Unable to get {}".format(template_name)) | ||
|
||
result = __salt__["file.apply_template_on_contents"]( | ||
contents=template_content, | ||
template="jinja", | ||
context=context, | ||
defaults=None, | ||
saltenv=saltenv, | ||
) | ||
|
||
return "\n".join([line for line in result.splitlines() if line.strip() != ""]) | ||
|
||
|
||
def _generate_snmp_config(ietfconfig, _, saltenv): | ||
# TODO: handle when no data | ||
os = _get_os() | ||
config = _apply_template( | ||
"salt://states/afk/templates/snmp/{}/snmp.j2".format(os), | ||
ietfconfig, | ||
saltenv, | ||
) | ||
|
||
return config | ||
|
||
|
||
def apply(name, ietfconfig=None, saltenv="base"): | ||
"""Apply and maintain Routing Policies configuration from openconfig format (JSON is expected). | ||
.. warning:: | ||
Be careful with dry run, in some conditions napalm apply the config instead of | ||
discarding it. | ||
Did not find the root cause yet. | ||
:param name: name of the task | ||
:param openconfig_routing_policy: Routing Policy configuration in JSON in openconfig | ||
(routing-policy) | ||
:param openconfig_bgp: BGP configuration in JSON in openconfig (bgp) | ||
:param saltenv: salt environment | ||
""" | ||
ret = {"name": name, "result": False, "changes": {}, "comment": []} | ||
|
||
# generate command to apply on the device using the templates | ||
log.debug("%s starting", name) | ||
|
||
# get candidate config | ||
config = _generate_snmp_config(ietfconfig, False, saltenv) | ||
|
||
nos = _get_os() | ||
|
||
if nos in ["eos", "junos"]: | ||
# only return generated commands/config during tests | ||
# there is an ongoing bug with napalm making dry-run really applying the config sometimes | ||
if __opts__["test"]: | ||
ret["result"] = None | ||
return ret | ||
|
||
res = __salt__["net.load_config"]( | ||
text=config, | ||
test=__opts__["test"], | ||
debug=True, | ||
) | ||
elif nos == "sonic": | ||
# TODO: modify .managed to support pushing raw config without template | ||
res = __salt__["sonic.snmp"]( | ||
template_name="salt://templates/snmp.j2", | ||
context={"raw": config}, | ||
push_only_if_changes=True, | ||
test=__opts__["test"], | ||
) | ||
res["diff"] = res["changes"] | ||
|
||
ret["comment"].append("- loaded:\n{}".format(config)) | ||
ret["comment"].append(res["comment"]) | ||
if res["diff"]: | ||
ret["changes"] = {"diff": res["diff"]} | ||
ret["result"] = res["result"] | ||
|
||
return ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
snmp-server contact {{ system.contact }} | ||
snmp-server location {{ system.location }} | ||
{% for community in snmp.community %} | ||
{% if community['security-name'] == "readonly" %} | ||
snmp-server community {{ community['text-name'] }} ro | ||
{% elif community['security-name'] == "readwrite" %} | ||
snmp-server community {{ community['text-name'] }} rw | ||
{% endif %} | ||
{% endfor %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
snmp { | ||
location "{{ system.location }}"; | ||
contact "{{ system.contact }}"; | ||
{% for community in snmp.community %} | ||
{% if community['security-name'] == "readonly" %} | ||
community {{ community['text-name'] }} { | ||
authorization read-only; | ||
} | ||
{% elif community['security-name'] == "readwrite" %} | ||
community {{ community['text-name'] }} { | ||
authorization read-write; | ||
} | ||
{%- endif %} | ||
{%- endfor %} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{% for community in snmp.community %} | ||
{% if community['security-name'] == "readonly" %} | ||
snmp_rocommunity: {{ community['text-name'] }} | ||
{% endif %} | ||
{% endfor %} | ||
snmp_location: {{ system.location }} | ||
snmp_contact: {{ system.contact }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
"""integration test of ietf_snmp for eos.""" | ||
|
||
import _states as STATE_MOD |
4 changes: 4 additions & 0 deletions
4
tests/states/ietf_snmp/data/integration_tests/full_config/expected_result_eos.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
snmp-server contact prod-network | ||
snmp-server location DC1;01.00 | ||
snmp-server community communityro ro | ||
snmp-server community communityrw rw |
10 changes: 10 additions & 0 deletions
10
tests/states/ietf_snmp/data/integration_tests/full_config/expected_result_junos.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
snmp { | ||
location "DC1;01.00"; | ||
contact "prod-network"; | ||
community communityro { | ||
authorization read-only; | ||
} | ||
community communityrw { | ||
authorization read-write; | ||
} | ||
} |
3 changes: 3 additions & 0 deletions
3
tests/states/ietf_snmp/data/integration_tests/full_config/expected_result_sonic.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
snmp_rocommunity: communityro | ||
snmp_location: DC1;01.00 | ||
snmp_contact: prod-network |
20 changes: 20 additions & 0 deletions
20
tests/states/ietf_snmp/data/integration_tests/full_config/ietf.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"snmp":{ | ||
"community":[ | ||
{ | ||
"index":"global_ro", | ||
"security-name":"readonly", | ||
"text-name":"communityro" | ||
}, | ||
{ | ||
"index":"globalrw", | ||
"security-name":"readwrite", | ||
"text-name":"communityrw" | ||
} | ||
] | ||
}, | ||
"system":{ | ||
"contact":"prod-network", | ||
"location":"DC1;01.00" | ||
} | ||
} |
Empty file.
87 changes: 87 additions & 0 deletions
87
tests/states/ietf_snmp/integration_tests/test_ietf_integration.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
"""integration test of ietf_snmp for eos.""" | ||
|
||
import functools | ||
import json | ||
import pytest | ||
|
||
import _states.ietf_snmp as STATE_MOD | ||
from _utils import frr_detect_diff, jinja_filters | ||
from jinja2 import BaseLoader, Environment | ||
|
||
## | ||
# Tests setup | ||
## | ||
|
||
|
||
def _get_data_and_expected_result(os_name): | ||
test_path = "tests/states/ietf_snmp/data/integration_tests/full_config" | ||
with open( | ||
f"{test_path}/ietf.json", | ||
encoding="utf-8", | ||
) as fd: | ||
fake_data = json.load(fd) | ||
|
||
with open( | ||
f"{test_path}/expected_result_{os_name}.txt", | ||
encoding="utf-8", | ||
) as fd: | ||
expected_result = fd.read() | ||
|
||
return fake_data, expected_result | ||
|
||
|
||
def _mock_apply_template_on_contents(contents, template, context, *_, **__): | ||
assert template == "jinja" | ||
loader = Environment(loader=BaseLoader) | ||
template = loader.from_string(contents) | ||
return template.render(**context) | ||
|
||
|
||
def _mock_get_file_str(template_name, *_, **__): | ||
# removing salt:// prefix in path file | ||
template_name = template_name[7:] | ||
with open(template_name, encoding="utf-8") as fd: | ||
content = fd.read() | ||
return content | ||
|
||
|
||
def _apply_common_mock(): | ||
STATE_MOD.__salt__ = { | ||
"file.apply_template_on_contents": _mock_apply_template_on_contents, | ||
"cp.get_file_str": _mock_get_file_str, | ||
"eos.get_bgp_config": lambda *_: (""), | ||
} | ||
STATE_MOD.__utils__ = { | ||
"frr_detect_diff.get_objects": frr_detect_diff.get_objects, | ||
"jinja_filters.format_route_policy_name": jinja_filters.format_route_policy_name, | ||
"jinja_filters.deep_get": jinja_filters.deep_get, | ||
} | ||
|
||
|
||
def _mock_then_clean(func): | ||
@functools.wraps(func) | ||
def wrapper(mocker, *args, **kwargs): | ||
# some mocking | ||
_apply_common_mock() | ||
try: | ||
return func(mocker, *args, **kwargs) | ||
finally: | ||
# some cleaning | ||
del STATE_MOD.__salt__ | ||
|
||
return wrapper | ||
|
||
|
||
## | ||
# Tests | ||
## | ||
|
||
|
||
@pytest.mark.parametrize("os", ["eos", "junos", "sonic"]) | ||
@_mock_then_clean | ||
def test_apply__generate_routing_policy_config__full_config(mocker, os): # pylint: disable=W0613 | ||
"""Test the entire config generation with full and valid config for eos.""" | ||
|
||
mocker.patch("_states.ietf_snmp._get_os", return_value=os) | ||
fake_data, expected_result = _get_data_and_expected_result(os) | ||
assert STATE_MOD._generate_snmp_config(fake_data, None, saltenv="base") == expected_result |