Skip to content

Commit

Permalink
Implement interface_lagg module
Browse files Browse the repository at this point in the history
  • Loading branch information
jiuka committed Sep 18, 2024
1 parent 9b4c34f commit 65cfd36
Show file tree
Hide file tree
Showing 13 changed files with 354 additions and 5 deletions.
2 changes: 1 addition & 1 deletion docs/source/modules/2_list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ In most cases the returned type of this module ist a list of dictionaries.
:header: "Parameter", "Type", "Required", "Default", "Aliases", "Comment"
:widths: 15 10 10 10 10 45

"target","string","true","\-","tgt, t","What part of the running config should be queried/listed. One of: 'alias', 'rule', 'route', 'cron', 'syslog', 'package', 'unbound_general', 'unbound_acl', 'unbound_host', 'unbound_domain', 'unbound_dot', 'unbound_forward', 'unbound_host_alias', 'ipsec_cert', 'shaper_pipe', 'shaper_queue', 'shaper_rule', 'monit_service', 'monit_test', 'monit_alert', 'wireguard_server', 'wireguard_peer', 'interface_vlan', 'interface_vxlan', 'source_nat', 'frr_bfd', 'frr_bgp_general', 'frr_bgp_neighbor', 'frr_bgp_prefix_list', 'frr_bgp_community_list', 'frr_bgp_as_path', 'frr_bgp_route_map', 'frr_ospf_general', 'frr_ospf_prefix_list', 'frr_ospf_interface', 'frr_ospf_route_map', 'frr_ospf_network', 'frr_ospf3_general', 'frr_ospf3_interface', 'frr_rip', 'bind_general', 'bind_blocklist', 'bind_acl', 'bind_domain', 'bind_record', 'interface_vip', 'webproxy_general', 'webproxy_cache', 'webproxy_parent', 'webproxy_traffic', 'webproxy_forward', 'webproxy_acl', 'webproxy_icap', 'webproxy_auth', 'webproxy_remote_acl', 'webproxy_pac_proxy', 'webproxy_pac_match', 'webproxy_pac_rule'"
"target","string","true","\-","tgt, t","What part of the running config should be queried/listed. One of: 'alias', 'rule', 'route', 'cron', 'syslog', 'package', 'unbound_general', 'unbound_acl', 'unbound_host', 'unbound_domain', 'unbound_dot', 'unbound_forward', 'unbound_host_alias', 'ipsec_cert', 'shaper_pipe', 'shaper_queue', 'shaper_rule', 'monit_service', 'monit_test', 'monit_alert', 'wireguard_server', 'wireguard_peer', 'interface_lagg', 'interface_vlan', 'interface_vxlan', 'source_nat', 'frr_bfd', 'frr_bgp_general', 'frr_bgp_neighbor', 'frr_bgp_prefix_list', 'frr_bgp_community_list', 'frr_bgp_as_path', 'frr_bgp_route_map', 'frr_ospf_general', 'frr_ospf_prefix_list', 'frr_ospf_interface', 'frr_ospf_route_map', 'frr_ospf_network', 'frr_ospf3_general', 'frr_ospf3_interface', 'frr_rip', 'bind_general', 'bind_blocklist', 'bind_acl', 'bind_domain', 'bind_record', 'interface_vip', 'webproxy_general', 'webproxy_cache', 'webproxy_parent', 'webproxy_traffic', 'webproxy_forward', 'webproxy_acl', 'webproxy_icap', 'webproxy_auth', 'webproxy_remote_acl', 'webproxy_pac_proxy', 'webproxy_pac_match', 'webproxy_pac_rule'"

.. include:: ../_include/param_basic.rst

Expand Down
2 changes: 1 addition & 1 deletion docs/source/modules/2_reload.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Definition
:header: "Parameter", "Type", "Required", "Default", "Aliases", "Comment"
:widths: 15 10 10 10 10 45

"target","string","true","\-","tgt, t","What part of the running config should be reloaded. One of: 'alias', 'rule', 'route', 'cron', 'unbound', 'syslog', 'ipsec', 'ipsec_legacy', 'shaper', 'monit', 'wireguard', 'interface_vlan', 'interface_vxlan', 'interface_vip', 'frr', 'webproxy', 'bind', 'ids'"
"target","string","true","\-","tgt, t","What part of the running config should be reloaded. One of: 'alias', 'rule', 'route', 'cron', 'unbound', 'syslog', 'ipsec', 'ipsec_legacy', 'shaper', 'monit', 'wireguard', 'interface_vlan', 'interface_vxlan', 'interface_vip', 'interface_lagg', 'frr', 'webproxy', 'bind', 'ids'"

