Commit c970da7f authored by Mohamad Rahhal's avatar Mohamad Rahhal
Browse files

Merge branch 'feat/389-cttc-spine-leaf-component' of...

Merge branch 'feat/389-cttc-spine-leaf-component' of https://labs.etsi.org/rep/tfs/controller into feat/390-cttc-integration-of-spine-leaf-fabric-management
parents b861f62e 1b6331a5
Loading
Loading
Loading
Loading
+396 −0
Original line number Diff line number Diff line
{
  "logical_resources": [
    {
      "fabric_id": "core-spine-leaf-evpn-static",

      "asn": {
        "settings": {
          "range": "65000-65199"
        },
        "allocations": {
          "e162b163-6969-512a-8ee9-cce9f0687c64": {
            "device_name": "Spine1",
            "value": "65001"
          },
          "1f3a8cbe-5826-585b-a207-4826d4ae9a61": {
            "device_name": "Spine2",
            "value": "65002"
          },
          "81b97fc5-6c85-5d0d-86e2-e00ff04a4740": {
            "device_name": "Spine3",
            "value": "65003"
          },
          "6ac9614b-6893-549d-b39c-d4af4320678a": {
            "device_name": "Leaf1",
            "value": "65101"
          },
          "03d3c087-da28-539e-aae0-60da7b90bad6": {
            "device_name": "Leaf4",
            "value": "65104"
          }
        }
      },

      "loopback": {
        "settings": {
          "range": "10.255.0.0/16"
        },
        "allocations": {
          "e162b163-6969-512a-8ee9-cce9f0687c64": {
            "device_name": "Spine1",
            "value": "10.255.0.1"
          },
          "1f3a8cbe-5826-585b-a207-4826d4ae9a61": {
            "device_name": "Spine2",
            "value": "10.255.0.2"
          },
          "81b97fc5-6c85-5d0d-86e2-e00ff04a4740": {
            "device_name": "Spine3",
            "value": "10.255.0.3"
          },
          "6ac9614b-6893-549d-b39c-d4af4320678a": {
            "device_name": "Leaf1",
            "value": "10.255.1.1"
          },
          "03d3c087-da28-539e-aae0-60da7b90bad6": {
            "device_name": "Leaf4",
            "value": "10.255.1.4"
          }
        }
      },

      "router_id": {
        "settings": {
          "range": "10.255.0.0/16"
        },
        "allocations": {
          "e162b163-6969-512a-8ee9-cce9f0687c64": {
            "device_name": "Spine1",
            "value": "10.255.0.1"
          },
          "1f3a8cbe-5826-585b-a207-4826d4ae9a61": {
            "device_name": "Spine2",
            "value": "10.255.0.2"
          },
          "81b97fc5-6c85-5d0d-86e2-e00ff04a4740": {
            "device_name": "Spine3",
            "value": "10.255.0.3"
          },
          "6ac9614b-6893-549d-b39c-d4af4320678a": {
            "device_name": "Leaf1",
            "value": "10.255.1.1"
          },
          "03d3c087-da28-539e-aae0-60da7b90bad6": {
            "device_name": "Leaf4",
            "value": "10.255.1.4"
          }
        }
      },

      "ip": {
        "settings": {
          "range": "10.0.0.0/16"
        },
        "allocations": {
          "e162b163-6969-512a-8ee9-cce9f0687c64#leaf1": {
            "device_name": "Spine1",
            "value": "10.0.0.0"
          },
          "e162b163-6969-512a-8ee9-cce9f0687c64#leaf4": {
            "device_name": "Spine1",
            "value": "10.0.0.6"
          },
          "1f3a8cbe-5826-585b-a207-4826d4ae9a61#leaf1": {
            "device_name": "Spine2",
            "value": "10.0.1.0"
          },
          "1f3a8cbe-5826-585b-a207-4826d4ae9a61#leaf4": {
            "device_name": "Spine2",
            "value": "10.0.1.6"
          },
          "81b97fc5-6c85-5d0d-86e2-e00ff04a4740#leaf1": {
            "device_name": "Spine3",
            "value": "10.0.2.0"
          },
          "81b97fc5-6c85-5d0d-86e2-e00ff04a4740#leaf4": {
            "device_name": "Spine3",
            "value": "10.0.2.6"
          },
          "6ac9614b-6893-549d-b39c-d4af4320678a#spine1": {
            "device_name": "Leaf1",
            "value": "10.0.0.1"
          },
          "6ac9614b-6893-549d-b39c-d4af4320678a#spine2": {
            "device_name": "Leaf1",
            "value": "10.0.1.1"
          },
          "6ac9614b-6893-549d-b39c-d4af4320678a#spine3": {
            "device_name": "Leaf1",
            "value": "10.0.2.1"
          },
          "03d3c087-da28-539e-aae0-60da7b90bad6#spine1": {
            "device_name": "Leaf4",
            "value": "10.0.0.7"
          },
          "03d3c087-da28-539e-aae0-60da7b90bad6#spine2": {
            "device_name": "Leaf4",
            "value": "10.0.1.7"
          },
          "03d3c087-da28-539e-aae0-60da7b90bad6#spine3": {
            "device_name": "Leaf4",
            "value": "10.0.2.7"
          }
        }
      },

      "vlan": {
        "settings": {
          "range": "10-4094"
        },
        "allocations": {
          "6ac9614b-6893-549d-b39c-d4af4320678a": {
            "device_name": "Leaf1",
            "value": "10"
          },
          "03d3c087-da28-539e-aae0-60da7b90bad6": {
            "device_name": "Leaf4",
            "value": "10"
          }
        }
      },

      "vni": {
        "settings": {
          "range": "1000-999999"
        },
        "allocations": {
          "6ac9614b-6893-549d-b39c-d4af4320678a": {
            "device_name": "Leaf1",
            "value": "1010"
          },
          "03d3c087-da28-539e-aae0-60da7b90bad6": {
            "device_name": "Leaf4",
            "value": "1010"
          }
        }
      },

      "interface_ip_address": {
        "allocations": {
          "e162b163-6969-512a-8ee9-cce9f0687c64": {
            "interfaces": {
              "lo0": {
                "ip": "10.255.0.1/32",
                "comment": "Spine1 Loopback"
              },
              "sfp-sfpplus1": {
                "ip": "10.0.0.0/31",
                "comment": "To Leaf1",
                "bgp_session_name": "Leaf1",
                "link_to_device": "6ac9614b-6893-549d-b39c-d4af4320678a",
                "link_to_interface": "sfp-sfpplus1"
              },
              "sfp-sfpplus4": {
                "ip": "10.0.0.6/31",
                "comment": "To Leaf4",
                "bgp_session_name": "Leaf4",
                "link_to_device": "03d3c087-da28-539e-aae0-60da7b90bad6",
                "link_to_interface": "sfp-sfpplus1"
              }
            }
          },

          "1f3a8cbe-5826-585b-a207-4826d4ae9a61": {
            "interfaces": {
              "lo0": {
                "ip": "10.255.0.2/32",
                "comment": "Spine2 Loopback"
              },
              "sfp-sfpplus1": {
                "ip": "10.0.1.0/31",
                "comment": "To Leaf1",
                "bgp_session_name": "Leaf1",
                "link_to_device": "6ac9614b-6893-549d-b39c-d4af4320678a",
                "link_to_interface": "sfp-sfpplus2"
              },
              "sfp-sfpplus4": {
                "ip": "10.0.1.6/31",
                "comment": "To Leaf4",
                "bgp_session_name": "Leaf4",
                "link_to_device": "03d3c087-da28-539e-aae0-60da7b90bad6",
                "link_to_interface": "sfp-sfpplus2"
              }
            }
          },

          "81b97fc5-6c85-5d0d-86e2-e00ff04a4740": {
            "interfaces": {
              "lo0": {
                "ip": "10.255.0.3/32",
                "comment": "Spine3 Loopback"
              },
              "sfp-sfpplus1": {
                "ip": "10.0.2.0/31",
                "comment": "To Leaf1",
                "bgp_session_name": "Leaf1",
                "link_to_device": "6ac9614b-6893-549d-b39c-d4af4320678a",
                "link_to_interface": "sfp-sfpplus3"
              },
              "sfp-sfpplus4": {
                "ip": "10.0.2.6/31",
                "comment": "To Leaf4",
                "bgp_session_name": "Leaf4",
                "link_to_device": "03d3c087-da28-539e-aae0-60da7b90bad6",
                "link_to_interface": "sfp-sfpplus3"
              }
            }
          },

          "6ac9614b-6893-549d-b39c-d4af4320678a": {
            "interfaces": {
              "lo0": {
                "ip": "10.255.1.1/32",
                "comment": "Leaf1 Loopback"
              },
              "sfp-sfpplus1": {
                "ip": "10.0.0.1/31",
                "comment": "To Spine1",
                "bgp_session_name": "Spine1",
                "link_to_device": "e162b163-6969-512a-8ee9-cce9f0687c64",
                "link_to_interface": "sfp-sfpplus1"
              },
              "sfp-sfpplus2": {
                "ip": "10.0.1.1/31",
                "comment": "To Spine2",
                "bgp_session_name": "Spine2",
                "link_to_device": "1f3a8cbe-5826-585b-a207-4826d4ae9a61",
                "link_to_interface": "sfp-sfpplus1"
              },
              "sfp-sfpplus3": {
                "ip": "10.0.2.1/31",
                "comment": "To Spine3",
                "bgp_session_name": "Spine3",
                "link_to_device": "81b97fc5-6c85-5d0d-86e2-e00ff04a4740",
                "link_to_interface": "sfp-sfpplus1"
              }
            }
          },

          "03d3c087-da28-539e-aae0-60da7b90bad6": {
            "interfaces": {
              "lo0": {
                "ip": "10.255.1.4/32",
                "comment": "Leaf4 Loopback"
              },
              "sfp-sfpplus1": {
                "ip": "10.0.0.7/31",
                "comment": "To Spine1",
                "bgp_session_name": "Spine1",
                "link_to_device": "e162b163-6969-512a-8ee9-cce9f0687c64",
                "link_to_interface": "sfp-sfpplus4"
              },
              "sfp-sfpplus2": {
                "ip": "10.0.1.7/31",
                "comment": "To Spine2",
                "bgp_session_name": "Spine2",
                "link_to_device": "1f3a8cbe-5826-585b-a207-4826d4ae9a61",
                "link_to_interface": "sfp-sfpplus4"
              },
              "sfp-sfpplus3": {
                "ip": "10.0.2.7/31",
                "comment": "To Spine3",
                "bgp_session_name": "Spine3",
                "link_to_device": "81b97fc5-6c85-5d0d-86e2-e00ff04a4740",
                "link_to_interface": "sfp-sfpplus4"
              }
            }
          }
        }
      },

      "vrf_interfaces": {
        "e162b163-6969-512a-8ee9-cce9f0687c64": [
          "sfp-sfpplus1",
          "sfp-sfpplus4",
          "lo0"
        ],
        "1f3a8cbe-5826-585b-a207-4826d4ae9a61": [
          "sfp-sfpplus1",
          "sfp-sfpplus4",
          "lo0"
        ],
        "81b97fc5-6c85-5d0d-86e2-e00ff04a4740": [
          "sfp-sfpplus1",
          "sfp-sfpplus4",
          "lo0"
        ],
        "6ac9614b-6893-549d-b39c-d4af4320678a": [
          "sfp-sfpplus1",
          "sfp-sfpplus2",
          "sfp-sfpplus3",
          "lo0"
        ],
        "03d3c087-da28-539e-aae0-60da7b90bad6": [
          "sfp-sfpplus1",
          "sfp-sfpplus2",
          "sfp-sfpplus3",
          "lo0"
        ]
      },

      "tenant_networks": {
        "default": {
          "name": "tenant-vni1010",
          "vlan_id": 10,
          "vni": 1010,
          "bridge_name": "br-vni1010",
          "vxlan_name": "vxlan1010",
          "evpn_name": "bgp-evpn-1010",
          "route_target_import": "1010:1010",
          "route_target_export": "1010:1010",
          "discovery_mode": "static"
        }
      },

      "bridge_ports": {
        "6ac9614b-6893-549d-b39c-d4af4320678a": [
          "sfp-sfpplus7"
        ],
        "03d3c087-da28-539e-aae0-60da7b90bad6": [
          "sfp-sfpplus8"
        ]
      },

      "static_vteps": {
        "6ac9614b-6893-549d-b39c-d4af4320678a": [
          "10.255.1.4"
        ],
        "03d3c087-da28-539e-aae0-60da7b90bad6": [
          "10.255.1.1"
        ]
      }
    }
  ],

  "spine-leaf": [
    {
      "fabric_id": "core-spine-leaf-evpn-static",
      "device_roles": {
        "e162b163-6969-512a-8ee9-cce9f0687c64": "DEVICEROLE_SPINE",
        "1f3a8cbe-5826-585b-a207-4826d4ae9a61": "DEVICEROLE_SPINE",
        "81b97fc5-6c85-5d0d-86e2-e00ff04a4740": "DEVICEROLE_SPINE",
        "6ac9614b-6893-549d-b39c-d4af4320678a": "DEVICEROLE_LEAF",
        "03d3c087-da28-539e-aae0-60da7b90bad6": "DEVICEROLE_LEAF"
      },
      "settings": {
        "underlay_type": "bgp",
        "overlay_type": "vxlan",
        "underlay_bgp": true,
        "overlay_bgp": true,
        "apply_config": true,
        "spine_count": 3,
        "leaf_count": 2
      }
    }
  ]
}
+4 −1
Original line number Diff line number Diff line
@@ -29,7 +29,10 @@ from device.client.DeviceClient import DeviceClient
from spine_leaf.client.SpineLeafClient import SpineLeafClient


