From 540e39bc9ddac90e94ff5698f9bf489d5fc67c99 Mon Sep 17 00:00:00 2001
From: Timotej Lazar <timotej.lazar@fri.uni-lj.si>
Date: Mon, 13 Jan 2025 11:10:38 +0100
Subject: [PATCH] Add script to create a MLAG bond

---
 interfaces.py | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 interfaces.py

diff --git a/interfaces.py b/interfaces.py
new file mode 100644
index 0000000..c33519f
--- /dev/null
+++ b/interfaces.py
@@ -0,0 +1,44 @@
+from dcim.models import Device, Interface
+from extras.models import CustomField
+from extras.scripts import *
+
+class CreateMLAGScript(Script):
+    class Meta:
+        name = 'Create MLAG'
+        description = 'Create and configure a new MLAG on paired Cumulus leaf switches'
+        scheduling_enabled = False
+
+    switch = ObjectVar(model=Device, query_params={'role': 'switch'},
+            description='One of the peer switches')
+    iface = ObjectVar(label='Interface', model=Interface, query_params={'device_id': '$switch'},
+            description='Switch interface (same for both switches)')
+    bond_name = StringVar(label='MLAG name', regex='[0-9a-z-]', max_length=15)
+    mode = ChoiceVar(choices=CustomField.objects.get(name='bond_mode').choices, required=False)
+
+    def run(self, data, commit):
+        switch = data['switch']
+        iface_name = data['iface'].name
+        bond_name = data['bond_name']
+        mode = data['mode']
+
+        peer_name = switch.local_context_data.get('peer')
+        if not peer_name:
+            raise AbortScript(f'Switch {switch} has no peer defined in local context')
+
+        for device in (switch, Device.objects.get(name=peer_name)):
+            bridge = device.interfaces.get(name='bridge')
+            iface = device.interfaces.get(name=iface_name)
+
+            bond_iface, new = Interface.objects.get_or_create(device=device, name=bond_name, type='lag', bridge=bridge)
+            if new:
+                self.log_info(f'created new bond {bond_iface} on {device}')
+            if mode:
+                bond_iface.custom_field_data['bond_mode'] = mode
+                self.log_info(f'setting mode for bond {bond_iface} to {mode}')
+            bond_iface.full_clean()
+            bond_iface.save()
+
+            iface.lag = bond_iface
+            self.log_info(f'setting {bond_iface} as LAG for interface {iface}')
+            iface.full_clean()
+            iface.save()