.. include:: ../_include/param_basic.rst

Expand Down
84 changes: 84 additions & 0 deletions docs/source/modules/interface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ ansibleguy.opnsense.interface_vip
This module manages VIP configuration that can be found in the WEB-UI menu: 'Interfaces - Virtual IPs - Settings'


ansibleguy.opnsense.interface_lagg
===================================

This module manages LAGG configuration that can be found in the WEB-UI menu: 'Interfaces - Other Types - LAGG'


Definition
**********

Expand Down Expand Up @@ -95,6 +101,31 @@ ansibleguy.opnsense.interface_vip
"reload","boolean","false","true","\-", .. include:: ../_include/param_reload.rst


ansibleguy.opnsense.interface_lagg
=================================

.. warning::

This feature is only available in OPNSense version >= 23.7

.. csv-table:: Definition
:header: "Parameter", "Type", "Required", "Default", "Aliases", "Comment"
:widths: 15 10 10 10 10 45

"match_fields","list","false","['members']","\-","Fields that are used to match configured LAGG with the running config - if any of those fields are changed, the module will think it's a new entry. At least one of: 'device', 'members', 'primary_member', 'proto', 'description'"
"device", "string", "false", "\-", "laggif", "Optional 'device' of the entry. Needs to start with 'lagg'"
"members", "list", "false", "\-", "port, int, if", "Existing LAGG capable interface - you must provide the network port as shown in 'Interfaces - Assignments - Network port'"
"primary_member", "string", "false", "\-", "\-", "This interface will be added first in the lagg making it the primary one - you must provide the network port as shown in 'Interfaces - Assignments - Network port'"
"proto", "string", "false", "lacp", "p", "The protocol to use. One of: 'none', 'lacp', 'failover', 'fec', 'loadbalance', 'roundrobin'"
"lacp_fast_timeout", "boolean", "false", "false", "\-", "Enable lacp fast-timeout on the interface."
"use_flowid", "string", "false", "\-", "\-", "Use the RSS hash from the network card if available, otherwise a hash is locally calculated. The default depends on the system tunable in net.link.lagg.default_use_flowid. One of: 'default', 'yes', 'no'"
"lagghash", "list", "false", "['l2']", "\-", "Set the packet layers to hash for aggregation protocols which load balance. At least one of: 'l2', 'l3', 'l4'"
"lacp_strict", "string", "false", "\-", "\-", "Enable lacp strict compliance on the interface. The default depends on the system tunable in net.link.lagg.lacp.default_strict_mode. One of: 'default', 'yes', 'no'"
"mtu", "integer", "false", "false", "\-", "If you leave this field blank, the smallest mtu of this laggs children will be used."
"description","string","true","\-","desc, name","The description used to match the configured entries to the existing ones"
"reload","boolean","false","true","\-", .. include:: ../_include/param_reload.rst


Examples
********

Expand Down Expand Up @@ -247,3 +278,56 @@ ansibleguy.opnsense.interface_vip
interface: 'opt1'
address: '192.168.0.100/24'
state: 'absent'
ansibleguy.opnsense.interface_lagg
=================================

.. code-block:: yaml
- hosts: localhost
gather_facts: no
module_defaults:
group/ansibleguy.opnsense.all:
firewall: 'opnsense.template.ansibleguy.net'
api_credential_file: '/home/guy/.secret/opn.key'
ansibleguy.opnsense.list:
target: 'interface_lagg'
tasks:
- name: Example
ansibleguy.opnsense.interface_lagg:
# device: lagg0
# description: LACP ax0/1
members:
- ax0
- ax1
# primary_member: ax0
# proto: lacp
# lacp_fast_timeout: 'default'
# use_flowid: 'default'
# lagghash: ['l2']
# lacp_strict: 'default'
# mtu: 9000
# match_fields: ['members']
- name: Adding LAGG
ansibleguy.opnsense.interface_lagg:
members:
- ax0
- ax1
- name: Listing
ansibleguy.opnsense.list:
# target: 'interface_lagg'
register: existing_entries
- name: Printing LAGGs
ansible.builtin.debug:
var: existing_entries.data
- name: Removing LAGG
ansibleguy.opnsense.interface_vip:
device: lagg0
match_fields: ['device']
state: 'absent'
1 change: 1 addition & 0 deletions meta/runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ action_groups:
- ansibleguy.opnsense.interface_vlan
- ansibleguy.opnsense.interface_vxlan
- ansibleguy.opnsense.interface_vip
- ansibleguy.opnsense.interface_lagg
frr:
- ansibleguy.opnsense.frr_diagnostic
- ansibleguy.opnsense.frr_general
Expand Down
53 changes: 53 additions & 0 deletions plugins/module_utils/main/interface_lagg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from ansible.module_utils.basic import AnsibleModule