DEFAULT_DESCRIPTOR = 'tmp/fabric-descriptor-spine1-spine2-leaf1-leaf4-evpn-vxlan-static.json'
DEFAULT_DESCRIPTOR = (
    'src/tests/Spine-Leaf-BGP-test/data/'
    'fabric-descriptor-spine1-spine2-leaf1-leaf4-evpn-vxlan-static.json'
)
DEFAULT_DEVICE_UUIDS = [
    'e162b163-6969-512a-8ee9-cce9f0687c64',
    '1f3a8cbe-5826-585b-a207-4826d4ae9a61',
+88 −24
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@ import json
import logging
import os
import copy
import socket
import subprocess

from common.proto.context_pb2 import ConfigRule
from common.proto.spineleaf_pb2 import DeployDeviceConfigRequest, UnsetDeviceRoleRequest
@@ -24,6 +26,7 @@ from common.tools.object_factory.ConfigRule import (
    json_config_rule_set,
    json_config_rule_delete,
)
from service.service.tools.object_uuid import get_uuid_from_string
from context.client.ContextClient import ContextClient
from device.client.DeviceClient import DeviceClient
from spine_leaf.client.SpineLeafClient import SpineLeafClient
@@ -38,21 +41,59 @@ LOGGER = logging.getLogger('spineleaf_all_multi_test')
# -----------------------------
# ENV
# -----------------------------
CONTEXTSERVICE_HOST = os.getenv('CONTEXTSERVICE_SERVICE_HOST', '10.152.183.46')
def _resolve_service_host(env_name, service_name, namespace='tfs'):
    env_value = os.getenv(env_name, '').strip()
    if env_value:
        return env_value

    dns_name = f'{service_name}.{namespace}.svc.cluster.local'
    try:
        socket.gethostbyname(dns_name)
        LOGGER.info('Resolved %s from Kubernetes DNS name %s', env_name, dns_name)
        return dns_name
    except OSError:
        pass

    try:
        result = subprocess.run(
            [
                'microk8s', 'kubectl', 'get', 'svc', service_name,
                '-n', namespace,
                '-o', 'jsonpath={.spec.clusterIP}',
            ],
            check=True,
            capture_output=True,
            text=True,
        )
        cluster_ip = result.stdout.strip()
        if cluster_ip:
            LOGGER.info('Resolved %s from Kubernetes service %s/%s => %s', env_name, namespace, service_name, cluster_ip)
            return cluster_ip
    except (FileNotFoundError, subprocess.CalledProcessError) as exc:
        LOGGER.warning('Unable to resolve Kubernetes service %s/%s: %s', namespace, service_name, exc)

    raise RuntimeError(
        f'Unable to resolve {service_name}. Set {env_name} explicitly, for example '
        f'{env_name}=<current-service-ip-or-hostname>.'
    )


CONTEXTSERVICE_HOST = _resolve_service_host('CONTEXTSERVICE_SERVICE_HOST', 'contextservice')
CONTEXTSERVICE_PORT = int(os.getenv('CONTEXTSERVICE_SERVICE_PORT_GRPC', '1010'))

DEVICESERVICE_HOST = os.getenv('DEVICESERVICE_SERVICE_HOST', '10.152.183.102')
DEVICESERVICE_HOST = _resolve_service_host('DEVICESERVICE_SERVICE_HOST', 'deviceservice')
DEVICESERVICE_PORT = int(os.getenv('DEVICESERVICE_SERVICE_PORT_GRPC', '2020'))

SPINE_LEAFSERVICE_HOST = os.getenv('SPINE_LEAFSERVICE_SERVICE_HOST', '10.152.183.147')
SPINE_LEAFSERVICE_HOST = _resolve_service_host('SPINE_LEAFSERVICE_SERVICE_HOST', 'spine-leafservice')
SPINE_LEAFSERVICE_PORT = int(os.getenv('SPINE_LEAFSERVICE_SERVICE_PORT_GRPC', '10095'))

FABRIC_ID = os.getenv(
    'FABRIC_ID',
    '354a08b7-3730-5dd6-9472-47554115818b',
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
DEFAULT_DESCRIPTOR_FILE = os.path.join(
    SCRIPT_DIR,
    'data',
    'fabric-descriptor-spine1-spine2-leaf1-leaf4-evpn-vxlan-static.json',
)

DESCRIPTOR_FILE = os.getenv('DESCRIPTOR_FILE', '')
DESCRIPTOR_FILE = os.getenv('DESCRIPTOR_FILE', DEFAULT_DESCRIPTOR_FILE)

DEFAULT_DEVICE_UUIDS = [
    'e162b163-6969-512a-8ee9-cce9f0687c64',
@@ -89,6 +130,25 @@ def is_apply_enabled() -> bool:
    return os.getenv('APPLY_CONFIG', 'false').lower() in ('1', 'true', 'yes')


def get_fabric_id() -> str:
    env_fabric_id = os.getenv('FABRIC_ID', '').strip()
    if env_fabric_id:
        return env_fabric_id

    if DESCRIPTOR_FILE and os.path.exists(DESCRIPTOR_FILE):
        try:
            with open(DESCRIPTOR_FILE, 'r', encoding='UTF-8') as f:
                descriptor = json.load(f)
            fabric = (descriptor.get('spine-leaf') or [{}])[0]
            fabric_name = str(fabric.get('fabric_name', fabric.get('fabric_id', '')) or '')
            if fabric_name:
                return get_uuid_from_string(fabric_name)
        except Exception:
            LOGGER.exception('Could not derive fabric id from descriptor %s', DESCRIPTOR_FILE)

    return '354a08b7-3730-5dd6-9472-47554115818b'


def parse_spineleaf_rule(entry):
    if not isinstance(entry, (list, tuple)) or len(entry) != 2:
        return None
@@ -144,8 +204,9 @@ def build_descriptor_rules(descriptor_file, device_uuid):

    settings = fabric.get('settings', {})
    store = SpineLeafStateStore()
    fabric_id_value = get_fabric_id()
    fabric_id, _, _ = store.create_fabric(
        FABRIC_ID,
        fabric_id_value,
        'spine_leaf',
        str(settings.get('underlay_type', 'bgp')),
        str(settings.get('overlay_type', '')),
@@ -255,8 +316,18 @@ class ApplySpineLeafConfig:
        LOGGER.info('')
        LOGGER.info('=== DEVICE %s ===', device_uuid)

        deconfigure = is_deconfigure_enabled()
        descriptor_rules = build_descriptor_rules(DESCRIPTOR_FILE, device_uuid)

        if deconfigure and descriptor_rules:
            payload = {'driver_config_rules': []}
            LOGGER.info(
                'Skipping SpineLeaf DeployDeviceConfig for descriptor-driven deconfigure of %s',
                device_uuid,
            )
        else:
            request = DeployDeviceConfigRequest(
            fabric_id=FABRIC_ID,
                fabric_id=get_fabric_id(),
                device_uuid=device_uuid,
            )

@@ -268,12 +339,9 @@ class ApplySpineLeafConfig:

            LOGGER.info('Parsed payload keys for %s: %s', device_uuid, list(payload.keys()))

        deconfigure = is_deconfigure_enabled()

        set_rules = []
        delete_rules = []
        driver_config_rules = payload.get('driver_config_rules', [])
        descriptor_rules = build_descriptor_rules(DESCRIPTOR_FILE, device_uuid)
        if deconfigure and descriptor_rules:
            seen_rules = {
                json.dumps(parse_spineleaf_rule(entry), sort_keys=True)
@@ -334,7 +402,7 @@ class ApplySpineLeafConfig:
            LOGGER.info('DELETE result %s => %s', device_uuid, result)

            unset_request = UnsetDeviceRoleRequest(
                fabric_id=FABRIC_ID,
                fabric_id=get_fabric_id(),
                device_uuid=device_uuid,
            )
            unset_result = self.spine_leaf_client.UnsetDeviceRole(unset_request)
@@ -366,9 +434,5 @@ class ApplySpineLeafConfig:
            device_client.close()
            context_client.close()


# -----------------------------
# ENTRY
# -----------------------------
if __name__ == '__main__':
    ApplySpineLeafConfig().run()