Skip to content
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ ci:

repos:
- repo: https://github.com/ansible-network/collection_prep
rev: 1.1.1
rev: 1.1.2
hooks:
- id: update-docs
additional_dependencies:
- "ansible-core==2.18.*"

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ compatibility with older versions of VyOS are maintained but not guaranteed.
<!--start requires_ansible-->
## Ansible version compatibility

This collection has been tested against following Ansible versions: **>=2.15.0**.
This collection has been tested against the following Ansible versions: **>=2.15.0**.

For collections that support Ansible 2.9, please ensure you update your `network_os` to use the
fully qualified collection name (for example, `cisco.ios.ios`).
Plugins and modules within a collection may be tested with only specific Ansible versions.
A collection may contain metadata that identifies these versions.
PEP440 is the schema used to describe the versions of Ansible.
Expand Down
3 changes: 3 additions & 0 deletions changelogs/fragments/t6823_ipv6_autoconf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
bugfixes:
- vyos_l3_interfaces - ipv6 auto-config option incorrectly set
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def execute_module(self):
commands = list()

if self.state in self.ACTION_STATES:
existing_l3_interfaces_facts = self.get_l3_interfaces_facts()
existing_l3_interfaces_facts = self.mutate_autoconfig(self.get_l3_interfaces_facts())
else:
existing_l3_interfaces_facts = []

Expand All @@ -96,16 +96,19 @@ def execute_module(self):
result["commands"] = commands

if self.state in self.ACTION_STATES or self.state == "gathered":
changed_l3_interfaces_facts = self.get_l3_interfaces_facts()
changed_l3_interfaces_facts = self.mutate_autoconfig(self.get_l3_interfaces_facts())
elif self.state == "rendered":
result["rendered"] = commands
elif self.state == "parsed":
running_config = self._module.params["running_config"]

if not running_config:
self._module.fail_json(
msg="value of running_config parameter must not be empty for state parsed",
)
result["parsed"] = self.get_l3_interfaces_facts(data=running_config)
result["parsed"] = self.mutate_autoconfig(
self.get_l3_interfaces_facts(data=running_config),
)
else:
changed_l3_interfaces_facts = []

