diff --git a/fabrictestbed_extensions/fablib/facility_port.py b/fabrictestbed_extensions/fablib/facility_port.py index 568fbd5b..53856ae2 100644 --- a/fabrictestbed_extensions/fablib/facility_port.py +++ b/fabrictestbed_extensions/fablib/facility_port.py @@ -141,31 +141,41 @@ def new_facility_port( slice: Slice = None, name: str = None, site: str = None, - vlan: Union[str, list] = None, + vlan: Union[List, str] = None, bandwidth: int = 10, + labels: Labels = None, + peer_labels: Labels = None, + capacities: Capacities = None, ): - if isinstance(vlan, list): - interfaces = [] + if capacities is None: + if not bandwidth: + bandwidth = 10 + capacities = Capacities(bw=bandwidth) + + interfaces = None + + if vlan: index = 1 + interfaces = [] + if isinstance(vlan, str): + vlan = [vlan] + for v in vlan: iface_tuple = ( f"iface-{index}", Labels(vlan=v), - Capacities(bw=bandwidth), + capacities, ) interfaces.append(iface_tuple) - fim_facility_port = slice.get_fim_topology().add_facility( - name=name, - site=site, - interfaces=interfaces, - ) - else: - fim_facility_port = slice.get_fim_topology().add_facility( - name=name, - site=site, - capacities=Capacities(bw=bandwidth), - labels=Labels(vlan=vlan), - ) + + fim_facility_port = slice.get_fim_topology().add_facility( + name=name, + site=site, + capacities=capacities, + labels=labels, + peer_labels=peer_labels, + interfaces=interfaces, + ) return FacilityPort(slice, fim_facility_port) @staticmethod diff --git a/fabrictestbed_extensions/fablib/metrics.py b/fabrictestbed_extensions/fablib/metrics.py deleted file mode 100644 index 06c61b0b..00000000 --- a/fabrictestbed_extensions/fablib/metrics.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python3 -# MIT License -# -# Copyright (c) 2020 FABRIC Testbed -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# Author: Komal Thareja (ktharej@renci.org) - - -class Metrics: - def __init__(self, fablib_manager): - self.fablib_manager = fablib_manager - - def list_metrics( - self, - output=None, - fields=None, - quiet=False, - filter_function=None, - pretty_names=True, - ): - table = [] - metric_dict = self.metrics_to_dict() - table.append(metric_dict) - - if pretty_names: - pretty_names_dict = self.pretty_names - else: - pretty_names_dict = {} - - return self.fablib_manager.list_table( - table, - fields=fields, - title="Metrics", - output=output, - quiet=quiet, - filter_function=filter_function, - pretty_names_dict=pretty_names_dict, - ) - - def metrics_to_dict(self): - """ - Convert Metrics information into a dictionary - """ - site_info = self.get_site_info(site) - d = { - "name": site.name if isinstance(site, node.Node) else site.get_name(), - "state": self.get_state(site), - "address": self.get_location_postal(site), - "location": self.get_location_lat_long(site) if latlon else "", - "ptp_capable": self.get_ptp_capable(site), - "hosts": self.get_host_capacity(site), - "cpus": self.get_cpu_capacity(site), - } - - for attribute, names in self.site_attribute_name_mappings.items(): - capacity = site_info.get(attribute, {}).get(self.CAPACITY.lower(), 0) - allocated = site_info.get(attribute, {}).get(self.ALLOCATED.lower(), 0) - available = capacity - allocated - d[f"{names.get(self.NON_PRETTY_NAME)}_{self.AVAILABLE.lower()}"] = available - d[f"{names.get(self.NON_PRETTY_NAME)}_{self.CAPACITY.lower()}"] = capacity - d[f"{names.get(self.NON_PRETTY_NAME)}_{self.ALLOCATED.lower()}"] = allocated - - if not latlon: - d.pop("location") - - return d diff --git a/fabrictestbed_extensions/fablib/network_service.py b/fabrictestbed_extensions/fablib/network_service.py index a881dc77..dec064c2 100644 --- a/fabrictestbed_extensions/fablib/network_service.py +++ b/fabrictestbed_extensions/fablib/network_service.py @@ -47,7 +47,7 @@ from ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network import jinja2 -from fabrictestbed.slice_editor import Labels +from fabrictestbed.slice_editor import Capacities, Labels from fabrictestbed.slice_editor import NetworkService as FimNetworkService from fabrictestbed.slice_editor import ServiceType, UserData from fim.slivers.network_service import NSLayer, ServiceType @@ -340,6 +340,7 @@ def new_l3network( interfaces: List[Interface] = [], type: str = None, user_data={}, + technology: str = None, ): """ Not inteded for API use. See slice.add_l3network @@ -369,6 +370,7 @@ def new_l3network( nstype=nstype, interfaces=interfaces, user_data=user_data, + technology=technology, ) @staticmethod @@ -446,6 +448,7 @@ def new_network_service( nstype: ServiceType = None, interfaces: List[Interface] = [], user_data: dict = {}, + technology: str = None, ): """ Not intended for API use. See slice.add_l2network @@ -460,6 +463,9 @@ def new_network_service( :param nstype: the type of network service to create :type nstype: ServiceType :param interfaces: a list of interfaces to + :type interfaces: List + :param technology: Specify the technology used should be set to AL2S when using for AL2S peering; otherwise None + :type technology: str :return: the new fablib network service :rtype: NetworkService """ @@ -471,7 +477,7 @@ def new_network_service( f"Create Network Service: Slice: {slice.get_name()}, Network Name: {name}, Type: {nstype}" ) fim_network_service = slice.topology.add_network_service( - name=name, nstype=nstype, interfaces=fim_interfaces + name=name, nstype=nstype, interfaces=fim_interfaces, technology=technology ) network_service = NetworkService( @@ -1279,3 +1285,34 @@ def config(self): if self.get_gateway() not in allocated_ips: allocated_ips.append(self.get_gateway()) self.set_allocated_ip(self.get_gateway()) + + def peer( + self, + other: NetworkService, + labels: Labels, + peer_labels: Labels, + capacities: Capacities, + ): + """ + Peer a network service; used for AL2S peering between FABRIC Networks and Cloud Networks + Peer this network service to another. A few constraints are enforced like services being + of the same type. Both services will have ServicePort interfaces facing each other over a link. + It typically requires labels and capacities to put on the interface facing the other service + + :param other: network service to be peered + :type other: NetworkService + :param labels: labels + :type labels: Labels + :param peer_labels: peer labels + :type peer_labels: Labels + :param capacities: capacities + :type capacities: Capacities + + """ + # Peer Cloud L3VPN with FABRIC L3VPN + self.get_fim().peer( + other.get_fim(), + labels=labels, + peer_labels=peer_labels, + capacities=capacities, + ) diff --git a/fabrictestbed_extensions/fablib/slice.py b/fabrictestbed_extensions/fablib/slice.py index 55b7c4c4..d8c8bb66 100644 --- a/fabrictestbed_extensions/fablib/slice.py +++ b/fabrictestbed_extensions/fablib/slice.py @@ -59,6 +59,7 @@ from typing import TYPE_CHECKING, Tuple import pandas as pd +from fim.user import Capacities, Labels from fss_utils.sshkey import FABRICSSHKey from IPython.core.display_functions import display @@ -1001,6 +1002,7 @@ def add_l3network( interfaces: List[Interface] = [], type: str = "IPv4", user_data: dict = {}, + technology: str = None, ) -> NetworkService: """ Adds a new L3 network service to this slice. @@ -1042,6 +1044,8 @@ def add_l3network( :type type: String :param user_data :type user_data: dict + :param technology: Specify the technology used should be set to AL2S when using for AL2S peering; otherwise None + :type technology: str :return: a new L3 network service :rtype: NetworkService @@ -1055,10 +1059,17 @@ def add_l3network( interfaces=interfaces, type=type, user_data=user_data, + technology=technology, ) def add_facility_port( - self, name: str = None, site: str = None, vlan: Union[str, list] = None + self, + name: str = None, + site: str = None, + vlan: Union[str, list] = None, + labels: Labels = None, + peer_labels: Labels = None, + capacities: Capacities = None, ) -> NetworkService: """ Adds a new L2 facility port to this slice @@ -1069,11 +1080,23 @@ def add_facility_port( :type site: String :param vlan: vlan :type vlan: String + :param labels: labels for the facility port such as VLAN, ip sub net + :type: labels: Labels + :param peer_labels: peer labels for the facility port such as VLAN, ip sub net, bgp key - used for AL2S Peering + :type: peer_labels: Labels + :param capacities: capacities for the facility port such as bandwidth + :type: capacities: Capacities :return: a new L2 facility port :rtype: NetworkService """ return FacilityPort.new_facility_port( - slice=self, name=name, site=site, vlan=vlan + slice=self, + name=name, + site=site, + vlan=vlan, + labels=labels, + peer_labels=peer_labels, + capacities=capacities, ) def add_node(