from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.api import \
Session
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.helper.main import \
validate_int_fields, is_unset
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.cls import BaseModule


class Lagg(BaseModule):
CMDS = {
'add': 'addItem',
'del': 'delItem',
'set': 'setItem',
'search': 'get',
}
API_KEY_PATH = 'lagg.lagg'
API_MOD = 'interfaces'
API_CONT = 'lagg_settings'
API_CMD_REL = 'reconfigure'
FIELDS_CHANGE = ['members', 'primary_member', 'proto', 'lacp_fast_timeout', 'use_flowid', 'lagghash', 'lacp_strict', 'mtu', 'description']
FIELDS_ALL = ['device']
FIELDS_ALL.extend(FIELDS_CHANGE)
FIELDS_TRANSLATE = {
'device': 'laggif',
'description': 'descr',
}
FIELDS_TYPING = {
'bool': ['lacp_fast_timeout'],
'list': ['members', 'lagghash'],
'select': ['members', 'primary_member', 'proto', 'use_flowid', 'lagghash', 'lacp_strict'],
}
INT_VALIDATIONS = {
'mtu': {'min': 576, 'max': 65535},
}
EXIST_ATTR = 'lagg'

def __init__(self, module: AnsibleModule, result: dict, session: Session = None):
BaseModule.__init__(self=self, m=module, r=result, s=session)
self.lagg = {}

def check(self) -> None:
if self.p['state'] == 'present':
if is_unset(self.p['members']):
self.m.fail_json("You need to provide a list of 'members' to create a lagg!")


validate_int_fields(module=self.m, data=self.p, field_minmax=self.INT_VALIDATIONS)

self._base_check()

def update(self) -> None:
self.b.update(enable_switch=False)
107 changes: 107 additions & 0 deletions plugins/modules/interface_lagg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright: (C) 2024, AnsibleGuy <[email protected]>
# GNU General Public License v3.0+ (see https://www.gnu.org/licenses/gpl-3.0.txt)

# see: https://docs.opnsense.org/development/api/core/interfaces.html

from ansible.module_utils.basic import AnsibleModule

from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.handler import \
module_dependency_error, MODULE_EXCEPTIONS

try:
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.helper.wrapper import module_wrapper
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.defaults.main import \
OPN_MOD_ARGS, STATE_ONLY_MOD_ARG, RELOAD_MOD_ARG
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.interface_lagg import Lagg

except MODULE_EXCEPTIONS:
module_dependency_error()


# DOCUMENTATION = 'https://opnsense.ansibleguy.net/en/latest/modules/interface.html'
# EXAMPLES = 'https://opnsense.ansibleguy.net/en/latest/modules/interface.html'


def run_module():
module_args = dict(
device=dict(
type='str', required=False, aliases=['laggif'],
description="Optional 'device' of the entry. Needs to start with 'lagg'",
),
members=dict(
type='list', elements='str', required=False, aliases=['port', 'int', 'if'],
description='Existing LAGG capable interface - you must provide the network '
"port as shown in 'Interfaces - Assignments - Network port'"
),
primary_member=dict(
type='list', elements='str', required=False,
description='This interface will be added first in the lagg making it the primary one '
"- you must provide the network port as shown in 'Interfaces - Assignments - Network port'"
),
proto=dict(
type='str', required=False, aliases=['p'], default='lacp',
choices=['none', 'lacp', 'failover', 'fec', 'loadbalance', 'roundrobin'],
description="The protocol to use."
),
lacp_fast_timeout=dict(type='bool', required=False, default=False,
description='Enable lacp fast-timeout on the interface.'
),
use_flowid=dict(
type='str', required=False, choices=['default', 'yes', 'no'],
description='Use the RSS hash from the network card if available, otherwise a hash is locally calculated. '
'The default depends on the system tunable in net.link.lagg.default_use_flowid.'
),
lagghash=dict(
type='list', elements='str', required=False, default=['l2'],
choices=['l2', 'l3', 'l4'],
description='Set the packet layers to hash for aggregation protocols which load balance.'
),
lacp_strict=dict(
type='str', required=False,
choices=['default', 'yes', 'no'],
description='Enable lacp strict compliance on the interface. The default depends on the '
'system tunable in net.link.lagg.lacp.default_strict_mode.',
),
mtu=dict(
type='int', required=False,
description='If you leave this field blank, the smallest mtu of this laggs children will be used.'
),
description=dict(type='str', required=False, aliases=['desc', 'name']),
match_fields=dict(
type='list', required=False, elements='str',
description='Fields that are used to match configured LAGG with the running config - '
"if any of those fields are changed, the module will think it's a new entry",
choices=['device', 'members', 'primary_member', 'proto', 'description'],
default=['members'],
),
**RELOAD_MOD_ARG,
**STATE_ONLY_MOD_ARG,
**OPN_MOD_ARGS,
)