Expand All @@ -129,6 +132,7 @@ def set_config(self, existing_l3_interfaces_facts):
"""
want = self._module.params["config"]
have = existing_l3_interfaces_facts

resp = self.set_state(want, have)
return to_list(resp)

Expand Down Expand Up @@ -174,6 +178,7 @@ def set_state(self, want, have):
elif state == "replaced":
commands.extend(self._state_replaced(item, obj_in_have))

commands = [command.replace("auto-config", "autoconf") for command in commands]
return commands

def _state_replaced(self, want, have):
Expand Down Expand Up @@ -247,7 +252,6 @@ def _state_merged(self, want, have):
vif=want_vif["vlan_id"],
),
)

return commands

def _state_deleted(self, want, have):
Expand All @@ -261,51 +265,73 @@ def _state_deleted(self, want, have):
want_copy = deepcopy(remove_empties(want))
have_copy = deepcopy(have)

want_vifs = want_copy.pop("vifs", [])
have_vifs = have_copy.pop("vifs", [])

for update in self._get_updates(have_copy, want_copy):
for key, value in iteritems(update):
if have_copy is not None:
if all(v in (None, {}, []) for k, v in want_copy.items() if k != "name"):
commands.append(
self._compute_commands(
key=key,
value=value,
key=None,
value=None,
interface=want_copy["name"],
remove=True,
),
)

if have_vifs:
for have_vif in have_vifs:
want_vif = search_obj_in_list(have_vif["vlan_id"], want_vifs, key="vlan_id")
if not want_vif:
want_vif = {"vlan_id": have_vif["vlan_id"]}

for update in self._get_updates(have_vif, want_vif):
for key, value in iteritems(update):
commands.append(
self._compute_commands(
key=key,
interface=want_copy["name"],
value=value,
vif=want_vif["vlan_id"],
remove=True,
),
)
return commands

want_vifs = want_copy.pop("vifs", [])
have_vifs = have_copy.pop("vifs", [])

if have_vifs:
for have_vif in have_vifs:
want_vif = search_obj_in_list(have_vif["vlan_id"], want_vifs, key="vlan_id")
if not want_vif:
want_vif = {"vlan_id": have_vif["vlan_id"]}

for update in self._get_updates(have_vif, want_vif):
for key, value in iteritems(update):
commands.append(
self._compute_commands(
key=key,
interface=want_copy["name"],
value=value,
vif=want_vif["vlan_id"],
remove=True,
),
)

for update in self._get_updates(have_copy, want_copy):
for key, value in iteritems(update):
commands.append(
self._compute_commands(
key=key,
value=value,
interface=want_copy["name"],
remove=True,
),
)

return commands

def _compute_commands(self, interface, key, vif=None, value=None, remove=False):
intf_context = "interfaces {0} {1}".format(get_interface_type(interface), interface)
if value == "auto-config" and vif is None:
intf_context = "interfaces {0} {1} ipv6".format(
get_interface_type(interface),
interface,
)
else:
intf_context = "interfaces {0} {1}".format(get_interface_type(interface), interface)

set_cmd = "set {0}".format(intf_context)
del_cmd = "delete {0}".format(intf_context)

if vif:
set_cmd = set_cmd + (" vif {0}".format(vif))
del_cmd = del_cmd + (" vif {0}".format(vif))
suffix = " ipv6" if value == "auto-config" else ""
set_cmd += f" vif {vif}{suffix}"
del_cmd += f" vif {vif}{suffix}"

if remove:
if remove and key and value:
command = "{0} {1} '{2}'".format(del_cmd, key, value)
elif remove and not (key and value):
command = "{0}".format(del_cmd)
else:
command = "{0} {1} '{2}'".format(set_cmd, key, value)

Expand All @@ -318,3 +344,12 @@ def _get_updates(self, want, have):
updates.extend(diff_list_of_dicts(want.get("ipv6", []), have.get("ipv6", [])))

return updates

def mutate_autoconfig(self, obj):
if isinstance(obj, dict):
return dict(map(lambda kv: (kv[0], self.mutate_autoconfig(kv[1])), obj.items()))
if isinstance(obj, list):
return list(map(self.mutate_autoconfig, obj))
if isinstance(obj, str):
return obj.replace("autoconf", "auto-config")
return obj
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
set interfaces ethernet eth0 ipv6 address 'autoconf'
set interfaces ethernet eth1 address '192.0.2.10/24'
set interfaces ethernet eth1 vif 102 ipv6 address 'autoconf'
set interfaces ethernet eth1 address '2001:db8::10/32'
set interfaces ethernet eth1 hw-id '08:00:27:da:67:43'
set interfaces ethernet eth2 address '198.51.100.10/24'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
---
- name: Remove Config
vars:
lines: "delete interfaces ethernet \"{{ intf }}\" address\ndelete interfaces ethernet \"{{ intf }}\" vif\n"
lines: "delete interfaces ethernet \"{{ intf }}\" address\ndelete interfaces ethernet \"{{ intf }}\" vif\ndelete interfaces ethernet \"{{ intf }}\" ipv6\n"
loop:
- eth1
- eth2
loop_control:
loop_var: intf
ansible.netcommon.cli_config:
config: "{{ lines }}"

- name: Reset eth0 ipv6 autoconf
vars:
lines: |-
delete interfaces ethernet eth0 ipv6
ansible.netcommon.cli_config:
config: "{{ lines }}"
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
vyos.vyos.vyos_l3_interfaces: &id001
config:
- name: eth1

- name: eth2
state: deleted

Expand Down Expand Up @@ -42,5 +41,42 @@
assert:
that:
- "{{ deleted['after'] | symmetric_difference(result['before']) |length == 0 }}"

- name: Prepare delete test for SLAAC auto-config
vyos.vyos.vyos_l3_interfaces:
config:
- name: eth1
ipv6:
- address: auto-config
- name: eth2
vifs:
- vlan_id: 101
ipv6:
- address: auto-config
state: replaced

- name: Delete SLACC auto-config of given interfaces
register: result
vyos.vyos.vyos_l3_interfaces:
config:
- name: eth1
- name: eth2
state: deleted

- name: Assert that the before dicts were correctly generated (SLAAC)
assert:
that:
- "{{ deleted['before_slaac'] | symmetric_difference(result['before']) |length == 0 }}"

- name: Assert that the correct set of commands were generated (SLAAC)
assert:
that:
- "{{ deleted['commands'] | symmetric_difference(result['commands']) |length == 0 }}"

- name: Assert that the after dicts were correctly generated (SLAAC)
assert:
that:
- "{{ deleted['after'] | symmetric_difference(result['after']) |length == 0 }}"

always:
- include_tasks: _remove_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,40 @@
assert:
that:
- result['changed'] == false

- name: Merge the provided configuration for SLAAC tesitng
register: result
vyos.vyos.vyos_l3_interfaces:
config:
- name: eth0
ipv6:
- address: auto-config
- name: eth1
vifs:
- vlan_id: 102
ipv6:
- address: auto-config
state: merged

- name: Gather the provided configuration with the existing running configuration
register: result
vyos.vyos.vyos_l3_interfaces: &id002
config:
state: gathered

- name: Assert that gathered dicts was correctly generated for SLAAC
assert:
that:
- "{{ populate_slaac | symmetric_difference(result['gathered']) |length == 0 }}"

- name: Gather the existing running configuration for SLAAC (IDEMPOTENT)
register: result
vyos.vyos.vyos_l3_interfaces: *id002

- name: Assert that the previous task was idempotent
assert:
that:
- result['changed'] == false

always:
- include_tasks: _remove_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@
register: result
vyos.vyos.vyos_l3_interfaces: &id001
config:
- name: eth0
ipv6:
- address: auto-config
- name: eth1
ipv4:
- address: 192.0.2.10/24
ipv6:
- address: 2001:db8::10/32
vifs:
- vlan_id: 102
ipv6:
- address: auto-config

- name: eth2
ipv4:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
- name: eth1
ipv4:
- address: 192.0.2.15/24
vifs:
- vlan_id: 102
ipv6:
- address: auto-config

- name: eth2
ipv6:
- address: auto-config
state: overridden

- name: Assert that before dicts were correctly generated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,29 @@
register: result
vyos.vyos.vyos_l3_interfaces: &id001
config:
- name: eth0
ipv6:
- address: auto-config
- name: eth1
ipv4:
- address: 192.0.2.14/24
vifs:
- vlan_id: 102
ipv6:
- address: auto-config
- name: eth2
ipv4:
- address: 192.0.2.10/24
- address: 192.0.2.11/24
ipv6:
- address: 2001:db8::10/32
- address: 2001:db8::12/32
vifs:
- vlan_id: 101
ipv4:
- address: 198.51.100.130/25
ipv6:
- address: 2001:db8::20/32
state: rendered

- name: Assert that correct set of commands were generated
Expand Down
Loading
Loading