result = dict(
changed=False,
diff={
'before': {},
'after': {},
}
)

module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True,
)

module_wrapper(Lagg(module=module, result=result))
module.exit_json(**result)


def main():
run_module()


if __name__ == '__main__':
main()
8 changes: 6 additions & 2 deletions plugins/modules/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
TARGETS = [
'alias', 'rule', 'rule_interface_group', 'route', 'gateway', 'syslog', 'package', 'unbound_host', 'unbound_domain',
'frr_ospf_general', 'frr_ospf3_general', 'unbound_forward', 'shaper_pipe', 'shaper_queue', 'shaper_rule',
'monit_service', 'monit_test', 'monit_alert', 'wireguard_server', 'bind_domain', 'wireguard_peer', 'interface_vlan',
'unbound_host_alias', 'interface_vxlan', 'frr_bfd_neighbor', 'frr_bgp_general', 'frr_bgp_neighbor',
'monit_service', 'monit_test', 'monit_alert', 'wireguard_server', 'bind_domain', 'wireguard_peer', 'interface_lagg',
'interface_vlan', 'unbound_host_alias', 'interface_vxlan', 'frr_bfd_neighbor', 'frr_bgp_general', 'frr_bgp_neighbor',
'frr_ospf3_interface', 'frr_ospf_interface', 'bind_acl', 'frr_ospf_network', 'frr_rip', 'bind_general',
'bind_blocklist', 'bind_record', 'interface_vip', 'webproxy_general', 'webproxy_cache', 'webproxy_parent',
'webproxy_traffic', 'webproxy_remote_acl', 'webproxy_pac_proxy', 'webproxy_pac_match', 'webproxy_pac_rule',
Expand Down Expand Up @@ -174,6 +174,10 @@ def run_module():
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.interface_vxlan import \
Vxlan as Target_Obj

elif target == 'interface_lagg':
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.interface_lagg import \
Lagg as Target_Obj

elif target == 'source_nat':
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.source_nat import \
SNat as Target_Obj
Expand Down
5 changes: 5 additions & 0 deletions plugins/modules/reload.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def run_module():
'interface_vlan',
'interface_vxlan',
'interface_vip',
'interface_lagg',
'frr',
'webproxy',
'bind',
Expand Down Expand Up @@ -132,6 +133,10 @@ def run_module():
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.interface_vip import \
Vip as Target_Obj

elif target == 'interface_lagg':
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.interface_lagg import \
Lagg as Target_Obj

elif target == 'frr':
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.frr_bgp_general import \
General as Target_Obj
Expand Down
1 change: 1 addition & 0 deletions scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ run_test 'wireguard_show' 1
run_test 'interface_vlan' 1
run_test 'interface_vxlan' 1
run_test 'interface_vip' 1
run_test 'interface_lagg' 1
run_test 'source_nat' 1
run_test 'frr_diagnostic' 1
run_test 'frr_general' 1
Expand Down
6 changes: 6 additions & 0 deletions tests/cleanup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,12 @@
- 100
- 101

- name: Cleanup lagg interfaces
ansibleguy.opnsense.interface_lagg:
members:
- 'vtnet0'
state: 'absent'

- name: Cleanup source-nat
ansibleguy.opnsense.source_nat:
description: "{{ item }}"
Expand Down
Loading

0 comments on commit 65cfd36

Please sign in to comment.