Repository: fabric-testbed/InformationModel (language: python)

Issue:
Instance sizes
This PR addresses a number of fixes:

1. Resizing of instance flavors (increasing the number of flavors available) to make VM provisioning more granular
   - Please see FIP-66 for more information - not all racks have been updated yet, only RENC - needs to be tested before other racks get the new flavor definitions. 
3. Add sliver diff methods #128 
4. Fixes the exception problem in #126 
5. Addresses #129 - topology pruning based on element (node, component, ns, interface) modify state

Add sliver diff methods
Based on @kthare10 code add to FIM sliver diff methods that can be used in the Broker, which doesn't have access to ASM and can't use its diff method.

```
#!/usr/bin/env python3
​
from fabric_mb.message_bus.messages.abc_message_avro import AbcMessageAvro
from fim.slivers.base_sliver import BaseSliver
from fim.slivers.network_node import NodeSliver
from fim.slivers.network_service import NetworkServiceSliver
from fim.user import ComponentType
from fim.user.topology import TopologyDiff, TopologyDiffTuple
​
from fabric_cf.actor.security.pdp_auth import ActionId
​
​
def sliver_to_str(*, sliver: BaseSliver):
    if isinstance(sliver, NodeSliver):
        return node_sliver_to_str(sliver=sliver)
​
    if isinstance(sliver, NetworkServiceSliver):
        return ns_sliver_to_str(sliver=sliver)
​
​
def dict_diff(dict_a, dict_b, show_value_diff=False):
    result = {'added': {k: dict_b[k] for k in set(dict_b) - set(dict_a)},
              'removed': {k: dict_a[k] for k in set(dict_a) - set(dict_b)}}
    if show_value_diff:
        common_keys = set(dict_a) & set(dict_b)
        result['value_diffs'] = {
            k: (dict_a[k], dict_b[k])
            for k in common_keys
            if dict_a[k] != dict_b[k]
        }
    return result
​
​
def sliver_diff(*, sliver1: BaseSliver, sliver2: BaseSliver) -> TopologyDiff or None:
    if isinstance(sliver1, NodeSliver) and isinstance(sliver2, NodeSliver):
        return node_sliver_diff(sliver1=sliver1, sliver2=sliver2)
​
    elif isinstance(sliver1, NetworkServiceSliver) and isinstance(sliver2, NetworkServiceSliver):
        return ns_sliver_diff(sliver1=sliver1, sliver2=sliver2)
    else:
        raise Exception("Incorrect Instance type")
​
​
def node_sliver_diff(*, sliver1: NodeSliver, sliver2: NodeSliver) -> TopologyDiff or None:
    if sliver1 is not None and sliver2 is not None:
        comp_added = set()
        comp_removed = set()
        ns_added = set()
        ns_removed = set()
        if sliver1.attached_components_info is not None and sliver2.attached_components_info is not None:
            diff_comps = dict_diff(sliver1.attached_components_info.devices,
                                   sliver2.attached_components_info.devices)
            comp_added = set(diff_comps['added'].keys())
            comp_removed = set(diff_comps['removed'].keys())
​
        if sliver1.attached_components_info is None and sliver2.attached_components_info is not None:
            comp_added = set(sliver2.attached_components_info.devices.keys())
​
        if sliver1.attached_components_info is not None and sliver2.attached_components_info is None:
            comp_removed = set(sliver1.attached_components_info.devices.keys())
​
        if sliver1.network_service_info is not None and sliver2.network_service_info is not None:
            diff_ns = dict_diff(sliver1.network_service_info.services,
                                sliver2.network_service_info.services)
            ns_added = set(diff_ns['added'].keys())
            ns_removed = set(diff_ns['removed'].keys())
​
        if sliver1.network_service_info is None and sliver2.network_service_info is not None:
            ns_added = set(sliver2.network_service_info.services.keys())
​
        if sliver1.network_service_info is not None and sliver2.network_service_info is None:
            ns_removed = set(sliver1.network_service_info.services.keys())
​
        if len(comp_added) > 0 or len(comp_removed) > 0 or len(ns_removed) > 0 or len(ns_added) > 0:
            return TopologyDiff(added=TopologyDiffTuple(components=comp_added, services=ns_added, interfaces=set(),
                                                        nodes=set()),
                                removed=TopologyDiffTuple(components=comp_removed, services=ns_removed,
                                                          interfaces=set(), nodes=set()))
​
    return None
​
​
def ns_sliver_diff(*, sliver1: NetworkServiceSliver, sliver2: NetworkServiceSliver) -> TopologyDiff or None:
    if sliver1 is not None and sliver2 is not None:
        ifs_added = set()
        ifs_removed = set()
        if sliver1.interface_info is not None and sliver2.interface_info is not None:
            diff_comps = dict_diff(sliver1.interface_info.interfaces,
                                   sliver2.interface_info.interfaces)
            ifs_added = set(diff_comps['added'].keys())
            ifs_removed = set(diff_comps['removed'].keys())
​
        if sliver1.interface_info is None and sliver2.interface_info is not None:
            ifs_added = set(sliver2.interface_info.interfaces.keys())
​
        if sliver1.interface_info is not None and sliver2.interface_info is None:
            ifs_removed = set(sliver1.interface_info.interfaces.keys())
​
        if len(ifs_added) > 0 or len(ifs_removed) > 0:
            return TopologyDiff(added=TopologyDiffTuple(components=set(), services=set(), interfaces=ifs_added,
                                                        nodes=set()),
                                removed=TopologyDiffTuple(components=set(), services=set(),
                                                          interfaces=ifs_removed, nodes=set()))
​
    return None
​
​
def node_sliver_to_str(*, sliver: NodeSliver):
    result = str(sliver)
    nic_types = [ComponentType.SharedNIC, ComponentType.SmartNIC]
    if sliver.attached_components_info is not None:
        for c in sliver.attached_components_info.devices.values():
            result += f"\nComponent: {c}"
            if c.get_type() not in nic_types:
                continue
            if c.network_service_info is not None and c.network_service_info.network_services is not None:
                for ns in c.network_service_info.network_services.values():
                    result += f"\nNS: {ns}"
                    if ns.interface_info is not None and ns.interface_info.interfaces is not None:
                        for i in ns.interface_info.interfaces.values():
                            result += f"\nIFS: {i}"
    return result
​
​
def ns_sliver_to_str(*, sliver: NetworkServiceSliver):
    result = str(sliver)
    for interface in sliver.interface_info.interfaces.values():
        result += f"\nIFS: {interface}"
    return result
​```


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index ea799e9..bb32706 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[![Requirements Status](https://requires.io/github/fabric-testbed/InformationModel/requirements.svg?branch=rel-1.2)](https://requires.io/github/fabric-testbed/InformationModel/requirements/?branch=rel-1.2)
+[![Requirements Status](https://requires.io/github/fabric-testbed/InformationModel/requirements.svg?branch=master)](https://requires.io/github/fabric-testbed/InformationModel/requirements/?branch=master)
 
 [![PyPI](https://img.shields.io/pypi/v/fabric-fim?style=plastic)](https://pypi.org/manage/project/fabric-fim/releases/)
 
diff --git a/fim/__init__.py b/fim/__init__.py
index 670ccae..c20d5ab 100644
--- a/fim/__init__.py
+++ b/fim/__init__.py
@@ -1,2 +1,3 @@
 #
-__VERSION__ = "1.2.5"
+__VERSION__ = "1.3.2"
+
diff --git a/fim/graph/abc_property_graph.py b/fim/graph/abc_property_graph.py
index a4bbe60..9d7e8dc 100644
--- a/fim/graph/abc_property_graph.py
+++ b/fim/graph/abc_property_graph.py
@@ -102,7 +102,8 @@ class ABCPropertyGraph(ABCPropertyGraphConstants):
         "mf_data": ABCPropertyGraphConstants.PROP_MEAS_DATA,
         "tags": ABCPropertyGraphConstants.PROP_TAGS,
         "flags": ABCPropertyGraphConstants.PROP_FLAGS,
-        "boot_script": ABCPropertyGraphConstants.PROP_BOOT_SCRIPT
+        "boot_script": ABCPropertyGraphConstants.PROP_BOOT_SCRIPT,
+        "layout": ABCPropertyGraphConstants.PROP_LAYOUT
     }
 
     @abstractmethod
@@ -947,6 +948,56 @@ def build_deep_component_sliver_from_dict(*, props: Dict[str, Any]) -> Component
             cs.network_service_info = nsi
         return cs
 
+    def build_deep_interface_sliver(self, *, node_id: str) -> InterfaceSliver:
+        """
+        Build a deep interface sliver from graph
+        :param node_id:
+        :return:
+        """
+        clazzes, props = self.get_node_properties(node_id=node_id)
+        if ABCPropertyGraph.CLASS_ConnectionPoint not in clazzes:
+            raise PropertyGraphQueryException(node_id=node_id, graph_id=self.graph_id,
+                                              msg="Node is not of class Interface")
+        # create top-level sliver
+        isl = ABCPropertyGraph.interface_sliver_from_graph_properties_dict(props)
+        return isl
+
+    @staticmethod
+    def build_deep_interface_sliver_from_dict(*, props: Dict[str, Any]) -> InterfaceSliver:
+        """
+        Build a deep interface sliver from graph
+        :param props:
+        :return:
+        """
+        # create top-level sliver
+        isl = ABCPropertyGraph.interface_sliver_from_graph_properties_dict(props)
+        return isl
+
+    def build_deep_link_sliver(self, *, node_id: str) -> NetworkLinkSliver:
+        """
+        Build a deep link sliver from graph
+        :param node_id:
+        :return:
+        """
+        clazzes, props = self.get_node_properties(node_id=node_id)
+        if ABCPropertyGraph.CLASS_Link not in clazzes:
+            raise PropertyGraphQueryException(node_id=node_id, graph_id=self.graph_id,
+                                              msg="Node is not of class Link")
+        # create top-level sliver
+        lsl = ABCPropertyGraph.link_sliver_from_graph_properties_dict(props)
+        return lsl
+
+    @staticmethod
+    def build_deep_link_sliver_from_dict(*, props: Dict[str, Any]) -> NetworkLinkSliver:
+        """
+        Build a deep link sliver from graph
+        :param props:
+        :return:
+        """
+        # create top-level sliver
+        lsl = ABCPropertyGraph.link_sliver_from_graph_properties_dict(props)
+        return lsl
+
     def remove_network_node_with_components_nss_cps_and_links(self, node_id: str):
         """
         Remove a network node, all of components and their interfaces, parent interfaces
@@ -1210,9 +1261,9 @@ def get_parent(self, node_id: str, rel: str, parent: str) -> Tuple[str, str]:
         :param parent: parent class
         :return:
         """
-        assert node_id is not None
-        assert rel is not None
-        assert parent is not None
+        #assert node_id is not None
+        #assert rel is not None
+        #assert parent is not None
         parent_ids = self.get_first_neighbor(node_id=node_id, rel=rel,
                                              node_label=parent)
         if len(parent_ids) != 1:
@@ -1228,6 +1279,16 @@ def get_stitch_nodes(self) -> List[str]:
         :return:
         """
 
+    @abstractmethod
+    def get_graph_diff(self, other_graph, label: str):
+        """
+        Return two lists - nodes that are in this graph but NOT in the other graph
+        and node that are in the other graph, but not in this graph, using label
+        as a filter
+        [0] - elements present in self, absent in other (i.e. removed elements)
+        [1] - elements present in other, absent in self (i.e. added elements
+        """
+
     def find_peer_connection_points(self, *, node_id: str) -> List[str] or None:
         """
         Find the ids of the peer connection points to this one (connected over a Link)
diff --git a/fim/graph/abc_property_graph_constants.py b/fim/graph/abc_property_graph_constants.py
index 76009ff..a59dc2c 100644
--- a/fim/graph/abc_property_graph_constants.py
+++ b/fim/graph/abc_property_graph_constants.py
@@ -73,12 +73,13 @@ class ABCPropertyGraphConstants(ABC):
     PROP_FLAGS = "Flags"
     PROP_MEAS_DATA = "MeasurementData"
     PROP_BOOT_SCRIPT = "BootScript"
+    PROP_LAYOUT = "Layout"
     # these properties get validated to be valid JSON objects whenever someone validates the graph
     JSON_PROPERTY_NAMES = [PROP_LABELS, PROP_CAPACITIES, PROP_LABEL_DELEGATIONS,
                            PROP_CAPACITY_DELEGATIONS, PROP_LABEL_ALLOCATIONS,
                            PROP_CAPACITY_ALLOCATIONS, PROP_RESERVATION_INFO, PROP_STRUCTURAL_INFO,
                            PROP_ERO, PROP_PATH_INFO, PROP_CAPACITY_HINTS, PROP_GATEWAY,
-                           PROP_TAGS, PROP_FLAGS, PROP_MEAS_DATA]
+                           PROP_TAGS, PROP_FLAGS, PROP_MEAS_DATA, PROP_LAYOUT]
     # these properties cannot be unset
     NO_UNSET_PROPERTIES = [GRAPH_ID, NODE_ID, PROP_TYPE, PROP_CLASS, PROP_NAME]
 
diff --git a/fim/graph/neo4j_property_graph.py b/fim/graph/neo4j_property_graph.py
index e4fe9bc..0afce32 100644
--- a/fim/graph/neo4j_property_graph.py
+++ b/fim/graph/neo4j_property_graph.py
@@ -602,6 +602,23 @@ def check_node_unique(self, *, label: str, name: str) -> bool:
                 return True
             return False
 
+    def get_graph_diff(self, other_graph, label: str):
+        assert other_graph is not None
+        assert label is not None
+
+        query = f"MATCH(n:{label} {{GraphID: $graphIdA}}) WITH n MATCH(n1:{label} {{GraphID: $graphIdB}}) WITH " \
+                f"collect(DISTINCT n) as A, collect(DISTINCT n1) as B, " \
+                f"collect(DISTINCT n.NodeID) as AN, collect(DISTINCT n1.NodeID) as BN " \
+                f"RETURN [x in A WHERE NOT x.NodeID in BN] as AnotB, [x in B WHERE NOT x.NodeID in AN] as BnotA"
+        with self.driver.session() as session:
+            val = session.run(query, graphIdA=self.graph_id, graphIdB=other_graph.graph_id).single()
+            if val is None:
+                raise PropertyGraphQueryException(graph_id=self.graph_id,
+                                                  node_id=None, msg=f"Unable to diff with graph {other_graph.graph_id}")
+            # A not B means element was removed
+            # B not A means element was added
+            return val.data()['AnotB'], val.data()['BnotA']
+
 
 class Neo4jGraphImporter(ABCGraphImporter):
 
@@ -758,10 +775,10 @@ def import_graph_from_string(self, *, graph_string: str, graph_id: str = None) -
                 # something in APOC prevents loading sometimes on some platforms
                 self.log.debug(f"Trying to load the file {mapped_file_name}")
                 self._import_graph(mapped_file_name, assigned_id)
-                retry = -1
+                retry = -5
             except PropertyGraphImportException:
                 self.log.warning(f"Transient error, unable to load, deleting and reimporting graph {assigned_id}")
-                retry = retry - 1
+                retry -= 1
                 self.delete_graph(graph_id=assigned_id)
                 # sleep and try again
                 time.sleep(1.0)
@@ -796,12 +813,28 @@ def import_graph_from_string_direct(self, *, graph_string: str) -> ABCPropertyGr
         # get graph id
         graph_id = self.get_graph_id(graph_file=host_file_name)
 
-        self._import_graph(mapped_file_name, graph_id)
+        retry = APOC_RETRY_COUNT
+        while retry > 0:
+            try:
+                # something in APOC prevents loading sometimes on some platforms
+                self.log.debug(f"Trying to load the file {mapped_file_name}")
+                self._import_graph(mapped_file_name, graph_id)
+                retry = -5
+            except PropertyGraphImportException:
+                self.log.warning(f"Transient error, unable to load, deleting and reimporting graph {graph_id}")
+                retry -= 1
+                self.delete_graph(graph_id=graph_id)
+                # sleep and try again
+                time.sleep(1.0)
 
         # unlink temp file
         self.log.debug(f"Unlinking temporary file {host_file_name}")
         os.unlink(host_file_name)
 
+        if retry == 0:
+            raise PropertyGraphImportException(graph_id=graph_id,
+                                               msg='Unable to load graph after multiple attempts')
+
         return Neo4jPropertyGraph(graph_id=graph_id, importer=self, logger=self.log)
 
     def import_graph_from_file_direct(self, *, graph_file: str) -> ABCPropertyGraph:
diff --git a/fim/graph/networkx_property_graph.py b/fim/graph/networkx_property_graph.py
index 69721b7..c0ab675 100644
--- a/fim/graph/networkx_property_graph.py
+++ b/fim/graph/networkx_property_graph.py
@@ -664,6 +664,9 @@ def check_node_unique(self, *, label: str, name: str):
                                             ]}))
         return len(graph_nodes) == 0
 
+    def get_graph_diff(self, other_graph, label: str):
+        raise RuntimeError("Not implementable with this backend.")
+
 
 class NetworkXGraphStorage:
     """
diff --git a/fim/graph/networkx_property_graph_disjoint.py b/fim/graph/networkx_property_graph_disjoint.py
index 6362aa4..0893b77 100644
--- a/fim/graph/networkx_property_graph_disjoint.py
+++ b/fim/graph/networkx_property_graph_disjoint.py
@@ -54,7 +54,7 @@ def merge_nodes(self, node_id: str, other_graph, merge_properties=None):
         has assumptions about a common store for all graphs.
         Would require to store all graphs in a single NetworkX graph.
         """
-        raise RuntimeError("Not implementable")
+        raise RuntimeError("Not implementable with this backend.")
 
     def graph_exists(self) -> bool:
         """
diff --git a/fim/slivers/attached_components.py b/fim/slivers/attached_components.py
index d764cf4..e69cc27 100644
--- a/fim/slivers/attached_components.py
+++ b/fim/slivers/attached_components.py
@@ -28,6 +28,7 @@
 
 from .base_sliver import BaseSliver
 from .network_service import NetworkServiceInfo
+from .topology_diff import TopologyDiff
 
 
 @enum.unique
@@ -63,6 +64,9 @@ def type_from_str(ctype: str) -> ComponentType or None:
             if ctype == str(t):
                 return t
 
+    def diff(self, other_sliver) -> TopologyDiff or None:
+        raise RuntimeError('Not implemented')
+
 
 class AttachedComponentsInfo:
     """
diff --git a/fim/slivers/base_sliver.py b/fim/slivers/base_sliver.py
index e3615de..d1d740c 100644
--- a/fim/slivers/base_sliver.py
+++ b/fim/slivers/base_sliver.py
@@ -33,6 +33,7 @@
 from fim.slivers.delegations import Delegations
 from fim.slivers.tags import Tags
 from fim.slivers.measurement_data import MeasurementData
+from fim.slivers.topology_diff import TopologyDiff, TopologyDiffTuple
 
 
 class BaseSliver(ABC):
@@ -63,6 +64,7 @@ def __init__(self):
         self.flags = None # various flags
         self.mf_data = None # opaque JSON object limited in length
         self.boot_script = None # string limited in length
+        self.layout = None # opaque JSON object limited in length
 
     def set_type(self, resource_type):
         self.resource_type = resource_type
@@ -212,6 +214,26 @@ def set_properties(self, **kwargs):
             # we can set anything the sliver model has a setter for
             self.__getattribute__('set_' + k)(v)
 
+    @staticmethod
+    def _dict_diff(dict_a, dict_b, show_value_diff=False):
+        """
+        supports diffing slivers
+        """
+        result = {'added': {k: dict_b[k] for k in set(dict_b) - set(dict_a)},
+                  'removed': {k: dict_a[k] for k in set(dict_a) - set(dict_b)}}
+        if show_value_diff:
+            common_keys = set(dict_a) & set(dict_b)
+            result['value_diffs'] = {
+                k: (dict_a[k], dict_b[k])
+                for k in common_keys
+                if dict_a[k] != dict_b[k]
+            }
+        return result
+
+    @abstractmethod
+    def diff(self, other_sliver) -> TopologyDiff or None:
+        assert isinstance(self, other_sliver.__class__)
+
     @classmethod
     def list_properties(cls) -> Tuple[str]:
         """
@@ -243,6 +265,17 @@ def get_property(self, prop_name: str):
         """
         return self.__getattribute__('get_' + prop_name)()
 
+    def property_exists(self, prop_name: str):
+        """
+        Does this property have a getter?
+        """
+        try:
+            self.__getattribute__('get_' + prop_name)
+            exists = True
+        except AttributeError:
+            exists = False
+        return exists
+
     def __repr__(self):
         exclude_set = {"get_property", "get_stitch_node"}
         print_set = list()
diff --git a/fim/slivers/capacities_labels.py b/fim/slivers/capacities_labels.py
index 34455dd..8bf731a 100644
--- a/fim/slivers/capacities_labels.py
+++ b/fim/slivers/capacities_labels.py
@@ -355,7 +355,7 @@ class Labels(JSONField):
                                          0 < int(v.split('-')[1]) <= 4096 and
                                          int(v.split('-')[0]) < int(v.split('-')[1]) else False),
                        "1-4096"),
-        'asn': ((lambda a: True if 0 < int(a) < 65536 else False), "1-65535")
+        'asn': ((lambda a: True if 0 < int(a) < 2**32 else False), "1-4294967295")
     }
 
     def __init__(self, **kwargs):
@@ -561,7 +561,8 @@ class Flags(JSONField):
     JSON-ified representation of various flags that can be attached to slivers
     """
     def __init__(self, **kwargs):
-        self.auto_config = False
+        self.auto_config = False # primarily for interfaces
+        self.auto_mount = False # primarily for storage components
         self._set_fields(**kwargs)
 
     def _set_fields(self, **kwargs):
diff --git a/fim/slivers/data/instance_sizes.json b/fim/slivers/data/instance_sizes.json
index c281c72..7b1579f 100644
--- a/fim/slivers/data/instance_sizes.json
+++ b/fim/slivers/data/instance_sizes.json
@@ -1,27 +1,4872 @@
 {
-  "fabric.c1.m4.d10": {"core":1, "ram":4, "disk": 10},
-  "fabric.c2.m8.d10": {"core":2, "ram":8, "disk": 10},
-  "fabric.c4.m16.d10": {"core":4, "ram":16, "disk": 10},
-  "fabric.c8.m32.d10": {"core":8, "ram":32, "disk": 10},
-  "fabric.c16.m64.d10": {"core":16, "ram":64, "disk": 10},
-  "fabric.c32.m128.d10": {"core":32, "ram":128, "disk": 10},
-  "fabric.c1.m4.d100": {"core":1, "ram":4, "disk": 100},
-  "fabric.c2.m8.d100": {"core":2, "ram":8, "disk": 100},
-  "fabric.c4.m16.d100": {"core":4, "ram":16, "disk": 100},
-  "fabric.c8.m32.d100": {"core":8, "ram":32, "disk": 100},
-  "fabric.c16.m64.d100": {"core":16, "ram":64, "disk": 100},
-  "fabric.c32.m128.d100": {"core":32, "ram":128, "disk": 100},
-  "fabric.c1.m4.d500": {"core":1, "ram":4, "disk": 500},
-  "fabric.c2.m8.d500": {"core":2, "ram":8, "disk": 500},
-  "fabric.c4.m16.d500": {"core":4, "ram":16, "disk": 500},
-  "fabric.c8.m32.d500": {"core":8, "ram":32, "disk": 500},
-  "fabric.c16.m64.d500": {"core":16, "ram":64, "disk": 500},
-  "fabric.c32.m128.d500": {"core":32, "ram":128, "disk": 500},
-  "fabric.c1.m4.d2000": {"core":1, "ram":4, "disk": 2000},
-  "fabric.c2.m8.d2000": {"core":2, "ram":8, "disk": 2000},
-  "fabric.c4.m16.d2000": {"core":4, "ram":16, "disk": 2000},
-  "fabric.c8.m32.d2000": {"core":8, "ram":32, "disk": 2000},
-  "fabric.c16.m64.d2000": {"core":16, "ram":64, "disk": 2000},
-  "fabric.c32.m128.d2000": {"core":32, "ram":128, "disk": 2000},
-  "fabric.c64.m384.d4000": {"core":64, "ram":384, "disk": 4000}
-}
\ No newline at end of file
+  "fabric.c4.m4.d10": {
+    "core": 4,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c4.m4.d100": {
+    "core": 4,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c4.m4.d500": {
+    "core": 4,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c4.m4.d2000": {
+    "core": 4,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c4.m8.d10": {
+    "core": 4,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c4.m8.d100": {
+    "core": 4,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c4.m8.d500": {
+    "core": 4,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c4.m8.d2000": {
+    "core": 4,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c4.m16.d10": {
+    "core": 4,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c4.m16.d100": {
+    "core": 4,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c4.m16.d500": {
+    "core": 4,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c4.m16.d2000": {
+    "core": 4,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c4.m32.d10": {
+    "core": 4,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c4.m32.d100": {
+    "core": 4,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c4.m32.d500": {
+    "core": 4,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c4.m32.d2000": {
+    "core": 4,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c4.m64.d10": {
+    "core": 4,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c4.m64.d100": {
+    "core": 4,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c4.m64.d500": {
+    "core": 4,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c4.m64.d2000": {
+    "core": 4,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c4.m128.d10": {
+    "core": 4,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c4.m128.d100": {
+    "core": 4,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c4.m128.d500": {
+    "core": 4,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c4.m128.d2000": {
+    "core": 4,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c4.m256.d10": {
+    "core": 4,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c4.m256.d100": {
+    "core": 4,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c4.m256.d500": {
+    "core": 4,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c4.m256.d2000": {
+    "core": 4,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c4.m384.d10": {
+    "core": 4,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c4.m384.d100": {
+    "core": 4,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c4.m384.d500": {
+    "core": 4,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c4.m384.d2000": {
+    "core": 4,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c6.m4.d10": {
+    "core": 6,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c6.m4.d100": {
+    "core": 6,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c6.m4.d500": {
+    "core": 6,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c6.m4.d2000": {
+    "core": 6,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c6.m8.d10": {
+    "core": 6,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c6.m8.d100": {
+    "core": 6,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c6.m8.d500": {
+    "core": 6,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c6.m8.d2000": {
+    "core": 6,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c6.m16.d10": {
+    "core": 6,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c6.m16.d100": {
+    "core": 6,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c6.m16.d500": {
+    "core": 6,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c6.m16.d2000": {
+    "core": 6,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c6.m32.d10": {
+    "core": 6,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c6.m32.d100": {
+    "core": 6,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c6.m32.d500": {
+    "core": 6,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c6.m32.d2000": {
+    "core": 6,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c6.m64.d10": {
+    "core": 6,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c6.m64.d100": {
+    "core": 6,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c6.m64.d500": {
+    "core": 6,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c6.m64.d2000": {
+    "core": 6,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c6.m128.d10": {
+    "core": 6,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c6.m128.d100": {
+    "core": 6,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c6.m128.d500": {
+    "core": 6,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c6.m128.d2000": {
+    "core": 6,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c6.m256.d10": {
+    "core": 6,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c6.m256.d100": {
+    "core": 6,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c6.m256.d500": {
+    "core": 6,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c6.m256.d2000": {
+    "core": 6,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c6.m384.d10": {
+    "core": 6,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c6.m384.d100": {
+    "core": 6,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c6.m384.d500": {
+    "core": 6,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c6.m384.d2000": {
+    "core": 6,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c8.m4.d10": {
+    "core": 8,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c8.m4.d100": {
+    "core": 8,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c8.m4.d500": {
+    "core": 8,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c8.m4.d2000": {
+    "core": 8,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c8.m8.d10": {
+    "core": 8,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c8.m8.d100": {
+    "core": 8,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c8.m8.d500": {
+    "core": 8,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c8.m8.d2000": {
+    "core": 8,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c8.m16.d10": {
+    "core": 8,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c8.m16.d100": {
+    "core": 8,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c8.m16.d500": {
+    "core": 8,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c8.m16.d2000": {
+    "core": 8,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c8.m32.d10": {
+    "core": 8,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c8.m32.d100": {
+    "core": 8,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c8.m32.d500": {
+    "core": 8,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c8.m32.d2000": {
+    "core": 8,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c8.m64.d10": {
+    "core": 8,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c8.m64.d100": {
+    "core": 8,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c8.m64.d500": {
+    "core": 8,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c8.m64.d2000": {
+    "core": 8,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c8.m128.d10": {
+    "core": 8,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c8.m128.d100": {
+    "core": 8,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c8.m128.d500": {
+    "core": 8,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c8.m128.d2000": {
+    "core": 8,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c8.m256.d10": {
+    "core": 8,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c8.m256.d100": {
+    "core": 8,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c8.m256.d500": {
+    "core": 8,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c8.m256.d2000": {
+    "core": 8,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c8.m384.d10": {
+    "core": 8,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c8.m384.d100": {
+    "core": 8,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c8.m384.d500": {
+    "core": 8,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c8.m384.d2000": {
+    "core": 8,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c10.m4.d10": {
+    "core": 10,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c10.m4.d100": {
+    "core": 10,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c10.m4.d500": {
+    "core": 10,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c10.m4.d2000": {
+    "core": 10,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c10.m8.d10": {
+    "core": 10,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c10.m8.d100": {
+    "core": 10,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c10.m8.d500": {
+    "core": 10,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c10.m8.d2000": {
+    "core": 10,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c10.m16.d10": {
+    "core": 10,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c10.m16.d100": {
+    "core": 10,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c10.m16.d500": {
+    "core": 10,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c10.m16.d2000": {
+    "core": 10,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c10.m32.d10": {
+    "core": 10,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c10.m32.d100": {
+    "core": 10,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c10.m32.d500": {
+    "core": 10,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c10.m32.d2000": {
+    "core": 10,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c10.m64.d10": {
+    "core": 10,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c10.m64.d100": {
+    "core": 10,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c10.m64.d500": {
+    "core": 10,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c10.m64.d2000": {
+    "core": 10,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c10.m128.d10": {
+    "core": 10,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c10.m128.d100": {
+    "core": 10,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c10.m128.d500": {
+    "core": 10,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c10.m128.d2000": {
+    "core": 10,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c10.m256.d10": {
+    "core": 10,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c10.m256.d100": {
+    "core": 10,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c10.m256.d500": {
+    "core": 10,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c10.m256.d2000": {
+    "core": 10,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c10.m384.d10": {
+    "core": 10,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c10.m384.d100": {
+    "core": 10,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c10.m384.d500": {
+    "core": 10,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c10.m384.d2000": {
+    "core": 10,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c12.m4.d10": {
+    "core": 12,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c12.m4.d100": {
+    "core": 12,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c12.m4.d500": {
+    "core": 12,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c12.m4.d2000": {
+    "core": 12,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c12.m8.d10": {
+    "core": 12,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c12.m8.d100": {
+    "core": 12,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c12.m8.d500": {
+    "core": 12,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c12.m8.d2000": {
+    "core": 12,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c12.m16.d10": {
+    "core": 12,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c12.m16.d100": {
+    "core": 12,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c12.m16.d500": {
+    "core": 12,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c12.m16.d2000": {
+    "core": 12,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c12.m32.d10": {
+    "core": 12,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c12.m32.d100": {
+    "core": 12,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c12.m32.d500": {
+    "core": 12,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c12.m32.d2000": {
+    "core": 12,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c12.m64.d10": {
+    "core": 12,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c12.m64.d100": {
+    "core": 12,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c12.m64.d500": {
+    "core": 12,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c12.m64.d2000": {
+    "core": 12,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c12.m128.d10": {
+    "core": 12,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c12.m128.d100": {
+    "core": 12,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c12.m128.d500": {
+    "core": 12,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c12.m128.d2000": {
+    "core": 12,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c12.m256.d10": {
+    "core": 12,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c12.m256.d100": {
+    "core": 12,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c12.m256.d500": {
+    "core": 12,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c12.m256.d2000": {
+    "core": 12,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c12.m384.d10": {
+    "core": 12,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c12.m384.d100": {
+    "core": 12,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c12.m384.d500": {
+    "core": 12,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c12.m384.d2000": {
+    "core": 12,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c14.m4.d10": {
+    "core": 14,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c14.m4.d100": {
+    "core": 14,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c14.m4.d500": {
+    "core": 14,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c14.m4.d2000": {
+    "core": 14,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c14.m8.d10": {
+    "core": 14,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c14.m8.d100": {
+    "core": 14,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c14.m8.d500": {
+    "core": 14,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c14.m8.d2000": {
+    "core": 14,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c14.m16.d10": {
+    "core": 14,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c14.m16.d100": {
+    "core": 14,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c14.m16.d500": {
+    "core": 14,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c14.m16.d2000": {
+    "core": 14,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c14.m32.d10": {
+    "core": 14,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c14.m32.d100": {
+    "core": 14,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c14.m32.d500": {
+    "core": 14,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c14.m32.d2000": {
+    "core": 14,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c14.m64.d10": {
+    "core": 14,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c14.m64.d100": {
+    "core": 14,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c14.m64.d500": {
+    "core": 14,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c14.m64.d2000": {
+    "core": 14,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c14.m128.d10": {
+    "core": 14,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c14.m128.d100": {
+    "core": 14,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c14.m128.d500": {
+    "core": 14,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c14.m128.d2000": {
+    "core": 14,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c14.m256.d10": {
+    "core": 14,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c14.m256.d100": {
+    "core": 14,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c14.m256.d500": {
+    "core": 14,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c14.m256.d2000": {
+    "core": 14,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c14.m384.d10": {
+    "core": 14,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c14.m384.d100": {
+    "core": 14,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c14.m384.d500": {
+    "core": 14,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c14.m384.d2000": {
+    "core": 14,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c16.m4.d10": {
+    "core": 16,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c16.m4.d100": {
+    "core": 16,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c16.m4.d500": {
+    "core": 16,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c16.m4.d2000": {
+    "core": 16,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c16.m8.d10": {
+    "core": 16,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c16.m8.d100": {
+    "core": 16,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c16.m8.d500": {
+    "core": 16,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c16.m8.d2000": {
+    "core": 16,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c16.m16.d10": {
+    "core": 16,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c16.m16.d100": {
+    "core": 16,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c16.m16.d500": {
+    "core": 16,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c16.m16.d2000": {
+    "core": 16,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c16.m32.d10": {
+    "core": 16,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c16.m32.d100": {
+    "core": 16,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c16.m32.d500": {
+    "core": 16,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c16.m32.d2000": {
+    "core": 16,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c16.m64.d10": {
+    "core": 16,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c16.m64.d100": {
+    "core": 16,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c16.m64.d500": {
+    "core": 16,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c16.m64.d2000": {
+    "core": 16,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c16.m128.d10": {
+    "core": 16,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c16.m128.d100": {
+    "core": 16,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c16.m128.d500": {
+    "core": 16,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c16.m128.d2000": {
+    "core": 16,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c16.m256.d10": {
+    "core": 16,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c16.m256.d100": {
+    "core": 16,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c16.m256.d500": {
+    "core": 16,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c16.m256.d2000": {
+    "core": 16,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c16.m384.d10": {
+    "core": 16,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c16.m384.d100": {
+    "core": 16,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c16.m384.d500": {
+    "core": 16,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c16.m384.d2000": {
+    "core": 16,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c18.m4.d10": {
+    "core": 18,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c18.m4.d100": {
+    "core": 18,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c18.m4.d500": {
+    "core": 18,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c18.m4.d2000": {
+    "core": 18,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c18.m8.d10": {
+    "core": 18,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c18.m8.d100": {
+    "core": 18,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c18.m8.d500": {
+    "core": 18,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c18.m8.d2000": {
+    "core": 18,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c18.m16.d10": {
+    "core": 18,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c18.m16.d100": {
+    "core": 18,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c18.m16.d500": {
+    "core": 18,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c18.m16.d2000": {
+    "core": 18,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c18.m32.d10": {
+    "core": 18,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c18.m32.d100": {
+    "core": 18,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c18.m32.d500": {
+    "core": 18,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c18.m32.d2000": {
+    "core": 18,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c18.m64.d10": {
+    "core": 18,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c18.m64.d100": {
+    "core": 18,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c18.m64.d500": {
+    "core": 18,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c18.m64.d2000": {
+    "core": 18,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c18.m128.d10": {
+    "core": 18,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c18.m128.d100": {
+    "core": 18,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c18.m128.d500": {
+    "core": 18,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c18.m128.d2000": {
+    "core": 18,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c18.m256.d10": {
+    "core": 18,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c18.m256.d100": {
+    "core": 18,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c18.m256.d500": {
+    "core": 18,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c18.m256.d2000": {
+    "core": 18,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c18.m384.d10": {
+    "core": 18,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c18.m384.d100": {
+    "core": 18,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c18.m384.d500": {
+    "core": 18,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c18.m384.d2000": {
+    "core": 18,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c20.m4.d10": {
+    "core": 20,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c20.m4.d100": {
+    "core": 20,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c20.m4.d500": {
+    "core": 20,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c20.m4.d2000": {
+    "core": 20,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c20.m8.d10": {
+    "core": 20,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c20.m8.d100": {
+    "core": 20,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c20.m8.d500": {
+    "core": 20,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c20.m8.d2000": {
+    "core": 20,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c20.m16.d10": {
+    "core": 20,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c20.m16.d100": {
+    "core": 20,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c20.m16.d500": {
+    "core": 20,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c20.m16.d2000": {
+    "core": 20,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c20.m32.d10": {
+    "core": 20,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c20.m32.d100": {
+    "core": 20,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c20.m32.d500": {
+    "core": 20,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c20.m32.d2000": {
+    "core": 20,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c20.m64.d10": {
+    "core": 20,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c20.m64.d100": {
+    "core": 20,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c20.m64.d500": {
+    "core": 20,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c20.m64.d2000": {
+    "core": 20,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c20.m128.d10": {
+    "core": 20,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c20.m128.d100": {
+    "core": 20,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c20.m128.d500": {
+    "core": 20,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c20.m128.d2000": {
+    "core": 20,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c20.m256.d10": {
+    "core": 20,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c20.m256.d100": {
+    "core": 20,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c20.m256.d500": {
+    "core": 20,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c20.m256.d2000": {
+    "core": 20,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c20.m384.d10": {
+    "core": 20,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c20.m384.d100": {
+    "core": 20,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c20.m384.d500": {
+    "core": 20,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c20.m384.d2000": {
+    "core": 20,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c22.m4.d10": {
+    "core": 22,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c22.m4.d100": {
+    "core": 22,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c22.m4.d500": {
+    "core": 22,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c22.m4.d2000": {
+    "core": 22,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c22.m8.d10": {
+    "core": 22,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c22.m8.d100": {
+    "core": 22,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c22.m8.d500": {
+    "core": 22,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c22.m8.d2000": {
+    "core": 22,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c22.m16.d10": {
+    "core": 22,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c22.m16.d100": {
+    "core": 22,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c22.m16.d500": {
+    "core": 22,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c22.m16.d2000": {
+    "core": 22,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c22.m32.d10": {
+    "core": 22,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c22.m32.d100": {
+    "core": 22,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c22.m32.d500": {
+    "core": 22,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c22.m32.d2000": {
+    "core": 22,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c22.m64.d10": {
+    "core": 22,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c22.m64.d100": {
+    "core": 22,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c22.m64.d500": {
+    "core": 22,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c22.m64.d2000": {
+    "core": 22,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c22.m128.d10": {
+    "core": 22,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c22.m128.d100": {
+    "core": 22,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c22.m128.d500": {
+    "core": 22,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c22.m128.d2000": {
+    "core": 22,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c22.m256.d10": {
+    "core": 22,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c22.m256.d100": {
+    "core": 22,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c22.m256.d500": {
+    "core": 22,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c22.m256.d2000": {
+    "core": 22,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c22.m384.d10": {
+    "core": 22,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c22.m384.d100": {
+    "core": 22,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c22.m384.d500": {
+    "core": 22,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c22.m384.d2000": {
+    "core": 22,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c24.m4.d10": {
+    "core": 24,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c24.m4.d100": {
+    "core": 24,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c24.m4.d500": {
+    "core": 24,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c24.m4.d2000": {
+    "core": 24,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c24.m8.d10": {
+    "core": 24,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c24.m8.d100": {
+    "core": 24,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c24.m8.d500": {
+    "core": 24,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c24.m8.d2000": {
+    "core": 24,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c24.m16.d10": {
+    "core": 24,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c24.m16.d100": {
+    "core": 24,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c24.m16.d500": {
+    "core": 24,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c24.m16.d2000": {
+    "core": 24,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c24.m32.d10": {
+    "core": 24,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c24.m32.d100": {
+    "core": 24,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c24.m32.d500": {
+    "core": 24,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c24.m32.d2000": {
+    "core": 24,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c24.m64.d10": {
+    "core": 24,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c24.m64.d100": {
+    "core": 24,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c24.m64.d500": {
+    "core": 24,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c24.m64.d2000": {
+    "core": 24,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c24.m128.d10": {
+    "core": 24,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c24.m128.d100": {
+    "core": 24,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c24.m128.d500": {
+    "core": 24,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c24.m128.d2000": {
+    "core": 24,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c24.m256.d10": {
+    "core": 24,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c24.m256.d100": {
+    "core": 24,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c24.m256.d500": {
+    "core": 24,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c24.m256.d2000": {
+    "core": 24,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c24.m384.d10": {
+    "core": 24,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c24.m384.d100": {
+    "core": 24,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c24.m384.d500": {
+    "core": 24,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c24.m384.d2000": {
+    "core": 24,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c26.m4.d10": {
+    "core": 26,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c26.m4.d100": {
+    "core": 26,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c26.m4.d500": {
+    "core": 26,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c26.m4.d2000": {
+    "core": 26,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c26.m8.d10": {
+    "core": 26,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c26.m8.d100": {
+    "core": 26,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c26.m8.d500": {
+    "core": 26,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c26.m8.d2000": {
+    "core": 26,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c26.m16.d10": {
+    "core": 26,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c26.m16.d100": {
+    "core": 26,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c26.m16.d500": {
+    "core": 26,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c26.m16.d2000": {
+    "core": 26,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c26.m32.d10": {
+    "core": 26,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c26.m32.d100": {
+    "core": 26,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c26.m32.d500": {
+    "core": 26,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c26.m32.d2000": {
+    "core": 26,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c26.m64.d10": {
+    "core": 26,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c26.m64.d100": {
+    "core": 26,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c26.m64.d500": {
+    "core": 26,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c26.m64.d2000": {
+    "core": 26,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c26.m128.d10": {
+    "core": 26,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c26.m128.d100": {
+    "core": 26,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c26.m128.d500": {
+    "core": 26,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c26.m128.d2000": {
+    "core": 26,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c26.m256.d10": {
+    "core": 26,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c26.m256.d100": {
+    "core": 26,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c26.m256.d500": {
+    "core": 26,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c26.m256.d2000": {
+    "core": 26,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c26.m384.d10": {
+    "core": 26,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c26.m384.d100": {
+    "core": 26,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c26.m384.d500": {
+    "core": 26,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c26.m384.d2000": {
+    "core": 26,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c28.m4.d10": {
+    "core": 28,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c28.m4.d100": {
+    "core": 28,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c28.m4.d500": {
+    "core": 28,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c28.m4.d2000": {
+    "core": 28,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c28.m8.d10": {
+    "core": 28,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c28.m8.d100": {
+    "core": 28,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c28.m8.d500": {
+    "core": 28,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c28.m8.d2000": {
+    "core": 28,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c28.m16.d10": {
+    "core": 28,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c28.m16.d100": {
+    "core": 28,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c28.m16.d500": {
+    "core": 28,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c28.m16.d2000": {
+    "core": 28,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c28.m32.d10": {
+    "core": 28,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c28.m32.d100": {
+    "core": 28,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c28.m32.d500": {
+    "core": 28,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c28.m32.d2000": {
+    "core": 28,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c28.m64.d10": {
+    "core": 28,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c28.m64.d100": {
+    "core": 28,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c28.m64.d500": {
+    "core": 28,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c28.m64.d2000": {
+    "core": 28,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c28.m128.d10": {
+    "core": 28,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c28.m128.d100": {
+    "core": 28,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c28.m128.d500": {
+    "core": 28,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c28.m128.d2000": {
+    "core": 28,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c28.m256.d10": {
+    "core": 28,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c28.m256.d100": {
+    "core": 28,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c28.m256.d500": {
+    "core": 28,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c28.m256.d2000": {
+    "core": 28,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c28.m384.d10": {
+    "core": 28,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c28.m384.d100": {
+    "core": 28,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c28.m384.d500": {
+    "core": 28,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c28.m384.d2000": {
+    "core": 28,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c30.m4.d10": {
+    "core": 30,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c30.m4.d100": {
+    "core": 30,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c30.m4.d500": {
+    "core": 30,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c30.m4.d2000": {
+    "core": 30,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c30.m8.d10": {
+    "core": 30,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c30.m8.d100": {
+    "core": 30,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c30.m8.d500": {
+    "core": 30,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c30.m8.d2000": {
+    "core": 30,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c30.m16.d10": {
+    "core": 30,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c30.m16.d100": {
+    "core": 30,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c30.m16.d500": {
+    "core": 30,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c30.m16.d2000": {
+    "core": 30,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c30.m32.d10": {
+    "core": 30,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c30.m32.d100": {
+    "core": 30,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c30.m32.d500": {
+    "core": 30,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c30.m32.d2000": {
+    "core": 30,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c30.m64.d10": {
+    "core": 30,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c30.m64.d100": {
+    "core": 30,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c30.m64.d500": {
+    "core": 30,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c30.m64.d2000": {
+    "core": 30,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c30.m128.d10": {
+    "core": 30,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c30.m128.d100": {
+    "core": 30,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c30.m128.d500": {
+    "core": 30,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c30.m128.d2000": {
+    "core": 30,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c30.m256.d10": {
+    "core": 30,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c30.m256.d100": {
+    "core": 30,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c30.m256.d500": {
+    "core": 30,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c30.m256.d2000": {
+    "core": 30,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c30.m384.d10": {
+    "core": 30,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c30.m384.d100": {
+    "core": 30,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c30.m384.d500": {
+    "core": 30,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c30.m384.d2000": {
+    "core": 30,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c32.m4.d10": {
+    "core": 32,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c32.m4.d100": {
+    "core": 32,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c32.m4.d500": {
+    "core": 32,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c32.m4.d2000": {
+    "core": 32,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c32.m8.d10": {
+    "core": 32,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c32.m8.d100": {
+    "core": 32,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c32.m8.d500": {
+    "core": 32,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c32.m8.d2000": {
+    "core": 32,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c32.m16.d10": {
+    "core": 32,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c32.m16.d100": {
+    "core": 32,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c32.m16.d500": {
+    "core": 32,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c32.m16.d2000": {
+    "core": 32,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c32.m32.d10": {
+    "core": 32,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c32.m32.d100": {
+    "core": 32,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c32.m32.d500": {
+    "core": 32,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c32.m32.d2000": {
+    "core": 32,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c32.m64.d10": {
+    "core": 32,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c32.m64.d100": {
+    "core": 32,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c32.m64.d500": {
+    "core": 32,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c32.m64.d2000": {
+    "core": 32,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c32.m128.d10": {
+    "core": 32,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c32.m128.d100": {
+    "core": 32,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c32.m128.d500": {
+    "core": 32,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c32.m128.d2000": {
+    "core": 32,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c32.m256.d10": {
+    "core": 32,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c32.m256.d100": {
+    "core": 32,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c32.m256.d500": {
+    "core": 32,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c32.m256.d2000": {
+    "core": 32,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c32.m384.d10": {
+    "core": 32,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c32.m384.d100": {
+    "core": 32,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c32.m384.d500": {
+    "core": 32,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c32.m384.d2000": {
+    "core": 32,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c34.m4.d10": {
+    "core": 34,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c34.m4.d100": {
+    "core": 34,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c34.m4.d500": {
+    "core": 34,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c34.m4.d2000": {
+    "core": 34,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c34.m8.d10": {
+    "core": 34,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c34.m8.d100": {
+    "core": 34,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c34.m8.d500": {
+    "core": 34,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c34.m8.d2000": {
+    "core": 34,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c34.m16.d10": {
+    "core": 34,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c34.m16.d100": {
+    "core": 34,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c34.m16.d500": {
+    "core": 34,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c34.m16.d2000": {
+    "core": 34,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c34.m32.d10": {
+    "core": 34,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c34.m32.d100": {
+    "core": 34,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c34.m32.d500": {
+    "core": 34,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c34.m32.d2000": {
+    "core": 34,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c34.m64.d10": {
+    "core": 34,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c34.m64.d100": {
+    "core": 34,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c34.m64.d500": {
+    "core": 34,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c34.m64.d2000": {
+    "core": 34,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c34.m128.d10": {
+    "core": 34,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c34.m128.d100": {
+    "core": 34,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c34.m128.d500": {
+    "core": 34,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c34.m128.d2000": {
+    "core": 34,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c34.m256.d10": {
+    "core": 34,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c34.m256.d100": {
+    "core": 34,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c34.m256.d500": {
+    "core": 34,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c34.m256.d2000": {
+    "core": 34,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c34.m384.d10": {
+    "core": 34,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c34.m384.d100": {
+    "core": 34,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c34.m384.d500": {
+    "core": 34,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c34.m384.d2000": {
+    "core": 34,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c36.m4.d10": {
+    "core": 36,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c36.m4.d100": {
+    "core": 36,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c36.m4.d500": {
+    "core": 36,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c36.m4.d2000": {
+    "core": 36,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c36.m8.d10": {
+    "core": 36,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c36.m8.d100": {
+    "core": 36,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c36.m8.d500": {
+    "core": 36,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c36.m8.d2000": {
+    "core": 36,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c36.m16.d10": {
+    "core": 36,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c36.m16.d100": {
+    "core": 36,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c36.m16.d500": {
+    "core": 36,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c36.m16.d2000": {
+    "core": 36,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c36.m32.d10": {
+    "core": 36,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c36.m32.d100": {
+    "core": 36,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c36.m32.d500": {
+    "core": 36,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c36.m32.d2000": {
+    "core": 36,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c36.m64.d10": {
+    "core": 36,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c36.m64.d100": {
+    "core": 36,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c36.m64.d500": {
+    "core": 36,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c36.m64.d2000": {
+    "core": 36,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c36.m128.d10": {
+    "core": 36,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c36.m128.d100": {
+    "core": 36,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c36.m128.d500": {
+    "core": 36,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c36.m128.d2000": {
+    "core": 36,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c36.m256.d10": {
+    "core": 36,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c36.m256.d100": {
+    "core": 36,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c36.m256.d500": {
+    "core": 36,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c36.m256.d2000": {
+    "core": 36,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c36.m384.d10": {
+    "core": 36,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c36.m384.d100": {
+    "core": 36,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c36.m384.d500": {
+    "core": 36,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c36.m384.d2000": {
+    "core": 36,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c38.m4.d10": {
+    "core": 38,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c38.m4.d100": {
+    "core": 38,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c38.m4.d500": {
+    "core": 38,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c38.m4.d2000": {
+    "core": 38,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c38.m8.d10": {
+    "core": 38,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c38.m8.d100": {
+    "core": 38,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c38.m8.d500": {
+    "core": 38,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c38.m8.d2000": {
+    "core": 38,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c38.m16.d10": {
+    "core": 38,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c38.m16.d100": {
+    "core": 38,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c38.m16.d500": {
+    "core": 38,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c38.m16.d2000": {
+    "core": 38,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c38.m32.d10": {
+    "core": 38,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c38.m32.d100": {
+    "core": 38,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c38.m32.d500": {
+    "core": 38,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c38.m32.d2000": {
+    "core": 38,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c38.m64.d10": {
+    "core": 38,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c38.m64.d100": {
+    "core": 38,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c38.m64.d500": {
+    "core": 38,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c38.m64.d2000": {
+    "core": 38,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c38.m128.d10": {
+    "core": 38,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c38.m128.d100": {
+    "core": 38,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c38.m128.d500": {
+    "core": 38,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c38.m128.d2000": {
+    "core": 38,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c38.m256.d10": {
+    "core": 38,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c38.m256.d100": {
+    "core": 38,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c38.m256.d500": {
+    "core": 38,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c38.m256.d2000": {
+    "core": 38,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c38.m384.d10": {
+    "core": 38,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c38.m384.d100": {
+    "core": 38,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c38.m384.d500": {
+    "core": 38,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c38.m384.d2000": {
+    "core": 38,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c40.m4.d10": {
+    "core": 40,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c40.m4.d100": {
+    "core": 40,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c40.m4.d500": {
+    "core": 40,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c40.m4.d2000": {
+    "core": 40,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c40.m8.d10": {
+    "core": 40,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c40.m8.d100": {
+    "core": 40,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c40.m8.d500": {
+    "core": 40,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c40.m8.d2000": {
+    "core": 40,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c40.m16.d10": {
+    "core": 40,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c40.m16.d100": {
+    "core": 40,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c40.m16.d500": {
+    "core": 40,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c40.m16.d2000": {
+    "core": 40,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c40.m32.d10": {
+    "core": 40,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c40.m32.d100": {
+    "core": 40,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c40.m32.d500": {
+    "core": 40,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c40.m32.d2000": {
+    "core": 40,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c40.m64.d10": {
+    "core": 40,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c40.m64.d100": {
+    "core": 40,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c40.m64.d500": {
+    "core": 40,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c40.m64.d2000": {
+    "core": 40,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c40.m128.d10": {
+    "core": 40,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c40.m128.d100": {
+    "core": 40,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c40.m128.d500": {
+    "core": 40,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c40.m128.d2000": {
+    "core": 40,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c40.m256.d10": {
+    "core": 40,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c40.m256.d100": {
+    "core": 40,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c40.m256.d500": {
+    "core": 40,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c40.m256.d2000": {
+    "core": 40,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c40.m384.d10": {
+    "core": 40,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c40.m384.d100": {
+    "core": 40,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c40.m384.d500": {
+    "core": 40,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c40.m384.d2000": {
+    "core": 40,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c42.m4.d10": {
+    "core": 42,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c42.m4.d100": {
+    "core": 42,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c42.m4.d500": {
+    "core": 42,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c42.m4.d2000": {
+    "core": 42,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c42.m8.d10": {
+    "core": 42,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c42.m8.d100": {
+    "core": 42,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c42.m8.d500": {
+    "core": 42,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c42.m8.d2000": {
+    "core": 42,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c42.m16.d10": {
+    "core": 42,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c42.m16.d100": {
+    "core": 42,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c42.m16.d500": {
+    "core": 42,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c42.m16.d2000": {
+    "core": 42,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c42.m32.d10": {
+    "core": 42,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c42.m32.d100": {
+    "core": 42,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c42.m32.d500": {
+    "core": 42,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c42.m32.d2000": {
+    "core": 42,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c42.m64.d10": {
+    "core": 42,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c42.m64.d100": {
+    "core": 42,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c42.m64.d500": {
+    "core": 42,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c42.m64.d2000": {
+    "core": 42,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c42.m128.d10": {
+    "core": 42,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c42.m128.d100": {
+    "core": 42,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c42.m128.d500": {
+    "core": 42,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c42.m128.d2000": {
+    "core": 42,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c42.m256.d10": {
+    "core": 42,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c42.m256.d100": {
+    "core": 42,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c42.m256.d500": {
+    "core": 42,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c42.m256.d2000": {
+    "core": 42,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c42.m384.d10": {
+    "core": 42,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c42.m384.d100": {
+    "core": 42,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c42.m384.d500": {
+    "core": 42,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c42.m384.d2000": {
+    "core": 42,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c44.m4.d10": {
+    "core": 44,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c44.m4.d100": {
+    "core": 44,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c44.m4.d500": {
+    "core": 44,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c44.m4.d2000": {
+    "core": 44,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c44.m8.d10": {
+    "core": 44,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c44.m8.d100": {
+    "core": 44,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c44.m8.d500": {
+    "core": 44,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c44.m8.d2000": {
+    "core": 44,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c44.m16.d10": {
+    "core": 44,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c44.m16.d100": {
+    "core": 44,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c44.m16.d500": {
+    "core": 44,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c44.m16.d2000": {
+    "core": 44,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c44.m32.d10": {
+    "core": 44,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c44.m32.d100": {
+    "core": 44,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c44.m32.d500": {
+    "core": 44,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c44.m32.d2000": {
+    "core": 44,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c44.m64.d10": {
+    "core": 44,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c44.m64.d100": {
+    "core": 44,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c44.m64.d500": {
+    "core": 44,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c44.m64.d2000": {
+    "core": 44,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c44.m128.d10": {
+    "core": 44,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c44.m128.d100": {
+    "core": 44,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c44.m128.d500": {
+    "core": 44,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c44.m128.d2000": {
+    "core": 44,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c44.m256.d10": {
+    "core": 44,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c44.m256.d100": {
+    "core": 44,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c44.m256.d500": {
+    "core": 44,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c44.m256.d2000": {
+    "core": 44,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c44.m384.d10": {
+    "core": 44,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c44.m384.d100": {
+    "core": 44,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c44.m384.d500": {
+    "core": 44,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c44.m384.d2000": {
+    "core": 44,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c46.m4.d10": {
+    "core": 46,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c46.m4.d100": {
+    "core": 46,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c46.m4.d500": {
+    "core": 46,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c46.m4.d2000": {
+    "core": 46,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c46.m8.d10": {
+    "core": 46,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c46.m8.d100": {
+    "core": 46,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c46.m8.d500": {
+    "core": 46,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c46.m8.d2000": {
+    "core": 46,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c46.m16.d10": {
+    "core": 46,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c46.m16.d100": {
+    "core": 46,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c46.m16.d500": {
+    "core": 46,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c46.m16.d2000": {
+    "core": 46,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c46.m32.d10": {
+    "core": 46,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c46.m32.d100": {
+    "core": 46,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c46.m32.d500": {
+    "core": 46,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c46.m32.d2000": {
+    "core": 46,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c46.m64.d10": {
+    "core": 46,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c46.m64.d100": {
+    "core": 46,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c46.m64.d500": {
+    "core": 46,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c46.m64.d2000": {
+    "core": 46,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c46.m128.d10": {
+    "core": 46,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c46.m128.d100": {
+    "core": 46,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c46.m128.d500": {
+    "core": 46,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c46.m128.d2000": {
+    "core": 46,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c46.m256.d10": {
+    "core": 46,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c46.m256.d100": {
+    "core": 46,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c46.m256.d500": {
+    "core": 46,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c46.m256.d2000": {
+    "core": 46,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c46.m384.d10": {
+    "core": 46,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c46.m384.d100": {
+    "core": 46,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c46.m384.d500": {
+    "core": 46,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c46.m384.d2000": {
+    "core": 46,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c48.m4.d10": {
+    "core": 48,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c48.m4.d100": {
+    "core": 48,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c48.m4.d500": {
+    "core": 48,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c48.m4.d2000": {
+    "core": 48,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c48.m8.d10": {
+    "core": 48,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c48.m8.d100": {
+    "core": 48,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c48.m8.d500": {
+    "core": 48,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c48.m8.d2000": {
+    "core": 48,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c48.m16.d10": {
+    "core": 48,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c48.m16.d100": {
+    "core": 48,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c48.m16.d500": {
+    "core": 48,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c48.m16.d2000": {
+    "core": 48,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c48.m32.d10": {
+    "core": 48,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c48.m32.d100": {
+    "core": 48,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c48.m32.d500": {
+    "core": 48,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c48.m32.d2000": {
+    "core": 48,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c48.m64.d10": {
+    "core": 48,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c48.m64.d100": {
+    "core": 48,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c48.m64.d500": {
+    "core": 48,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c48.m64.d2000": {
+    "core": 48,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c48.m128.d10": {
+    "core": 48,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c48.m128.d100": {
+    "core": 48,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c48.m128.d500": {
+    "core": 48,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c48.m128.d2000": {
+    "core": 48,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c48.m256.d10": {
+    "core": 48,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c48.m256.d100": {
+    "core": 48,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c48.m256.d500": {
+    "core": 48,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c48.m256.d2000": {
+    "core": 48,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c48.m384.d10": {
+    "core": 48,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c48.m384.d100": {
+    "core": 48,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c48.m384.d500": {
+    "core": 48,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c48.m384.d2000": {
+    "core": 48,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c50.m4.d10": {
+    "core": 50,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c50.m4.d100": {
+    "core": 50,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c50.m4.d500": {
+    "core": 50,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c50.m4.d2000": {
+    "core": 50,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c50.m8.d10": {
+    "core": 50,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c50.m8.d100": {
+    "core": 50,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c50.m8.d500": {
+    "core": 50,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c50.m8.d2000": {
+    "core": 50,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c50.m16.d10": {
+    "core": 50,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c50.m16.d100": {
+    "core": 50,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c50.m16.d500": {
+    "core": 50,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c50.m16.d2000": {
+    "core": 50,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c50.m32.d10": {
+    "core": 50,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c50.m32.d100": {
+    "core": 50,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c50.m32.d500": {
+    "core": 50,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c50.m32.d2000": {
+    "core": 50,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c50.m64.d10": {
+    "core": 50,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c50.m64.d100": {
+    "core": 50,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c50.m64.d500": {
+    "core": 50,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c50.m64.d2000": {
+    "core": 50,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c50.m128.d10": {
+    "core": 50,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c50.m128.d100": {
+    "core": 50,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c50.m128.d500": {
+    "core": 50,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c50.m128.d2000": {
+    "core": 50,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c50.m256.d10": {
+    "core": 50,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c50.m256.d100": {
+    "core": 50,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c50.m256.d500": {
+    "core": 50,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c50.m256.d2000": {
+    "core": 50,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c50.m384.d10": {
+    "core": 50,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c50.m384.d100": {
+    "core": 50,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c50.m384.d500": {
+    "core": 50,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c50.m384.d2000": {
+    "core": 50,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c52.m4.d10": {
+    "core": 52,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c52.m4.d100": {
+    "core": 52,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c52.m4.d500": {
+    "core": 52,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c52.m4.d2000": {
+    "core": 52,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c52.m8.d10": {
+    "core": 52,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c52.m8.d100": {
+    "core": 52,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c52.m8.d500": {
+    "core": 52,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c52.m8.d2000": {
+    "core": 52,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c52.m16.d10": {
+    "core": 52,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c52.m16.d100": {
+    "core": 52,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c52.m16.d500": {
+    "core": 52,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c52.m16.d2000": {
+    "core": 52,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c52.m32.d10": {
+    "core": 52,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c52.m32.d100": {
+    "core": 52,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c52.m32.d500": {
+    "core": 52,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c52.m32.d2000": {
+    "core": 52,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c52.m64.d10": {
+    "core": 52,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c52.m64.d100": {
+    "core": 52,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c52.m64.d500": {
+    "core": 52,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c52.m64.d2000": {
+    "core": 52,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c52.m128.d10": {
+    "core": 52,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c52.m128.d100": {
+    "core": 52,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c52.m128.d500": {
+    "core": 52,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c52.m128.d2000": {
+    "core": 52,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c52.m256.d10": {
+    "core": 52,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c52.m256.d100": {
+    "core": 52,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c52.m256.d500": {
+    "core": 52,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c52.m256.d2000": {
+    "core": 52,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c52.m384.d10": {
+    "core": 52,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c52.m384.d100": {
+    "core": 52,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c52.m384.d500": {
+    "core": 52,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c52.m384.d2000": {
+    "core": 52,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c54.m4.d10": {
+    "core": 54,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c54.m4.d100": {
+    "core": 54,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c54.m4.d500": {
+    "core": 54,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c54.m4.d2000": {
+    "core": 54,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c54.m8.d10": {
+    "core": 54,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c54.m8.d100": {
+    "core": 54,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c54.m8.d500": {
+    "core": 54,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c54.m8.d2000": {
+    "core": 54,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c54.m16.d10": {
+    "core": 54,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c54.m16.d100": {
+    "core": 54,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c54.m16.d500": {
+    "core": 54,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c54.m16.d2000": {
+    "core": 54,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c54.m32.d10": {
+    "core": 54,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c54.m32.d100": {
+    "core": 54,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c54.m32.d500": {
+    "core": 54,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c54.m32.d2000": {
+    "core": 54,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c54.m64.d10": {
+    "core": 54,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c54.m64.d100": {
+    "core": 54,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c54.m64.d500": {
+    "core": 54,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c54.m64.d2000": {
+    "core": 54,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c54.m128.d10": {
+    "core": 54,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c54.m128.d100": {
+    "core": 54,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c54.m128.d500": {
+    "core": 54,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c54.m128.d2000": {
+    "core": 54,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c54.m256.d10": {
+    "core": 54,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c54.m256.d100": {
+    "core": 54,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c54.m256.d500": {
+    "core": 54,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c54.m256.d2000": {
+    "core": 54,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c54.m384.d10": {
+    "core": 54,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c54.m384.d100": {
+    "core": 54,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c54.m384.d500": {
+    "core": 54,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c54.m384.d2000": {
+    "core": 54,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c56.m4.d10": {
+    "core": 56,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c56.m4.d100": {
+    "core": 56,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c56.m4.d500": {
+    "core": 56,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c56.m4.d2000": {
+    "core": 56,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c56.m8.d10": {
+    "core": 56,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c56.m8.d100": {
+    "core": 56,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c56.m8.d500": {
+    "core": 56,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c56.m8.d2000": {
+    "core": 56,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c56.m16.d10": {
+    "core": 56,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c56.m16.d100": {
+    "core": 56,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c56.m16.d500": {
+    "core": 56,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c56.m16.d2000": {
+    "core": 56,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c56.m32.d10": {
+    "core": 56,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c56.m32.d100": {
+    "core": 56,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c56.m32.d500": {
+    "core": 56,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c56.m32.d2000": {
+    "core": 56,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c56.m64.d10": {
+    "core": 56,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c56.m64.d100": {
+    "core": 56,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c56.m64.d500": {
+    "core": 56,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c56.m64.d2000": {
+    "core": 56,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c56.m128.d10": {
+    "core": 56,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c56.m128.d100": {
+    "core": 56,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c56.m128.d500": {
+    "core": 56,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c56.m128.d2000": {
+    "core": 56,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c56.m256.d10": {
+    "core": 56,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c56.m256.d100": {
+    "core": 56,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c56.m256.d500": {
+    "core": 56,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c56.m256.d2000": {
+    "core": 56,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c56.m384.d10": {
+    "core": 56,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c56.m384.d100": {
+    "core": 56,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c56.m384.d500": {
+    "core": 56,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c56.m384.d2000": {
+    "core": 56,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c58.m4.d10": {
+    "core": 58,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c58.m4.d100": {
+    "core": 58,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c58.m4.d500": {
+    "core": 58,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c58.m4.d2000": {
+    "core": 58,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c58.m8.d10": {
+    "core": 58,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c58.m8.d100": {
+    "core": 58,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c58.m8.d500": {
+    "core": 58,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c58.m8.d2000": {
+    "core": 58,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c58.m16.d10": {
+    "core": 58,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c58.m16.d100": {
+    "core": 58,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c58.m16.d500": {
+    "core": 58,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c58.m16.d2000": {
+    "core": 58,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c58.m32.d10": {
+    "core": 58,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c58.m32.d100": {
+    "core": 58,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c58.m32.d500": {
+    "core": 58,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c58.m32.d2000": {
+    "core": 58,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c58.m64.d10": {
+    "core": 58,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c58.m64.d100": {
+    "core": 58,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c58.m64.d500": {
+    "core": 58,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c58.m64.d2000": {
+    "core": 58,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c58.m128.d10": {
+    "core": 58,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c58.m128.d100": {
+    "core": 58,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c58.m128.d500": {
+    "core": 58,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c58.m128.d2000": {
+    "core": 58,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c58.m256.d10": {
+    "core": 58,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c58.m256.d100": {
+    "core": 58,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c58.m256.d500": {
+    "core": 58,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c58.m256.d2000": {
+    "core": 58,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c58.m384.d10": {
+    "core": 58,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c58.m384.d100": {
+    "core": 58,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c58.m384.d500": {
+    "core": 58,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c58.m384.d2000": {
+    "core": 58,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c60.m4.d10": {
+    "core": 60,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c60.m4.d100": {
+    "core": 60,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c60.m4.d500": {
+    "core": 60,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c60.m4.d2000": {
+    "core": 60,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c60.m8.d10": {
+    "core": 60,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c60.m8.d100": {
+    "core": 60,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c60.m8.d500": {
+    "core": 60,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c60.m8.d2000": {
+    "core": 60,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c60.m16.d10": {
+    "core": 60,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c60.m16.d100": {
+    "core": 60,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c60.m16.d500": {
+    "core": 60,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c60.m16.d2000": {
+    "core": 60,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c60.m32.d10": {
+    "core": 60,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c60.m32.d100": {
+    "core": 60,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c60.m32.d500": {
+    "core": 60,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c60.m32.d2000": {
+    "core": 60,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c60.m64.d10": {
+    "core": 60,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c60.m64.d100": {
+    "core": 60,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c60.m64.d500": {
+    "core": 60,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c60.m64.d2000": {
+    "core": 60,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c60.m128.d10": {
+    "core": 60,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c60.m128.d100": {
+    "core": 60,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c60.m128.d500": {
+    "core": 60,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c60.m128.d2000": {
+    "core": 60,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c60.m256.d10": {
+    "core": 60,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c60.m256.d100": {
+    "core": 60,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c60.m256.d500": {
+    "core": 60,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c60.m256.d2000": {
+    "core": 60,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c60.m384.d10": {
+    "core": 60,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c60.m384.d100": {
+    "core": 60,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c60.m384.d500": {
+    "core": 60,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c60.m384.d2000": {
+    "core": 60,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c62.m4.d10": {
+    "core": 62,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c62.m4.d100": {
+    "core": 62,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c62.m4.d500": {
+    "core": 62,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c62.m4.d2000": {
+    "core": 62,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c62.m8.d10": {
+    "core": 62,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c62.m8.d100": {
+    "core": 62,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c62.m8.d500": {
+    "core": 62,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c62.m8.d2000": {
+    "core": 62,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c62.m16.d10": {
+    "core": 62,
+    "ram": 16,
+    "disk": 10
+  },
+  "fabric.c62.m16.d100": {
+    "core": 62,
+    "ram": 16,
+    "disk": 100
+  },
+  "fabric.c62.m16.d500": {
+    "core": 62,
+    "ram": 16,
+    "disk": 500
+  },
+  "fabric.c62.m16.d2000": {
+    "core": 62,
+    "ram": 16,
+    "disk": 2000
+  },
+  "fabric.c62.m32.d10": {
+    "core": 62,
+    "ram": 32,
+    "disk": 10
+  },
+  "fabric.c62.m32.d100": {
+    "core": 62,
+    "ram": 32,
+    "disk": 100
+  },
+  "fabric.c62.m32.d500": {
+    "core": 62,
+    "ram": 32,
+    "disk": 500
+  },
+  "fabric.c62.m32.d2000": {
+    "core": 62,
+    "ram": 32,
+    "disk": 2000
+  },
+  "fabric.c62.m64.d10": {
+    "core": 62,
+    "ram": 64,
+    "disk": 10
+  },
+  "fabric.c62.m64.d100": {
+    "core": 62,
+    "ram": 64,
+    "disk": 100
+  },
+  "fabric.c62.m64.d500": {
+    "core": 62,
+    "ram": 64,
+    "disk": 500
+  },
+  "fabric.c62.m64.d2000": {
+    "core": 62,
+    "ram": 64,
+    "disk": 2000
+  },
+  "fabric.c62.m128.d10": {
+    "core": 62,
+    "ram": 128,
+    "disk": 10
+  },
+  "fabric.c62.m128.d100": {
+    "core": 62,
+    "ram": 128,
+    "disk": 100
+  },
+  "fabric.c62.m128.d500": {
+    "core": 62,
+    "ram": 128,
+    "disk": 500
+  },
+  "fabric.c62.m128.d2000": {
+    "core": 62,
+    "ram": 128,
+    "disk": 2000
+  },
+  "fabric.c62.m256.d10": {
+    "core": 62,
+    "ram": 256,
+    "disk": 10
+  },
+  "fabric.c62.m256.d100": {
+    "core": 62,
+    "ram": 256,
+    "disk": 100
+  },
+  "fabric.c62.m256.d500": {
+    "core": 62,
+    "ram": 256,
+    "disk": 500
+  },
+  "fabric.c62.m256.d2000": {
+    "core": 62,
+    "ram": 256,
+    "disk": 2000
+  },
+  "fabric.c62.m384.d10": {
+    "core": 62,
+    "ram": 384,
+    "disk": 10
+  },
+  "fabric.c62.m384.d100": {
+    "core": 62,
+    "ram": 384,
+    "disk": 100
+  },
+  "fabric.c62.m384.d500": {
+    "core": 62,
+    "ram": 384,
+    "disk": 500
+  },
+  "fabric.c62.m384.d2000": {
+    "core": 62,
+    "ram": 384,
+    "disk": 2000
+  },
+  "fabric.c1.m2.d10": {
+    "core": 1,
+    "ram": 2,
+    "disk": 10
+  },
+  "fabric.c1.m4.d10": {
+    "core": 1,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c1.m4.d100": {
+    "core": 1,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c1.m4.d500": {
+    "core": 1,
+    "ram": 4,
+    "disk": 500
+  },
+  "fabric.c1.m4.d2000": {
+    "core": 1,
+    "ram": 4,
+    "disk": 2000
+  },
+  "fabric.c2.m2.d10": {
+    "core": 2,
+    "ram": 2,
+    "disk": 10
+  },
+  "fabric.c2.m2.d100": {
+    "core": 2,
+    "ram": 2,
+    "disk": 100
+  },
+  "fabric.c2.m4.d10": {
+    "core": 2,
+    "ram": 4,
+    "disk": 10
+  },
+  "fabric.c2.m4.d100": {
+    "core": 2,
+    "ram": 4,
+    "disk": 100
+  },
+  "fabric.c2.m8.d10": {
+    "core": 2,
+    "ram": 8,
+    "disk": 10
+  },
+  "fabric.c2.m8.d100": {
+    "core": 2,
+    "ram": 8,
+    "disk": 100
+  },
+  "fabric.c2.m8.d500": {
+    "core": 2,
+    "ram": 8,
+    "disk": 500
+  },
+  "fabric.c2.m8.d2000": {
+    "core": 2,
+    "ram": 8,
+    "disk": 2000
+  },
+  "fabric.c64.m384.d4000": {
+    "core": 64,
+    "ram": 384,
+    "disk": 4000
+  }
+}
diff --git a/fim/slivers/interface_info.py b/fim/slivers/interface_info.py
index 2b41ac9..51a3eef 100644
--- a/fim/slivers/interface_info.py
+++ b/fim/slivers/interface_info.py
@@ -28,6 +28,7 @@
 import enum
 
 from .base_sliver import BaseSliver
+from .topology_diff import TopologyDiff
 
 
 class InterfaceType(enum.Enum):
@@ -67,6 +68,8 @@ def type_from_str(ntype: str) -> InterfaceType:
             if ntype == str(t):
                 return t
 
+    def diff(self, other_sliver) -> TopologyDiff or None:
+        raise RuntimeError('Not implemented')
 
 class InterfaceInfo:
     def __init__(self):
diff --git a/fim/slivers/network_link.py b/fim/slivers/network_link.py
index d4a9716..04f7a5d 100644
--- a/fim/slivers/network_link.py
+++ b/fim/slivers/network_link.py
@@ -28,6 +28,7 @@
 
 from .base_sliver import BaseSliver
 from .network_service import NSLayer
+from .topology_diff import TopologyDiff
 
 
 class LinkType(enum.Enum):
@@ -110,3 +111,5 @@ def layer_from_str(layer: str) -> NSLayer or None:
             return None
         return NSLayer.from_string(layer)
 
+    def diff(self, other_sliver) -> TopologyDiff or None:
+        raise RuntimeError('Not implemented')
diff --git a/fim/slivers/network_node.py b/fim/slivers/network_node.py
index 7923abb..20c4eae 100644
--- a/fim/slivers/network_node.py
+++ b/fim/slivers/network_node.py
@@ -29,6 +29,7 @@
 
 from fim.slivers.capacities_labels import Location
 from .base_sliver import BaseSliver
+from .topology_diff import TopologyDiff, TopologyDiffTuple
 
 
 class NodeType(enum.Enum):
@@ -145,6 +146,49 @@ def set_location(self, location: Location):
     def get_location(self) -> Location:
         return self.location
 
+    def diff(self, other_sliver) -> TopologyDiff or None:
+        if not other_sliver:
+            return None
+
+        super().diff(other_sliver)
+
+        comp_added = set()
+        comp_removed = set()
+        ns_added = set()
+        ns_removed = set()
+
+        if self.attached_components_info and other_sliver.attached_components_info:
+            diff_comps = self._dict_diff(self.attached_components_info.devices,
+                                         other_sliver.attached_components_info.devices)
+            comp_added = set(diff_comps['added'].keys())
+            comp_removed = set(diff_comps['removed'].keys())
+
+        if not self.attached_components_info and other_sliver.attached_components_info:
+            comp_added = set(other_sliver.attached_components_info.devices.keys())
+
+        if self.attached_components_info and not other_sliver.attached_components_info:
+            comp_removed = set(self.attached_components_info.devices.keys())
+
+        if self.network_service_info and other_sliver.network_service_info:
+            diff_ns = self._dict_diff(other_sliver.network_service_info.services,
+                                      other_sliver.network_service_info.services)
+            ns_added = set(diff_ns['added'].keys())
+            ns_removed = set(diff_ns['removed'].keys())
+
+        if not self.network_service_info and other_sliver.network_service_info:
+            ns_added = set(other_sliver.network_service_info.services.keys())
+
+        if self.network_service_info and not other_sliver.network_service_info:
+            ns_removed = set(self.network_service_info.services.keys())
+
+        if len(comp_added) > 0 or len(comp_removed) > 0 or len(ns_removed) > 0 or len(ns_added) > 0:
+            return TopologyDiff(added=TopologyDiffTuple(components=comp_added, services=ns_added, interfaces=set(),
+                                                        nodes=set()),
+                                removed=TopologyDiffTuple(components=comp_removed, services=ns_removed,
+                                                          interfaces=set(), nodes=set()))
+        else:
+            return None
+
     @staticmethod
     def type_from_str(ntype: str) -> NodeType or None:
         if ntype is None:
diff --git a/fim/slivers/network_service.py b/fim/slivers/network_service.py
index 9a41268..f5a3755 100644
--- a/fim/slivers/network_service.py
+++ b/fim/slivers/network_service.py
@@ -31,6 +31,7 @@
 from .path_info import PathRepresentationType, ERO, PathInfo
 from .gateway import Gateway
 from .interface_info import InterfaceType
+from .topology_diff import TopologyDiff, TopologyDiffTuple
 
 
 class NSLayer(enum.Enum):
@@ -315,6 +316,34 @@ def layer_from_str(layer: str) -> NSLayer or None:
             if layer == str(t):
                 return t
 
+    def diff(self, other_sliver) -> TopologyDiff or None:
+        if not other_sliver:
+            return None
+
+        super().diff(other_sliver)
+
+        ifs_added = set()
+        ifs_removed = set()
+        if self.interface_info and other_sliver.interface_info:
+            diff_comps = self._dict_diff(self.interface_info.interfaces,
+                                         other_sliver.interface_info.interfaces)
+            ifs_added = set(diff_comps['added'].keys())
+            ifs_removed = set(diff_comps['removed'].keys())
+
+        if not self.interface_info and other_sliver.interface_info:
+            ifs_added = set(other_sliver.interface_info.interfaces.keys())
+
+        if self.interface_info and not other_sliver.interface_info:
+            ifs_removed = set(self.interface_info.interfaces.keys())
+
+        if len(ifs_added) > 0 or len(ifs_removed) > 0:
+            return TopologyDiff(added=TopologyDiffTuple(components=set(), services=set(), interfaces=ifs_added,
+                                                        nodes=set()),
+                                removed=TopologyDiffTuple(components=set(), services=set(),
+                                                          interfaces=ifs_removed, nodes=set()))
+        else:
+            return None
+
 
 class NetworkServiceInfo:
 
diff --git a/fim/slivers/topology_diff.py b/fim/slivers/topology_diff.py
new file mode 100644
index 0000000..0317928
--- /dev/null
+++ b/fim/slivers/topology_diff.py
@@ -0,0 +1,45 @@
+#!/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: Ilya Baldin (ibaldin@renci.org)
+
+"""
+Definitions of topology differences for modify operations - used in topology and sliver diff methods
+"""
+import dataclasses
+from typing import Any
+
+
+@dataclasses.dataclass
+class TopologyDiffTuple:
+    nodes: set[Any]
+    components: set[Any]
+    services: set[Any]
+    interfaces: set[Any]
+
+
+@dataclasses.dataclass
+class TopologyDiff:
+    added: TopologyDiffTuple
+    removed: TopologyDiffTuple
diff --git a/fim/user/component.py b/fim/user/component.py
index a22d84f..509629f 100644
--- a/fim/user/component.py
+++ b/fim/user/component.py
@@ -54,7 +54,9 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any,
                  ctype: ComponentType = None, comp_model: ComponentModelType = None,
                  parent_node_id: str = None,
                  network_service_node_id: str = None, interface_node_ids: List[str] = None,
-                 interface_labels: List[Labels] = None, **kwargs):
+                 interface_labels: List[Labels] = None,
+                 check_existing: bool = False,
+                 **kwargs):
         """
         Don't call this yourself, use Node.add_component(). Instantiates components based on
         catalog resource file.
@@ -69,6 +71,7 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any,
         :param network_service_node_id: node id of network_service if one needs to be added (for substrate models only)
         :param interface_node_ids: a list of node ids for expected interfaces (for substrate models only)
         :param interface_labels: a list of Labels structure to associate with each interface
+        :param check_existing: check if a Component exists in the graph
         """
 
         assert name is not None
@@ -110,8 +113,8 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any,
         else:
             assert node_id is not None
             super().__init__(name=name, node_id=node_id, topo=topo)
-            if not self.topo.graph_model.check_node_name(node_id=node_id, name=name,
-                                                         label=ABCPropertyGraph.CLASS_Component):
+            if check_existing and not self.topo.graph_model.check_node_name(node_id=node_id, name=name,
+                                                                            label=ABCPropertyGraph.CLASS_Component):
                 raise TopologyException(f"Component with this id and name {name} doesn't exist")
 
     @property
@@ -240,6 +243,13 @@ def interface_list(self):
     def network_services(self):
         return self.__list_network_services()
 
+    def get_sliver(self) -> ComponentSliver:
+        """
+        Get a deep sliver representation of this component from graph
+        :return:
+        """
+        return self.topo.graph_model.build_deep_component_sliver(node_id=self.node_id)
+
     def __repr__(self):
         _, node_properties = self.topo.graph_model.get_node_properties(node_id=self.node_id)
         comp_sliver = self.topo.graph_model.component_sliver_from_graph_properties_dict(node_properties)
diff --git a/fim/user/composite_node.py b/fim/user/composite_node.py
index d442b5a..c80a67c 100644
--- a/fim/user/composite_node.py
+++ b/fim/user/composite_node.py
@@ -43,7 +43,7 @@ class CompositeNode(Node):
     node.interface_list - a list of all interfaces
     """
 
-    def __init__(self, *, name: str, node_id: str, topo: Any):
+    def __init__(self, *, name: str, node_id: str, topo: Any, check_existing: bool = False):
         """
         Don't call this method yourself, call topology.add_node()
         node_id will be generated if not provided for experiment topologies
@@ -51,6 +51,7 @@ def __init__(self, *, name: str, node_id: str, topo: Any):
         :param name:
         :param node_id:
         :param topo:
+        :param check_existing:
         """
         assert name is not None
         assert topo is not None
@@ -58,11 +59,12 @@ def __init__(self, *, name: str, node_id: str, topo: Any):
 
         # skip one level of constructor
         super(Node, self).__init__(name=name, node_id=node_id, topo=topo)
-        # check that this node exists
-        existing_node_id = self.topo.graph_model.find_node_by_name(node_name=name,
-                                                                   label=str(ABCPropertyGraph.CLASS_CompositeNode))
-        if existing_node_id != node_id:
-            raise TopologyException(f'Composite Node name {name} is not unique within the topology')
+        if check_existing:
+            # check that this node exists
+            existing_node_id = self.topo.graph_model.find_node_by_name(node_name=name,
+                                                                       label=str(ABCPropertyGraph.CLASS_CompositeNode))
+            if existing_node_id != node_id:
+                raise TopologyException(f'Composite Node name {name} is not unique within the topology')
 
     def __list_components(self) -> ViewOnlyDict:
         """
diff --git a/fim/user/interface.py b/fim/user/interface.py
index 5b6ce21..9548aa6 100644
--- a/fim/user/interface.py
+++ b/fim/user/interface.py
@@ -39,7 +39,9 @@ class Interface(ModelElement):
     def __init__(self, *, name: str, node_id: str = None, topo: Any,
                  etype: ElementType = ElementType.EXISTING,
                  parent_node_id: str = None,
-                 itype: InterfaceType = None, **kwargs):
+                 itype: InterfaceType = None,
+                 check_existing: bool = False,
+                 **kwargs):
         """
         Don't call this method yourself, call node.add_interface()
         node_id will be generated if not provided for experiment topologies
@@ -50,6 +52,7 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any,
         :param etype: is this supposed to exist or new should be created
         :param parent_node_id: parent network service or parent interface
         :param itype: node type if it is new
+        :param check_existing: check if the Interface exists in the graph
         :param kwargs: any additional properties
         """
         assert name is not None
@@ -76,8 +79,8 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any,
         else:
             assert node_id is not None
             super().__init__(name=name, node_id=node_id, topo=topo)
-            if not self.topo.graph_model.check_node_name(node_id=node_id, name=name,
-                                                         label=ABCPropertyGraph.CLASS_ConnectionPoint):
+            if check_existing and not self.topo.graph_model.check_node_name(node_id=node_id, name=name,
+                                                                            label=ABCPropertyGraph.CLASS_ConnectionPoint):
                 raise TopologyException(f"Interface with this id {node_id} and name {name} doesn't exist")
 
     @property
@@ -153,6 +156,13 @@ def get_peers(self, itype: InterfaceType = None):
                 ret.append(i)
         return ret
 
+    def get_sliver(self) -> InterfaceSliver:
+        """
+        Get a deep sliver representation of this interface from graph
+        :return:
+        """
+        return self.topo.graph_model.build_deep_interface_sliver(node_id=self.node_id)
+
     def __repr__(self):
         _, node_properties = self.topo.graph_model.get_node_properties(node_id=self.node_id)
         if_sliver = self.topo.graph_model.interface_sliver_from_graph_properties_dict(node_properties)
diff --git a/fim/user/link.py b/fim/user/link.py
index 8a27f8a..22d233d 100644
--- a/fim/user/link.py
+++ b/fim/user/link.py
@@ -45,7 +45,9 @@ class Link(ModelElement):
     def __init__(self, *, name: str, node_id: str = None, topo: Any,
                  etype: ElementType = ElementType.EXISTING,
                  interfaces: List[Interface] = None,
-                 ltype: LinkType = None, technology: str = None, **kwargs):
+                 ltype: LinkType = None, technology: str = None,
+                 check_existing: bool = False,
+                 **kwargs):
         """
         Don't call this method yourself, call topology.add_link()
         node_id will be generated if not provided for experiment topologies
@@ -93,12 +95,13 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any,
         else:
             assert node_id is not None
             super().__init__(name=name, node_id=node_id, topo=topo)
-            # check that this node exists
-            existing_node_id = self.topo.\
-                graph_model.find_node_by_name(node_name=name,
-                                              label=ABCPropertyGraph.CLASS_Link)
-            if existing_node_id != node_id:
-                raise TopologyException(f'Link name {name} is not unique within the topology.')
+            if check_existing:
+                # check that this node exists
+                existing_node_id = self.topo.\
+                    graph_model.find_node_by_name(node_name=name,
+                                                  label=ABCPropertyGraph.CLASS_Link)
+                if existing_node_id != node_id:
+                    raise TopologyException(f'Link name {name} is not unique within the topology.')
             # collect a list of interfaces it attaches to
             interface_list = self.topo.graph_model.get_all_ns_or_link_connection_points(link_id=self.node_id)
             name_id_tuples = list()
@@ -171,6 +174,12 @@ def __list_of_interfaces(self) -> List[Interface] or None:
             return self._interfaces.copy()
         return None
 
+    def get_sliver(self):
+        """
+        Return a NetworkLinkSliver
+        """
+        return self.topo.graph_model.build_deep_link_sliver(node_id=self.node_id)
+
     @property
     def interface_list(self):
         return self.__list_of_interfaces()
diff --git a/fim/user/model_element.py b/fim/user/model_element.py
index 1bc2f76..055f9d2 100644
--- a/fim/user/model_element.py
+++ b/fim/user/model_element.py
@@ -29,7 +29,7 @@
 import enum
 
 from ..graph.abc_property_graph import ABCPropertyGraph
-from ..slivers.capacities_labels import Capacities, Labels
+from ..slivers.capacities_labels import Capacities, Labels, ReservationInfo
 from ..slivers.measurement_data import MeasurementData
 
 
@@ -127,6 +127,12 @@ def set_properties(self, **kwargs):
         :return:
         """
 
+    @abstractmethod
+    def get_sliver(self):
+        """
+        Return sliver of appropriate type for this element
+        """
+
     @property
     def name(self):
         return self._name
@@ -217,6 +223,15 @@ def boot_script(self, value: str):
         if self.__dict__.get('topo', None) is not None:
             self.set_property('boot_script', value)
 
+    @property
+    def reservation_info(self):
+        return self.get_property('reservation_info') if self.__dict__.get('topo', None) is not None else None
+
+    @reservation_info.setter
+    def reservation_info(self, value: ReservationInfo):
+        if self.__dict__.get('topo', None) is not None:
+            self.set_property('reservation_info', value)
+
     def update_labels(self, **kwargs):
         """
         Take current labels field (even empty) and add/overwrite additional values into it
diff --git a/fim/user/network_service.py b/fim/user/network_service.py
index 1ed32fd..b3e7639 100644
--- a/fim/user/network_service.py
+++ b/fim/user/network_service.py
@@ -53,6 +53,8 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any,
                  parent_node_id: str = None,
                  interfaces: List[Interface] = None,
                  nstype: ServiceType = None, technology: str = None,
+                 check_existing: bool = False,
+                 site: str = None,
                  **kwargs):
         """
         Don't call this method yourself, call topology.add_network_service()
@@ -66,12 +68,12 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any,
         :param interfaces: list of interface objects to connect
         :param nstype: service type if new
         :param technology: service technology
+        :param check_existing: check if Network Service exists in the graph
         :param kwargs: any additional properties
         """
         assert name is not None
         assert topo is not None
 
-        site = None
         if etype == ElementType.NEW:
             # node id myst be specified for new nodes in substrate topologies
             if node_id is None:
@@ -79,40 +81,46 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any,
             super().__init__(name=name, node_id=node_id, topo=topo)
             if nstype is None:
                 raise TopologyException("When creating new services you must specify ServiceType")
-            # cant use isinstance as it would create circular import dependencies
-            # We do more careful checks for ExperimentTopologies, but for substrate we let things loose
-            if str(self.topo.__class__) == "<class 'fim.user.topology.ExperimentTopology'>" and interfaces:
-                sites = self.__validate_nstype_constraints(nstype, interfaces)
-
-                # if a single-site service
-                if len(sites) == 1:
-                    site = sites.pop()
 
             sliver = NetworkServiceSliver()
             sliver.node_id = self.node_id
             sliver.set_name(self.name)
             sliver.set_type(nstype)
-            sliver.set_site(site)
             # set based on service type
             sliver.set_layer(NetworkServiceSliver.ServiceConstraints[nstype].layer)
             sliver.set_technology(technology)
             sliver.set_properties(**kwargs)
+            sliver.set_site(site)
             self.topo.graph_model.add_network_service_sliver(parent_node_id=parent_node_id, network_service=sliver)
             self._interfaces = list()
+
             if interfaces is not None and len(interfaces) > 0:
+                connected_interfaces = list()
+                exception_thrown = False
                 for i in interfaces:
                     # run through guardrails, then connect
-                    self.__service_guardrails(sliver, i)
-                    self.__connect_interface(interface=i)
+                    try:
+                        self.__service_guardrails(sliver, i)
+                        self.connect_interface(interface=i)
+                        connected_interfaces.append(i)
+                    except TopologyException as e:
+                        # disconnect previously connected interfaces
+                        for ii in connected_interfaces:
+                            self.disconnect_interface(ii)
+                        # remove sliver from the graph
+                        self.topo.graph_model.remove_ns_with_cps_and_links(node_id=self.node_id)
+                        # re-throw the exception
+                        raise TopologyException(str(e))
         else:
             assert node_id is not None
             super().__init__(name=name, node_id=node_id, topo=topo)
-            # check that this node exists
-            existing_node_id = self.topo.\
-                graph_model.find_node_by_name(node_name=name,
-                                              label=ABCPropertyGraph.CLASS_NetworkService)
-            if existing_node_id != node_id:
-                raise TopologyException(f'Service name {name} node id does not match the expected node id.')
+            if check_existing:
+                # check that this node exists
+                existing_node_id = self.topo.\
+                    graph_model.find_node_by_name(node_name=name,
+                                                  label=ABCPropertyGraph.CLASS_NetworkService)
+                if existing_node_id != node_id:
+                    raise TopologyException(f'Service name {name} node id does not match the expected node id.')
             # collect a list of interface nodes it attaches to
             interface_list = self.topo.graph_model.get_all_ns_or_link_connection_points(link_id=self.node_id)
             name_id_tuples = list()
@@ -200,12 +208,12 @@ def __validate_nstype_constraints(self, nstype, interfaces) -> Set[str]:
             services = self.topo.graph_model.get_all_nodes_by_class_and_type(label=ABCPropertyGraph.CLASS_NetworkService,
                                                                              ntype=str(nstype))
             if len(services) + 1 > NetworkServiceSliver.ServiceConstraints[self.type].num_instances:
-                raise TopologyException(f"Service type {nstype} cannot have {len(services) + 1} instances. "
+                raise TopologyException(f"Service {self.name} type {nstype} cannot have {len(services) + 1} instances. "
                                         f"Limit: {NetworkServiceSliver.ServiceConstraints[nstype].num_instances}")
         # check the number of interfaces
         if NetworkServiceSliver.ServiceConstraints[nstype].num_interfaces != NetworkServiceSliver.NO_LIMIT:
             if len(interfaces) > NetworkServiceSliver.ServiceConstraints[nstype].num_interfaces:
-                raise TopologyException(f"Service of type {nstype} cannot have {len(interfaces)} interfaces. "
+                raise TopologyException(f"Service {self.name} of type {nstype} cannot have {len(interfaces)} interfaces. "
                                         f"Limit: {NetworkServiceSliver.ServiceConstraints[nstype].num_interfaces}")
         sites = set()
         # check the number of sites spanned by this service
@@ -214,13 +222,26 @@ def __validate_nstype_constraints(self, nstype, interfaces) -> Set[str]:
             for interface in interfaces:
                 owner = self.topo.get_owner_node(interface)
                 if owner is None:
-                    print(f'Interface {interface=} has no owner')
+                    print(f'In validating service {self.name} interface {interface=} has no owner')
                 sites.add(owner.site)
 
             if len(sites) > NetworkServiceSliver.ServiceConstraints[nstype].num_sites:
-                raise TopologyException(f"Service of type {nstype} cannot span {len(sites)} sites. "
+                raise TopologyException(f"Service {self.name} of type {nstype} cannot span {len(sites)} sites. "
                                         f"Limit: {NetworkServiceSliver.ServiceConstraints[nstype].num_sites}.")
-        return sites
+
+        if len(sites) == 1:
+            # set the site property if possible
+            old_site = self.site
+            if not self.site:
+                self.site = sites.pop()
+
+            if old_site and old_site != self.site:
+                raise TopologyException(f"For service {self.name} originally specified site {old_site} does not"
+                                        f"match the site {self.site} inferred from connected interfaces.")
+        else:
+            if self.site:
+                raise TopologyException(f"Service {self.name} is multi-site, but site {self.site} was specified in"
+                                        f"constructor")
 
     def validate_constraints(self, interfaces):
         """
@@ -260,13 +281,12 @@ def __service_guardrails(sliver: NetworkServiceSliver, interface: Interface):
         :return:
         """
         # - L2P2P service does not work for shared ports
-        # - L2S2S needs to warn that it may not work if the VMs with shared ports land on the same worker
         if sliver.get_type() == ServiceType.L2PTP and \
             interface.type == InterfaceType.SharedPort:
             raise TopologyException(f"Unable to connect interface {interface.name} to service {sliver.get_name()}: "
                                     f"L2P2P service currently doesn't support shared interfaces")
 
-    def __connect_interface(self, *, interface: Interface):
+    def connect_interface(self, interface: Interface):
         """
         Connect a (compute or switch) node interface to network service by transparently
         creating a peer service interface and a link between them
@@ -298,7 +318,7 @@ def __connect_interface(self, *, interface: Interface):
                          interfaces=[interface, peer_if], ltype=ltype)
         self._interfaces.append(peer_if)
 
-    def disconnect_interface(self, *, interface: Interface) -> None:
+    def disconnect_interface(self, interface: Interface) -> None:
         """
         Disconnect a node interface from the network service.
         Transparently remove peer service interface and link between them.
@@ -312,7 +332,8 @@ def disconnect_interface(self, *, interface: Interface) -> None:
             return
 
         if len(peers) > 1:
-            raise TopologyException(f'List of ServicePort peers for interface {interface} is more than one')
+            raise TopologyException(f'Interface {interface} has more than one peer: {peers}, '
+                                    f'this is a model error, unable to proceed.')
 
         self.topo.graph_model.remove_cp_and_links(node_id=peers[0].node_id)
         # remove from interface list as well
@@ -331,8 +352,9 @@ def add_interface(self, *, name: str, node_id: str = None, itype: InterfaceType
         assert name is not None
 
         # check uniqueness
-        if name in self.__list_interfaces().keys():
-            raise TopologyException('Interface names must be unique within a switch fabric')
+        all_names = [n.name for n in self._interfaces]
+        if name in all_names:
+            raise TopologyException(f'Interface {name} is not unique within a network service')
         iff = Interface(name=name, node_id=node_id, parent_node_id=self.node_id,
                         etype=ElementType.NEW, topo=self.topo, itype=itype,
                         **kwargs)
@@ -422,26 +444,30 @@ def __list_interfaces(self) -> ViewOnlyDict:
         List all interfaces of the network service as a dictionary
         :return:
         """
-        node_id_list = self.topo.graph_model.get_all_ns_or_link_connection_points(link_id=self.node_id)
         ret = dict()
-        for nid in node_id_list:
-            c = self.__get_interface_by_id(nid)
-            ret[c.name] = c
+        for intf in self._interfaces:
+            ret[intf.name] = intf
         return ViewOnlyDict(ret)
 
     def __list_of_interfaces(self) -> Tuple[Interface]:
         """
-        Return a list of all interfaces of network service
+        Return a list of names of interfaces of network service
         :return:
         """
         return tuple(self._interfaces)
 
     @property
     def interface_list(self):
+        """
+        List of names of service interfaces
+        """
         return self.__list_of_interfaces()
 
     @property
     def interfaces(self):
+        """
+        Dictionary name->Interface for all interfaces
+        """
         return self.__list_interfaces()
 
     def __repr__(self):
@@ -465,6 +491,7 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any,
                  etype: ElementType = ElementType.EXISTING,
                  parent_node_id: str = None, direction: MirrorDirection = MirrorDirection.Both,
                  from_interface_name: str = None, to_interface: Interface = None,
+                 check_existing: bool = False,
                  **kwargs):
         if etype == ElementType.NEW:
             assert to_interface
@@ -486,12 +513,13 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any,
         else:
             assert node_id is not None
             super().__init__(name=name, node_id=node_id, topo=topo)
-            # check that this node exists
-            existing_node_id = self.topo.\
-                graph_model.find_node_by_name(node_name=name,
-                                              label=ABCPropertyGraph.CLASS_NetworkService)
-            if existing_node_id != node_id:
-                raise TopologyException(f'Service name {name} node id does not match the expected node id.')
+            if check_existing:
+                # check that this node exists
+                existing_node_id = self.topo.\
+                    graph_model.find_node_by_name(node_name=name,
+                                                  label=ABCPropertyGraph.CLASS_NetworkService)
+                if existing_node_id != node_id:
+                    raise TopologyException(f'Service name {name} node id does not match the expected node id.')
             # collect a list of interface nodes it attaches to
             interface_list = self.topo.graph_model.get_all_ns_or_link_connection_points(link_id=self.node_id)
             name_id_tuples = list()
diff --git a/fim/user/node.py b/fim/user/node.py
index b900d22..73f81d5 100644
--- a/fim/user/node.py
+++ b/fim/user/node.py
@@ -40,7 +40,7 @@
 from ..slivers.network_node import NodeType
 from ..slivers.network_service import ServiceType, NetworkServiceInfo
 from ..slivers.component_catalog import ComponentModelType
-from ..slivers.capacities_labels import CapacityHints, Location, ReservationInfo
+from ..slivers.capacities_labels import CapacityHints, Location
 
 
 class Node(ModelElement):
@@ -58,7 +58,8 @@ class Node(ModelElement):
     """
 
     def __init__(self, *, name: str, node_id: str = None, topo: Any, etype: ElementType = ElementType.EXISTING,
-                 ntype: NodeType = None, site: str = None, ns_info: NetworkServiceInfo = None, **kwargs):
+                 ntype: NodeType = None, site: str = None, ns_info: NetworkServiceInfo = None,
+                 check_existing: bool = False, **kwargs):
         """
         Don't call this method yourself, call topology.add_node()
         node_id will be generated if not provided for experiment topologies
@@ -70,6 +71,7 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any, etype: ElementT
         :param ntype: node type if it is new
         :param site: node site
         :param ns_info: NetworkServiceInfo structure
+        :param check_existing: for an existing node check if it is in the graph
         :param kwargs: any additional properties
         """
         assert name is not None
@@ -100,11 +102,12 @@ def __init__(self, *, name: str, node_id: str = None, topo: Any, etype: ElementT
         else:
             assert node_id is not None
             super().__init__(name=name, node_id=node_id, topo=topo)
-            # check that this node exists
-            existing_node_id = self.topo.graph_model.find_node_by_name(node_name=name,
-                                                                       label=str(ABCPropertyGraph.CLASS_NetworkNode))
-            if existing_node_id != node_id:
-                raise TopologyException(f'Node name {name} is not unique within the topology')
+            if check_existing:
+                # check that this node exists
+                existing_node_id = self.topo.graph_model.find_node_by_name(node_name=name,
+                                                                           label=str(ABCPropertyGraph.CLASS_NetworkNode))
+                if existing_node_id != node_id:
+                    raise TopologyException(f'Node name {name} is not unique within the topology')
 
     @property
     def site(self):
@@ -153,15 +156,6 @@ def capacity_hints(self, value: CapacityHints):
         if self.__dict__.get('topo', None) is not None:
             self.set_property('capacity_hints', value)
 
-    @property
-    def reservation_info(self):
-        return self.get_property('reservation_info') if self.__dict__.get('topo', None) is not None else None
-
-    @reservation_info.setter
-    def reservation_info(self, value: ReservationInfo):
-        if self.__dict__.get('topo', None) is not None:
-            self.set_property('reservation_info', value)
-
     @property
     def location(self):
         return self.get_property('location') if self.__dict__.get('topo', None) is not None else None
@@ -204,10 +198,11 @@ def validate_constraints(self):
         _, node_properties = self.topo.graph_model.get_node_properties(node_id=self.node_id)
         node_sliver = self.topo.graph_model.node_sliver_from_graph_properties_dict(node_properties)
         for rp in req_props:
-            if not node_sliver.get_property(rp):
+            if not node_sliver.property_exists(rp) or \
+                    (node_sliver.property_exists(rp) and not node_sliver.get_property(rp)):
                 raise TopologyException(f"Node of type {nstype} must have property {rp} set")
         for fp in forb_props:
-            if node_sliver.get_property(fp):
+            if node_sliver.property_exists(fp) and node_sliver.get_property(fp):
                 raise TopologyException(f"Node of type {nstype} must NOT have property {fp} set")
 
     def get_sliver(self) -> NodeSliver:
diff --git a/fim/user/topology.py b/fim/user/topology.py
index c6475c8..e807b70 100644
--- a/fim/user/topology.py
+++ b/fim/user/topology.py
@@ -23,9 +23,8 @@
 #
 #
 # Author: Ilya Baldin (ibaldin@renci.org)
-
 from abc import ABC
-from typing import List, Tuple, Any
+from typing import List, Tuple, Any, Set
 import enum
 
 import uuid
@@ -41,12 +40,15 @@
 from ..slivers.network_service import NSLayer, ServiceType, MirrorDirection
 from ..graph.slices.abc_asm import ABCASMPropertyGraph
 from ..graph.slices.networkx_asm import NetworkxASM
+from ..graph.slices.neo4j_asm import Neo4jASM
 from ..graph.abc_property_graph import ABCPropertyGraph, GraphFormat
 from ..graph.resources.networkx_arm import NetworkXARMGraph, NetworkXGraphImporter
+from ..graph.resources.neo4j_arm import Neo4jARMGraph
 from ..slivers.delegations import Delegation, Delegations, Pools, DelegationType, DelegationFormat
 from fim.graph.resources.networkx_abqm import NetworkXAggregateBQM, NetworkXABQMFactory
-from fim.slivers.capacities_labels import Capacities, FreeCapacity
+from fim.slivers.capacities_labels import FreeCapacity
 from fim.slivers.interface_info import InterfaceType
+from fim.slivers.topology_diff import TopologyDiff, TopologyDiffTuple
 
 from .model_element import ElementType
 from .node import Node
@@ -69,13 +71,24 @@ class TopologyDetail(enum.Enum):
 class Topology(ABC):
     """
     Base class to define and manipulate a topology over its life cycle.
-    Default constructor and load functions create NetworkX-based ASM graphs.
+    Default constructor and load functions create NetworkX-based ASM graphs. Pass
+    in Neo4jImporter to create a Neo4j-based Topology.
     """
-    def __init__(self, graph_file: str = None, graph_string: str = None, logger=None):
+    def __init__(self, graph_file: str = None, graph_string: str = None, logger=None, importer=None):
 
-        self.graph_model = NetworkxASM(graph_id=str(uuid.uuid4()),
-                                       importer=NetworkXGraphImporter(logger=logger),
-                                       logger=logger)
+        if not importer:
+            self.graph_model = NetworkxASM(graph_id=str(uuid.uuid4()),
+                                           importer=NetworkXGraphImporter(logger=logger),
+                                           logger=logger)
+        else:
+            if isinstance(importer, NetworkXGraphImporter):
+                self.graph_model = NetworkxASM(graph_id=str(uuid.uuid4()),
+                                               importer=importer,
+                                               logger=logger)
+            else:
+                self.graph_model = Neo4jASM(graph_id=str(uuid.uuid4()),
+                                            importer=importer,
+                                            logger=logger)
         if graph_file is not None or graph_string is not None:
             self.load(file_name=graph_file, graph_string=graph_string)
 
@@ -86,10 +99,19 @@ def get_parent_element(self, e: ModelElement) -> ModelElement or None:
         :param e:
         :return:
         """
-        assert e is not None
         if isinstance(e, Node) or isinstance(e, Link):
             # nodes or links don't have parents
             return None
+
+        # interfaces have NSs as parents
+        if isinstance(e, Interface):
+            node_name, node_id = self.graph_model.get_parent(node_id=e.node_id,
+                                                             rel=ABCPropertyGraph.REL_CONNECTS,
+                                                             parent=ABCPropertyGraph.CLASS_NetworkService)
+            if node_id is None:
+                raise TopologyException(f'Interface {e} has no parent')
+            return NetworkService(name=node_name, node_id=node_id, topo=self)
+
         # components have nodes as parents
         if isinstance(e, Component):
             node_name, node_id = self.graph_model.get_parent(node_id=e.node_id,
@@ -98,6 +120,7 @@ def get_parent_element(self, e: ModelElement) -> ModelElement or None:
             if node_id is None:
                 raise TopologyException(f'Component {e} has no parent')
             return Node(name=node_name, node_id=node_id, topo=self)
+
         # NSs may have nodes or components as parents or be by themselves
         if isinstance(e, NetworkService):
             node_name, node_id = self.graph_model.get_parent(node_id=e.node_id,
@@ -119,14 +142,7 @@ def get_parent_element(self, e: ModelElement) -> ModelElement or None:
                 return CompositeNode(name=node_name, node_id=node_id, topo=self)
 
             return None
-        # interfaces have NSs as parents
-        if isinstance(e, Interface):
-            node_name, node_id = self.graph_model.get_parent(node_id=e.node_id,
-                                                             rel=ABCPropertyGraph.REL_CONNECTS,
-                                                             parent=ABCPropertyGraph.CLASS_NetworkService)
-            if node_id is None:
-                raise TopologyException(f'Interface {e} has no parent')
-            return NetworkService(name=node_name, node_id=node_id, topo=self)
+
         raise TopologyException(f'Unable to determine parent of element {e}')
 
     def get_owner_node(self, e: ModelElement) -> ModelElement or None:
@@ -136,7 +152,6 @@ def get_owner_node(self, e: ModelElement) -> ModelElement or None:
         :param e:
         :return:
         """
-        assert e is not None
         if isinstance(e, Node) or isinstance(e, Link):
             # nodes or links don't have parents
             return None
@@ -191,7 +206,6 @@ def remove_node(self, name: str):
         :param name:
         :return:
         """
-        assert name is not None
         self.graph_model.remove_network_node_with_components_nss_cps_and_links(
             node_id=self._get_node_by_name(name=name).node_id)
 
@@ -252,11 +266,10 @@ def remove_link(self, name: str):
         :param name:
         :return:
         """
-        assert name is not None
         self.graph_model.remove_network_link(node_id=self._get_link_by_name(name=name).node_id)
 
     def add_network_service(self, *, name: str, node_id: str = None, nstype: ServiceType,
-                            interfaces: List[Interface], technology: str = None, **kwargs) -> NetworkService:
+                            interfaces: List[Interface] = None, technology: str = None, **kwargs) -> NetworkService:
         """
         Add a network service to a topology. Interfaces can be specified upfront or added/removed later
         :param name:
@@ -277,7 +290,6 @@ def remove_network_service(self, name: str):
         :param name:
         :return:
         """
-        assert name is not None
         self.graph_model.remove_ns_with_cps_and_links(node_id=self._get_ns_by_name(name=name).node_id)
 
     def _get_node_by_name(self, name: str) -> Node:
@@ -286,7 +298,6 @@ def _get_node_by_name(self, name: str) -> Node:
         :param name:
         :return:
         """
-        assert name is not None
         node_id = self.graph_model.find_node_by_name(node_name=name,
                                                      label=ABCPropertyGraph.CLASS_NetworkNode)
         return Node(name=name, node_id=node_id, topo=self)
@@ -297,7 +308,6 @@ def _get_link_by_name(self, name: str) -> Link:
         :param name:
         :return:
         """
-        assert name is not None
         node_id = self.graph_model.find_node_by_name(node_name=name,
                                                      label=ABCPropertyGraph.CLASS_Link)
         return Link(name=name, node_id=node_id, topo=self)
@@ -308,7 +318,6 @@ def _get_ns_by_name(self, name: str) -> NetworkService:
         :param name:
         :return:
         """
-        assert name is not None
         node_id = self.graph_model.find_node_by_name(node_name=name,
                                                      label=ABCPropertyGraph.CLASS_NetworkService)
         return NetworkService(name=name, node_id=node_id, topo=self)
@@ -319,9 +328,7 @@ def _get_node_by_id(self, node_id: str) -> Node:
         :param node_id:
         :return:
         """
-        assert node_id is not None
         _, node_props = self.graph_model.get_node_properties(node_id=node_id)
-        assert node_props.get(ABCPropertyGraph.PROP_NAME, None) is not None
         return Node(name=node_props[ABCPropertyGraph.PROP_NAME], node_id=node_id, topo=self)
 
     def _get_link_by_id(self, node_id: str) -> Link:
@@ -330,9 +337,7 @@ def _get_link_by_id(self, node_id: str) -> Link:
         :param node_id:
         :return:
         """
-        assert node_id is not None
         _, node_props = self.graph_model.get_node_properties(node_id=node_id)
-        assert node_props.get(ABCPropertyGraph.PROP_NAME, None) is not None
         return Link(name=node_props[ABCPropertyGraph.PROP_NAME], node_id=node_id, topo=self)
 
     def _get_ns_by_id(self, node_id: str) -> NetworkService:
@@ -341,9 +346,7 @@ def _get_ns_by_id(self, node_id: str) -> NetworkService:
         :param node_id:
         :return:
         """
-        assert node_id is not None
         _, node_props = self.graph_model.get_node_properties(node_id=node_id)
-        assert node_props.get(ABCPropertyGraph.PROP_NAME, None) is not None
         ns = NetworkService(name=node_props[ABCPropertyGraph.PROP_NAME], node_id=node_id, topo=self)
         if ns.type == ServiceType.PortMirror:
             return PortMirrorService(name=node_props[ABCPropertyGraph.PROP_NAME], node_id=node_id, topo=self)
@@ -433,11 +436,13 @@ def serialize(self, file_name: str = None, fmt: GraphFormat = GraphFormat.GRAPHM
                 f.write(graph_string)
         return None
 
-    def load(self, *, file_name: str = None, graph_string: str = None):
+    def load(self, *, file_name: str = None, graph_string: str = None, new_graph_id: str = None):
         """
-        Load the topology from file or string
+        Load the topology from file or string. It is possible to overwrite the graph id if
+        loading from string (but not from file).
         :param file_name:
         :param graph_string:
+        :param new_graph_id:
         :return:
         """
         if file_name is None and graph_string is None:
@@ -445,10 +450,19 @@ def load(self, *, file_name: str = None, graph_string: str = None):
         if file_name is not None:
             nx_pgraph = self.graph_model.importer.import_graph_from_file_direct(graph_file=file_name)
         else:
-            nx_pgraph = self.graph_model.importer.import_graph_from_string_direct(graph_string=graph_string)
-        self.graph_model = NetworkxASM(graph_id=nx_pgraph.graph_id,
-                                       importer=nx_pgraph.importer,
-                                       logger=nx_pgraph.log)
+            if not new_graph_id:
+                nx_pgraph = self.graph_model.importer.import_graph_from_string_direct(graph_string=graph_string)
+            else:
+                nx_pgraph = self.graph_model.importer.import_graph_from_string(graph_string=graph_string,
+                                                                               graph_id=new_graph_id)
+        if isinstance(self.graph_model.importer, NetworkXGraphImporter):
+            self.graph_model = NetworkxASM(graph_id=nx_pgraph.graph_id,
+                                           importer=nx_pgraph.importer,
+                                           logger=nx_pgraph.log)
+        else:
+            self.graph_model = Neo4jASM(graph_id=nx_pgraph.graph_id,
+                                        importer=nx_pgraph.importer,
+                                        logger=nx_pgraph.log)
 
     @staticmethod
     def __print_caplabs__(caps) -> str:
@@ -507,6 +521,35 @@ def facilities(self) -> ViewOnlyDict or None:
             ret[n.name] = n
         return ViewOnlyDict(ret)
 
+    def validate(self):
+        """
+        Validate an experiment or a substrate topology. Throw an exception if rules
+        are violated.
+        :return:
+        """
+        # check nodes
+        for n in self.nodes.values():
+            n.validate_constraints()
+
+        # check network services, interfaces, sites
+        for s in self.network_services.values():
+            service_interfaces = s.interface_list
+            node_interfaces = list()
+            # some services like OVS have node ports, others like Bridge, STS, PTP
+            # have ServicePorts which peer with node ports. Validation code needs
+            # owning nodes for each interface so we search for proper interfaces
+            for si in service_interfaces:
+                if si.type == InterfaceType.ServicePort:
+                    # there should only ever be one peer for a service port
+                    peers = si.get_peers()
+                    if peers is None or len(peers) != 1:
+                        raise TopologyException(f'Interface {si} of Network Service {s} has unexpected '
+                                                f'number of peer interfaces')
+                    node_interfaces.append(si.get_peers()[0])
+                else:
+                    node_interfaces.append(si)
+            s.validate_constraints(node_interfaces)
+
 
 class ExperimentTopology(Topology):
     """
@@ -517,8 +560,8 @@ class ExperimentTopology(Topology):
     topology.interface_list - a read-only list of all interfaces of all nodes
     If you want to operate on top of a Neo4j graph, use the cast() method.
     """
-    def __init__(self, graph_file: str = None, graph_string: str = None, logger=None):
-        super().__init__(graph_file=graph_file, graph_string=graph_string, logger=logger)
+    def __init__(self, graph_file: str = None, graph_string: str = None, logger=None, importer=None):
+        super().__init__(graph_file=graph_file, graph_string=graph_string, logger=logger, importer=importer)
 
     def cast(self, *, asm_graph: ABCASMPropertyGraph):
         """
@@ -527,7 +570,6 @@ def cast(self, *, asm_graph: ABCASMPropertyGraph):
         :param asm_graph:
         :return:
         """
-        assert asm_graph is not None
         assert isinstance(asm_graph, ABCASMPropertyGraph)
         self.graph_model = asm_graph
 
@@ -632,33 +674,196 @@ def add_port_mirror_service(self, *, name: str, node_id: str = None,
                                to_interface=to_interface, **kwargs)
         return ns
 
-    def validate(self):
+    @staticmethod
+    def _generate_set_of_diff_elements(elems, topo: Topology, elemClass):
+
+        return {elemClass(name=x["Name"], node_id=x["NodeID"], topo=topo)
+                for x in elems}
+
+    @staticmethod
+    def _is_parented_component(comp: Component, nodes: Set[Node]):
         """
-        Validate the experiment topology. Throw an exception if
-        :return:
+        Is this component parented to any of the nodes?
         """
-        # check nodes
+        if not nodes:
+            return False
+        parent_node = comp.topo.get_parent_element(comp)
+        # so we can get early exit
+        for n in nodes:
+            if n.node_id == parent_node.node_id:
+                return True
+        return False
+
+    @staticmethod
+    def _is_parented_interface(intf: Interface, nss: Set[NetworkService]):
+        """
+        Is this Interface parented to the Network Service
+        """
+        if not nss:
+            return False
+        parent_ns = intf.topo.get_parent_element(intf)
+        # so we can get early exit
+        for ns in nss:
+            if ns.node_id == parent_ns.node_id:
+                return True
+        return False
+
+    @staticmethod
+    def _is_parented_ns(ns: NetworkService, parents: Set[Node or Component]):
+        """
+        Is this Network Service parented to a node or component
+        """
+        if not parents:
+            return False
+        parent_node = ns.topo.get_parent_element(ns)
+        if parent_node:
+            # so we get early exit
+            for n in parents:
+                if n.node_id == parent_node.node_id:
+                    return True
+        return False
+
+    @staticmethod
+    def _exclude_parented_elements(nodes: Set[Node], nss: Set[NetworkService],
+                                   components: Set[Component], interfaces: Set[Interface]):
+        """
+        for lists of graph nodes (AnotB or BnotA) exclude parented components,
+        network services and interfaces
+        - components listed as part of nodes should be excluded
+        - nss listed as part of added nodes should be excluded
+        - interfaces listed as part of added or excluded network services should also be excluded
+        """
+
+        excluded_components = {c for c in components if ExperimentTopology._is_parented_component(c, nodes)}
+        excluded_nss = {ns for ns in nss if ExperimentTopology._is_parented_ns(ns, nodes.union(excluded_components))}
+        excluded_interfaces = {i for i in interfaces if ExperimentTopology._is_parented_interface(i, nss.union(excluded_nss))}
+        return nodes, nss - excluded_nss, components - excluded_components, interfaces - excluded_interfaces
+
+    def diff(self, t) -> TopologyDiff:
+        """
+        Do a diff of two topologies assuming they are both in Neo4j (will not work with NetworkX backend)
+        """
+        nodes_diff = self.graph_model.get_graph_diff(t.graph_model, ABCPropertyGraph.CLASS_NetworkNode)
+        ns_diff = self.graph_model.get_graph_diff(t.graph_model, ABCPropertyGraph.CLASS_NetworkService)
+        component_diff = self.graph_model.get_graph_diff(t.graph_model, ABCPropertyGraph.CLASS_Component)
+        interface_diff = self.graph_model.get_graph_diff(t.graph_model, ABCPropertyGraph.CLASS_ConnectionPoint)
+
+        # convert to appropriate types to make easier to operate on
+        # FIXME: Facility?
+        nodes_removed = self._generate_set_of_diff_elements(nodes_diff[0], self, Node)
+        nodes_added = self._generate_set_of_diff_elements(nodes_diff[1], t, Node)
+
+        # FIXME: MirrorService?
+        nss_removed = self._generate_set_of_diff_elements(ns_diff[0], self, NetworkService)
+        nss_added = self._generate_set_of_diff_elements(ns_diff[1], t, NetworkService)
+
+        components_removed = self._generate_set_of_diff_elements(component_diff[0], self, Component)
+        components_added = self._generate_set_of_diff_elements(component_diff[1], t, Component)
+
+        interfaces_removed = self._generate_set_of_diff_elements(interface_diff[0], self, Interface)
+        interfaces_added = self._generate_set_of_diff_elements(interface_diff[1], t, Interface)
+
+        nodes_added, nss_added, components_added, interfaces_added = \
+            ExperimentTopology._exclude_parented_elements(nodes_added, nss_added,
+                                                          components_added, interfaces_added)
+
+        nodes_removed, nss_removed, components_removed, interfaces_removed = \
+            ExperimentTopology._exclude_parented_elements(nodes_removed, nss_removed,
+                                                          components_removed, interfaces_removed)
+
+        return TopologyDiff(added=TopologyDiffTuple(nodes=nodes_added,
+                                                    components=components_added,
+                                                    services=nss_added,
+                                                    interfaces=interfaces_added),
+                            removed=TopologyDiffTuple(nodes=nodes_removed,
+                                                      components=components_removed,
+                                                      services=nss_removed,
+                                                      interfaces=interfaces_removed))
+
+    def _prune_node(self, node: Node):
+        """
+        Prune this node, its components, network services and interfaces
+        """
+        self.graph_model.remove_network_node_with_components_nss_cps_and_links(node_id=node.node_id)
+
+    def _prune_ns(self, ns: NetworkService):
+        """
+        Prune this network service and its interfaces
+        """
+        self.graph_model.remove_ns_with_cps_and_links(node_id=ns.node_id)
+
+    def _prune_components(self, c: Component):
+        """
+        Prune this component, its network services and interfaces
+        """
+        self.graph_model.remove_component_with_nss_cps_and_links(node_id=c.node_id)
+
+    def _prune_interface(self, i: Interface):
+        """
+        Prune this interface
+        """
+        self.graph_model.remove_cp_and_links(node_id=i.node_id)
+
+    def prune(self, reservation_state):
+        """
+        Prune the topology of any elements with reservation_info.reservation_state matching
+        the provided.
+        """
+        #
+        # for all nodes, network services, components and interfaces collect them
+        #
+        nodes = set()
+        components = set()
+        nss = set()
+        seennss = set()
+        interfaces = set()
         for n in self.nodes.values():
-            n.validate_constraints()
+            nsl = n.get_sliver()
+            if nsl.get_reservation_info() and \
+                    nsl.get_reservation_info().reservation_state == reservation_state:
+                nodes.add(n)
+            for c in n.components.values():
+                csl = c.get_sliver()
+                if csl.get_reservation_info() and \
+                        csl.get_reservation_info().reservation_state == reservation_state:
+                    components.add(c)
+                for ns in c.network_services.values():
+                    seennss.add(ns)
+                    nsl = ns.get_sliver()
+                    if nsl.get_reservation_info() and \
+                            nsl.get_reservation_info().reservation_state == reservation_state:
+                        nss.add(ns)
+                    for i in ns.interface_list:
+                        isl = i.get_sliver()
+                        if isl.get_reservation_info() and \
+                                isl.get_reservation_info().reservation_state == reservation_state:
+                            interfaces.add(i)
+
+        # top level network services only, we visited others already
+        for ns in self.network_services.values():
+            if ns not in seennss:
+                nsl = ns.get_sliver()
+                if nsl.get_reservation_info() and \
+                        nsl.get_reservation_info().reservation_state == reservation_state:
+                    nss.add(ns)
+                for i in ns.interface_list:
+                    isl = i.get_sliver()
+                    if isl.get_reservation_info() and \
+                            isl.get_reservation_info().reservation_state == reservation_state:
+                        interfaces.add(i)
 
-        # check network services, interfaces, sites
-        for s in self.network_services.values():
-            service_interfaces = s.interface_list
-            node_interfaces = list()
-            # some services like OVS have node ports, others like Bridge, STS, PTP
-            # have ServicePorts which peer with node ports. Validation code needs
-            # owning nodes for each interface so we search for proper interfaces
-            for si in service_interfaces:
-                if si.type == InterfaceType.ServicePort:
-                    # there should only ever be one peer for a service port
-                    peers = si.get_peers()
-                    if peers is None or len(peers) != 1:
-                        raise TopologyException(f'Interface {si} of Network Service {s} has unexpected '
-                                                f'number of peer interfaces')
-                    node_interfaces.append(si.get_peers()[0])
-                else:
-                    node_interfaces.append(si)
-            s.validate_constraints(node_interfaces)
+        # all deletes are supposed to be idempotent
+        for n in nodes:
+            self._prune_node(n)
+
+        for c in components:
+            self._prune_components(c)
+
+        for ns in nss:
+            self._prune_ns(ns)
+
+        for i in interfaces:
+            self._prune_interface(i)
 
 
 class SubstrateTopology(Topology):
@@ -670,8 +875,8 @@ class SubstrateTopology(Topology):
     topology.interface_list - a read-only list of all interfaces of all nodes
     """
 
-    def __init__(self, graph_file: str = None, graph_string: str = None, logger=None):
-        super().__init__(graph_file=graph_file, graph_string=graph_string, logger=logger)
+    def __init__(self, graph_file: str = None, graph_string: str = None, logger=None, importer=None):
+        super().__init__(graph_file=graph_file, graph_string=graph_string, logger=logger, importer=importer)
 
     def as_arm(self):
         """
@@ -679,8 +884,12 @@ def as_arm(self):
         rather recast into ARM, so any changes to the model propagate back to the topology.
         :return:
         """
-        return NetworkXARMGraph(graph=self.graph_model,
-                                logger=self.graph_model.log)
+        if isinstance(self.graph_model, NetworkxASM):
+            return NetworkXARMGraph(graph=self.graph_model,
+                                    logger=self.graph_model.log)
+        else:
+            return Neo4jARMGraph(graph=self.graph_model,
+                                 logger=self.graph_model.log)
 
     @staticmethod
     def __copy_to_delegations(e: ModelElement, atype: DelegationType,
@@ -692,8 +901,6 @@ def __copy_to_delegations(e: ModelElement, atype: DelegationType,
         :param e:
         :return:
         """
-        assert e is not None
-        assert delegation_id is not None
         if e.get_property("stitch_node"):
             return None
         if atype == DelegationType.CAPACITY:
@@ -811,9 +1018,7 @@ def _get_node_by_id(self, node_id: str) -> Node:
         :param node_id:
         :return:
         """
-        assert node_id is not None
         claz, node_props = self.graph_model.get_node_properties(node_id=node_id)
-        assert node_props.get(ABCPropertyGraph.PROP_NAME, None) is not None
         if claz[0] == ABCPropertyGraph.CLASS_CompositeNode:
             return CompositeNode(name=node_props[ABCPropertyGraph.PROP_NAME], node_id=node_id, topo=self)
         elif claz[0] == ABCPropertyGraph.CLASS_NetworkNode:
@@ -825,9 +1030,7 @@ def _get_link_by_id(self, node_id: str) -> Link:
         :param node_id:
         :return:
         """
-        assert node_id is not None
         _, node_props = self.graph_model.get_node_properties(node_id=node_id)
-        assert node_props.get(ABCPropertyGraph.PROP_NAME, None) is not None
         return Link(name=node_props[ABCPropertyGraph.PROP_NAME], node_id=node_id, topo=self)
 
     def __list_sites(self) -> ViewOnlyDict:
diff --git a/requirements.txt b/requirements.txt
index ed95f86..38b6473 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -24,7 +24,7 @@ pycodestyle==2.6.0
 Pygments==2.9.0
 pyparsing==2.4.7
 pytest==7.1.1
-python-dateutil==2.8.1
+python-dateutil==2.8.2
 pytz==2020.1
 PyYAML==5.4
 readme-renderer==29.0


Test patch:
diff --git a/test/after.graphml b/test/after.graphml
new file mode 100644
index 0000000..d52172c
--- /dev/null
+++ b/test/after.graphml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?><graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"><key id="Site" for="node" attr.name="Site" attr.type="string"/><key id="labels" for="node" attr.name="labels" attr.type="string"/>
+<key id="ImageRef" for="node" attr.name="ImageRef" attr.type="string"/><key id="GraphID" for="node" attr.name="GraphID" attr.type="string"/><key id="Labels" for="node" attr.name="Labels" attr.type="string"/><key id="label" for="node" attr.name="label" attr.type="string"/><key id="MgmtIp" for="node" attr.name="MgmtIp" attr.type="string"/><key id="Capacities" for="node" attr.name="Capacities" attr.type="string"/><key id="Layer" for="node" attr.name="Layer" attr.type="string"/><key id="Name" for="node" attr.name="Name" attr.type="string"/><key id="LabelAllocations" for="node" attr.name="LabelAllocations" attr.type="string"/><key id="Type" for="node" attr.name="Type" attr.type="string"/><key id="Details" for="node" attr.name="Details" attr.type="string"/><key id="CapacityAllocations" for="node" attr.name="CapacityAllocations" attr.type="string"/><key id="ReservationInfo" for="node" attr.name="ReservationInfo" attr.type="string"/><key id="NodeID" for="node" attr.name="NodeID" attr.type="string"/><key id="Model" for="node" attr.name="Model" attr.type="string"/><key id="NodeMap" for="node" attr.name="NodeMap" attr.type="string"/><key id="Class" for="node" attr.name="Class" attr.type="string"/><key id="id" for="node" attr.name="id" attr.type="string"/><key id="StitchNode" for="node" attr.name="StitchNode" attr.type="string"/><key id="label" for="edge" attr.name="label" attr.type="string"/><key id="Class" for="edge" attr.name="Class" attr.type="string"/><graph id="G" edgedefault="directed"><node id="n393" labels=":GraphNode:NetworkNode"><data key="labels">:GraphNode:NetworkNode</data><data key="MgmtIp">128.163.179.51</data><data key="ReservationInfo">{"reservation_id": "8d47bd65-6ce4-47e7-bc89-1e021b6264ed", "reservation_state": "Active"}</data><data key="NodeMap">["4c9df36e-0e5b-4012-a78c-27f858d1b5ef", "3JB2R53"]</data><data key="LabelAllocations">{"instance": "instance-000004c3", "instance_parent": "uky-w1.fabric-testbed.net"}</data><data key="Class">NetworkNode</data><data key="Name">n2</data><data key="CapacityAllocations">{"core": 2, "disk": 10, "ram": 8}</data><data key="ImageRef">default_centos_8,qcow2</data><data key="Type">VM</data><data key="NodeID">510b85fe-1c4d-47d6-9c1e-2a5df1415535</data><data key="Site">UKY</data><data key="Capacities">{"core": 2, "disk": 10, "ram": 6}</data><data key="StitchNode">false</data><data key="id">28</data><data key="GraphID">7a45613b-b0b6-4454-89b7-a3020b1bb781</data></node><node id="n394" labels=":Component:GraphNode"><data key="labels">:Component:GraphNode</data><data key="LabelAllocations">{"bdf": "0000:a1:16.4"}</data><data key="CapacityAllocations">{"unit": 1}</data><data key="Class">Component</data><data key="Name">n2-nic1</data><data key="Type">SharedNIC</data><data key="Model">ConnectX-6</data><data key="NodeID">62628d0a-89e3-49a5-87bd-17c8bb047543</data><data key="Details">Mellanox ConnectX-6 VPI MCX653 dual port 100Gbps</data><data key="StitchNode">false</data><data key="id">29</data><data key="NodeMap">["4c9df36e-0e5b-4012-a78c-27f858d1b5ef", "3JB2R53-slot6"]</data><data key="GraphID">7a45613b-b0b6-4454-89b7-a3020b1bb781</data></node><node id="n395" labels=":GraphNode:NetworkService"><data key="labels">:GraphNode:NetworkService</data><data key="Name">n2-n2-nic1-l2ovs</data><data key="Class">NetworkService</data><data key="NodeID">1cfea468-c29d-45ee-b9ea-d1da5a779495</data><data key="StitchNode">false</data><data key="id">30</data><data key="Type">OVS</data><data key="Layer">L2</data><data key="GraphID">7a45613b-b0b6-4454-89b7-a3020b1bb781</data></node><node id="n396" labels=":ConnectionPoint:GraphNode"><data key="labels">:ConnectionPoint:GraphNode</data><data key="Class">ConnectionPoint</data><data key="Labels">{"local_name": "p1"}</data><data key="Type">SharedPort</data><data key="Name">n2-nic1-p1</data><data key="NodeID">4f60ed7c-01c6-4786-9de2-664b5840f55b</data><data key="Capacities">{"unit": 1}</data><data key="StitchNode">false</data><data key="id">31</data><data key="GraphID">7a45613b-b0b6-4454-89b7-a3020b1bb781</data></node><edge id="e380" source="n393" target="n394" label="has"><data key="label">has</data><data key="Class">has</data></edge><edge id="e381" source="n394" target="n395" label="has"><data key="label">has</data><data key="Class">has</data></edge><edge id="e382" source="n395" target="n396" label="connects"><data key="label">connects</data><data key="Class">connects</data></edge></graph></graphml>
diff --git a/test/before.graphml b/test/before.graphml
new file mode 100644
index 0000000..036a167
--- /dev/null
+++ b/test/before.graphml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?><graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"><key id="Site" for="node" attr.name="Site" attr.type="string"/><key id="labels" for="node" attr.name="labels" attr.type="string"/>
+<key id="ImageRef" for="node" attr.name="ImageRef" attr.type="string"/><key id="GraphID" for="node" attr.name="GraphID" attr.type="string"/><key id="Labels" for="node" attr.name="Labels" attr.type="string"/><key id="label" for="node" attr.name="label" attr.type="string"/><key id="Capacities" for="node" attr.name="Capacities" attr.type="string"/><key id="Layer" for="node" attr.name="Layer" attr.type="string"/><key id="Name" for="node" attr.name="Name" attr.type="string"/><key id="LabelAllocations" for="node" attr.name="LabelAllocations" attr.type="string"/><key id="Type" for="node" attr.name="Type" attr.type="string"/><key id="Details" for="node" attr.name="Details" attr.type="string"/><key id="CapacityAllocations" for="node" attr.name="CapacityAllocations" attr.type="string"/><key id="ReservationInfo" for="node" attr.name="ReservationInfo" attr.type="string"/><key id="NodeID" for="node" attr.name="NodeID" attr.type="string"/><key id="Model" for="node" attr.name="Model" attr.type="string"/><key id="NodeMap" for="node" attr.name="NodeMap" attr.type="string"/><key id="Class" for="node" attr.name="Class" attr.type="string"/><key id="id" for="node" attr.name="id" attr.type="string"/><key id="StitchNode" for="node" attr.name="StitchNode" attr.type="string"/><key id="label" for="edge" attr.name="label" attr.type="string"/><key id="Class" for="edge" attr.name="Class" attr.type="string"/><graph id="G" edgedefault="directed"><node id="n393" labels=":GraphNode:NetworkNode"><data key="labels">:GraphNode:NetworkNode</data><data key="LabelAllocations">{"instance_parent": "uky-w1.fabric-testbed.net"}</data><data key="NodeMap">["4c9df36e-0e5b-4012-a78c-27f858d1b5ef", "3JB2R53"]</data><data key="ReservationInfo">{"reservation_id": "8d47bd65-6ce4-47e7-bc89-1e021b6264ed", "reservation_state": "Ticketed"}</data><data key="Class">NetworkNode</data><data key="Name">n2</data><data key="CapacityAllocations">{"core": 2, "disk": 10, "ram": 8}</data><data key="ImageRef">default_centos_8,qcow2</data><data key="Type">VM</data><data key="NodeID">510b85fe-1c4d-47d6-9c1e-2a5df1415535</data><data key="Site">UKY</data><data key="Capacities">{"core": 2, "disk": 10, "ram": 6}</data><data key="StitchNode">false</data><data key="id">28</data><data key="GraphID">7a45613b-b0b6-4454-89b7-a3020b1bb781</data></node><node id="n394" labels=":Component:GraphNode"><data key="labels">:Component:GraphNode</data><data key="LabelAllocations">{"bdf": "0000:a1:16.4"}</data><data key="CapacityAllocations">{"unit": 1}</data><data key="Class">Component</data><data key="Name">n2-nic1</data><data key="Type">SharedNIC</data><data key="Model">ConnectX-6</data><data key="NodeID">62628d0a-89e3-49a5-87bd-17c8bb047543</data><data key="Details">Mellanox ConnectX-6 VPI MCX653 dual port 100Gbps</data><data key="StitchNode">false</data><data key="id">29</data><data key="NodeMap">["4c9df36e-0e5b-4012-a78c-27f858d1b5ef", "3JB2R53-slot6"]</data><data key="GraphID">7a45613b-b0b6-4454-89b7-a3020b1bb781</data></node><node id="n395" labels=":GraphNode:NetworkService"><data key="labels">:GraphNode:NetworkService</data><data key="Name">n2-n2-nic1-l2ovs</data><data key="Class">NetworkService</data><data key="NodeID">1cfea468-c29d-45ee-b9ea-d1da5a779495</data><data key="StitchNode">false</data><data key="id">30</data><data key="Type">OVS</data><data key="Layer">L2</data><data key="GraphID">7a45613b-b0b6-4454-89b7-a3020b1bb781</data></node><node id="n396" labels=":ConnectionPoint:GraphNode"><data key="labels">:ConnectionPoint:GraphNode</data><data key="Class">ConnectionPoint</data><data key="Labels">{"local_name": "p1"}</data><data key="Type">SharedPort</data><data key="Name">n2-nic1-p1</data><data key="NodeID">4f60ed7c-01c6-4786-9de2-664b5840f55b</data><data key="Capacities">{"unit": 1}</data><data key="StitchNode">false</data><data key="id">31</data><data key="GraphID">7a45613b-b0b6-4454-89b7-a3020b1bb781</data></node><edge id="e380" source="n393" target="n394" label="has"><data key="label">has</data><data key="Class">has</data></edge><edge id="e381" source="n394" target="n395" label="has"><data key="label">has</data><data key="Class">has</data></edge><edge id="e382" source="n395" target="n396" label="connects"><data key="label">connects</data><data key="Class">connects</data></edge></graph></graphml>
diff --git a/test/catalog_test.py b/test/catalog_test.py
index e206367..d7cc876 100644
--- a/test/catalog_test.py
+++ b/test/catalog_test.py
@@ -28,17 +28,18 @@ def testCatalog(self):
         c3port = c3ns.interface_info.get_interface(c3ns.interface_info.get_interface_names()[0])
         self.assertEqual(c3port.get_property('capacities').bw, 0)
 
-
     def testInstanceCatalog(self):
         cata = InstanceCatalog()
-        cap = Capacities(ram=20, cpu=1, core=9, disk=110)
+        cap = Capacities(ram=4, core=1, disk=90)
         c = cata.map_capacities_to_instance(cap=cap)
+        print(f'For {cap=} instance is {c}')
         cap1 = cata.get_instance_capacities(instance_type=c)
-        self.assertTrue(cap1.core > cap.core and cap1.ram > cap.ram and cap1.disk > cap.disk)
-        cap = Capacities(ram=20, cpu=1, core=9, disk=110)
+        self.assertTrue(cap1.core >= cap.core and cap1.ram >= cap.ram and cap1.disk >= cap.disk)
+        cap = Capacities(ram=20, core=9, disk=110)
         c = cata.map_capacities_to_instance(cap=cap)
+        print(f'For {cap=} instance is {c}')
         cap1 = cata.get_instance_capacities(instance_type=c)
-        self.assertTrue(cap1.core > cap.core and cap1.ram > cap.ram and cap1.disk > cap.disk)
+        self.assertTrue(cap1.core >= cap.core and cap1.ram >= cap.ram and cap1.disk >= cap.disk)
 
     def testComponentTypeModel(self):
         cata = ComponentCatalog()
diff --git a/test/modify_test.py b/test/modify_test.py
new file mode 100644
index 0000000..8c9ccdc
--- /dev/null
+++ b/test/modify_test.py
@@ -0,0 +1,247 @@
+import unittest
+import uuid
+from typing import Any
+
+import cProfile
+from pstats import Stats
+
+import fim.user as f
+
+from fim.graph.neo4j_property_graph import Neo4jGraphImporter
+from fim.slivers.attached_components import ComponentType
+from fim.slivers.network_service import ServiceType
+from fim.user.topology import TopologyDiff, TopologyDiffTuple
+from fim.slivers.capacities_labels import ReservationInfo
+
+WITH_PROFILER = False
+
+
+class ModifyTest(unittest.TestCase):
+
+    neo4j = {"url": "neo4j://0.0.0.0:7687",
+             "user": "neo4j",
+             "pass": "password",
+             "import_host_dir": "neo4j/imports/",
+             "import_dir": "/imports"}
+
+    def initialTopo(self):
+        """
+        Define an initial topology before modify
+        """
+        nA = self.topoA.add_node(name='NodeA', site='RENC')
+        nic1 = nA.add_component(name='nic1', ctype=ComponentType.SmartNIC, model='ConnectX-6')
+        nic3 = nA.add_component(name='nic3', ctype=ComponentType.SharedNIC, model='ConnectX-6')
+        nC = self.topoA.add_node(name='NodeC', site='RENC')
+        nic2 = nC.add_component(name='nic2', ctype=ComponentType.SharedNIC, model='ConnectX-6')
+        nC.add_component(name='drive1', ctype=ComponentType.NVME, model='P4510')
+        self.topoA.add_network_service(name='bridge1', nstype=ServiceType.L2Bridge,
+                                       interfaces=[nic3.interface_list[0], nic2.interface_list[0]])
+
+        self.topoA.add_network_service(name='bridge2', nstype=ServiceType.L2Bridge)
+        nD = self.topoA.add_node(name='NodeD', site='UKY')
+        nic4 = nD.add_component(name='nic4', ctype=ComponentType.SharedNIC, model='ConnectX-6')
+        self.topoA.network_services['bridge2'].connect_interface(nic4.interface_list[0])
+        nE = self.topoA.add_node(name='NodeE', site='UKY')
+        nic5 = nE.add_component(name='nic5', ctype=ComponentType.SharedNIC, model='ConnectX-6')
+        self.topoA.network_services['bridge2'].connect_interface(nic5.interface_list[0])
+
+        self.topoA.validate()
+
+        self.diff = TopologyDiff(added=TopologyDiffTuple(nodes=set(), components=set(),
+                                                         services=set(), interfaces=set()),
+                                 removed=TopologyDiffTuple(nodes=set(), components=set(),
+                                                           services=set(), interfaces=set()))
+
+    def modifyActions(self):
+        """
+        Define modify actions on the initial topo
+        """
+        #
+        # add a node with components, components won't show up as 'added'
+        nB = self.topoB.add_node(name='NodeB', site='UKY')
+        nic2 = nB.add_component(name='nic2', ctype=ComponentType.SmartNIC, model='ConnectX-5')
+        nB.add_component(name='gpu2', ctype=ComponentType.GPU, model='RTX6000')
+        self.diff.added.nodes.add(nB)
+
+        #
+        # add a network service between new node and old node (will show up as added)
+        #
+        s1 = self.topoB.add_network_service(name='ns2', nstype=ServiceType.L2PTP,
+                                            interfaces=[self.topoB.nodes['NodeA'].components['nic1'].interface_list[0],
+                                                        nic2.interface_list[0]])
+        self.diff.added.services.add(s1)
+
+        #
+        # add a connection to a facility to the second port of nic1
+        #
+        f1 = self.topoB.add_facility(name='RENCI-DTN', site='RENC', capacities=f.Capacities(bw=10),
+                                     labels=f.Labels(vlan='100'))
+        sfac = self.topoB.add_network_service(name='s-fac', nstype=f.ServiceType.L2STS,
+                                              interfaces=[f1.interface_list[0],
+                                                          self.topoB.nodes['NodeA'].components['nic1'].interface_list[1]])
+        self.diff.added.nodes.add(f1)
+        self.diff.added.services.add(sfac)
+
+        #
+        # add a component to old node (will show up as added)
+        #
+        c1 = self.topoB.nodes['NodeA'].add_component(name='gpu1', ctype=ComponentType.GPU, model='RTX6000')
+        self.diff.added.components.add(c1)
+
+        #
+        # remove old node (will show up as removed), should also
+        #
+        self.diff.removed.nodes.add(self.topoA.nodes['NodeC'])
+        self.topoB.remove_node(name='NodeC')
+
+        #
+        # Remove the bridge service (as it now connects nothing)
+        #
+        self.diff.removed.services.add(self.topoA.network_services['bridge1'])
+        self.topoB.remove_network_service(name='bridge1')
+
+        #
+        # add a node and connect to bridge2 (need connect/disconnect on services)
+        #
+        nF = self.topoB.add_node(name='NodeF', site='UKY')
+        self.diff.added.nodes.add(nF)
+        nic6 = nF.add_component(name='nic6', ctype=ComponentType.SharedNIC, model='ConnectX-6')
+        self.topoB.network_services['bridge2'].connect_interface(nic6.interface_list[0])
+        # add peer of this interface (that is attached to the service) to list of things we should find in a diff
+        self.diff.added.interfaces.add(nic6.interface_list[0].get_peers()[0])
+
+        #
+        # disconnect Node D from bridge2
+        #
+        # we need to get the interface from topoA because in topoB it will be missing
+        disconnected_interface = self.topoA.nodes['NodeD'].components['nic4'].interface_list[0]
+        self.diff.removed.interfaces.add(disconnected_interface.get_peers()[0])
+        self.topoB.network_services['bridge2'].disconnect_interface(disconnected_interface)
+
+        self.topoB.validate()
+
+    def modifyActions1(self):
+        #
+        # add a component to old node (will show up as added)
+        #
+        c1 = self.topoB.nodes['NodeA'].add_component(name='gpu1', ctype=ComponentType.GPU, model='RTX6000')
+        self.diff.added.components.add(c1)
+
+        self.topoB.validate()
+
+    def setUp(self) -> None:
+        if WITH_PROFILER: self.pr = cProfile.Profile()
+
+        self.n4j_imp = Neo4jGraphImporter(url=self.neo4j["url"], user=self.neo4j["user"],
+                                          pswd=self.neo4j["pass"],
+                                          import_host_dir=self.neo4j["import_host_dir"],
+                                          import_dir=self.neo4j["import_dir"])
+        self.topoA = f.ExperimentTopology(importer=self.n4j_imp)
+        print(f'Created topology A with GUID {self.topoA.graph_model.graph_id}')
+        # create initial topology
+        self.initialTopo()
+        # serialize
+        graph_A_string = self.topoA.serialize()
+        # load as topo B with alternate GUID, don't pass graph string
+        # to constructor - it will re-use the GUID
+        self.topoB = f.ExperimentTopology(importer=self.n4j_imp)
+        new_id = str(uuid.uuid4())
+        self.topoB.load(graph_string=graph_A_string, new_graph_id=new_id)
+        print(f'Created topology B with new GUID {self.topoB.graph_model.graph_id}/{new_id}')
+
+    @staticmethod
+    def compare_sets(diff1: set[Any], diff2: set[Any], str):
+        if diff1 != diff2:
+            raise Exception(f"Topology differences don't match in {str}: {d}")
+
+    @staticmethod
+    def compare_tuples(diff1: TopologyDiffTuple, diff2: TopologyDiffTuple):
+        ModifyTest.compare_sets(diff1.nodes, diff2.nodes, 'nodes')
+        ModifyTest.compare_sets(diff1.services, diff2.services, 'services')
+        ModifyTest.compare_sets(diff1.components, diff2.components, 'components')
+        ModifyTest.compare_sets(diff1.interfaces, diff2.interfaces, 'interfaces')
+
+    @staticmethod
+    def compare_diffs(diff1: TopologyDiff, diff2: TopologyDiff):
+        ModifyTest.compare_tuples(diff1.added, diff2.added)
+        ModifyTest.compare_tuples(diff1.removed, diff2.removed)
+
+    def tearDown(self) -> None:
+        pass
+        self.n4j_imp.delete_all_graphs()
+        if WITH_PROFILER:
+            p = Stats(self.pr)
+            p.strip_dirs()
+            p.sort_stats('ncalls')
+            p.print_stats()
+            print('\n')
+
+    def testNodeAddRemove(self):
+        """
+        Run the diff between topoA and topoB and validate the results
+        """
+        print('*** Full diff test')
+        self.modifyActions()
+
+        if WITH_PROFILER: self.pr.enable()
+        diff_res = self.topoA.diff(self.topoB)
+        if WITH_PROFILER: self.pr.disable()
+
+        ModifyTest.compare_diffs(diff_res, self.diff)
+
+        print(f'Result {diff_res=}')
+        #print(f'\nExpected {self.diff}')
+        #print(f'\nStarting Topo {self.topoA}')
+        #print(f'\nFinal Topo {self.topoB}')
+
+    def testComponentAddOnly(self):
+        print('*** Component add test')
+        self.modifyActions1()
+
+        if WITH_PROFILER: self.pr.enable()
+        diff_res = self.topoA.diff(self.topoB)
+        if WITH_PROFILER: self.pr.disable()
+
+        ModifyTest.compare_diffs(diff_res, self.diff)
+
+        #print(f'Result {diff_res=}')
+        #print(f'\nExpected {self.diff}')
+        #print(f'\nStarting Topo {self.topoA}')
+        #print(f'\nFinal Topo {self.topoB}')
+
+    def testSliverDiffs(self):
+
+        print('*** Sliver diff test')
+        self.modifyActions()
+
+        nAA = self.topoA.nodes['NodeA']
+        print(f'{nAA.components=}')
+        nAB = self.topoB.nodes['NodeA']
+        print(f'{nAB.components=}')
+        nAAs = nAA.get_sliver()
+        nABs = nAB.get_sliver()
+
+        if WITH_PROFILER: self.pr.enable()
+        diff = nAAs.diff(nABs)
+        if WITH_PROFILER: self.pr.disable()
+
+        assert(len(diff.added.components) == 1)
+        assert('gpu1' in diff.added.components)
+
+        print(f'Sliver diff {diff}')
+
+    def testPrune(self):
+
+        print('*** Prune test')
+
+        print(self.topoA.nodes)
+
+        self.topoA.nodes['NodeA'].reservation_info = ReservationInfo(reservation_state="Failed")
+        self.topoA.network_services['bridge1'].reservation_info = ReservationInfo(reservation_state="Failed")
+
+        self.topoA.prune(reservation_state="Failed")
+
+        self.assertTrue('NodeA' not in self.topoA.nodes.keys())
+        self.assertTrue('bridge1' not in self.topoA.network_services.keys())
+
+        print(self.topoA.nodes)
diff --git a/test/slice_topology_test.py b/test/slice_topology_test.py
index 60758b4..bd72d51 100644
--- a/test/slice_topology_test.py
+++ b/test/slice_topology_test.py
@@ -137,6 +137,8 @@ def testNodesAndComponents(self):
         self.assertEqual(service_port, None)
 
         self.topo.add_network_service(name='s1', nstype=f.ServiceType.L2Bridge, interfaces=self.topo.interface_list)
+        # validate sets node names on services
+        self.topo.validate()
         print(self.topo.network_services['s1'])
         assert(self.topo.network_services['s1'].get_property('site') == 'RENC')
 
@@ -554,10 +556,11 @@ def testL3Service(self):
         with self.assertRaises(TopologyException):
             self.topo.add_network_service(name='bad_service', nstype=f.ServiceType.FABNetv4,
                                           interfaces=self.topo.interface_list)
-        # site property is set automagically
+        # site property is set automagically by validate
+        # NOTE: site property NO LONGER SET BY CONSTRUCTOR
+        self.topo.validate()
         self.assertEqual(s1.site, 'UKY')
         self.assertEqual(s2.site, 'RENC')
-        self.topo.validate()
 
         slice_graph = self.topo.serialize()
 
@@ -576,9 +579,14 @@ def testPortMirrorService(self):
         n2.add_component(name='nic1', model_type=ComponentModelType.SharedNIC_ConnectX_6)
         n3 = t.add_node(name='n3', site='RENC')
         n3.add_component(name='nic1', model_type=ComponentModelType.SmartNIC_ConnectX_6)
-        with self.assertRaises(TopologyException) as e:
-            t.add_network_service(name='ns1', nstype=ServiceType.PortMirror,
-                                  interfaces=[n1.interface_list[0], n2.interface_list[0]])
+
+        t.add_network_service(name='ns1', nstype=ServiceType.PortMirror,
+                              interfaces=[n1.interface_list[0], n2.interface_list[0]])
+        with self.assertRaises(TopologyException):
+            t.validate()
+
+        t.remove_network_service(name='ns1')
+        t.validate()
         t.add_network_service(name='ns1', nstype=ServiceType.L2STS,
                               interfaces=[n1.interface_list[0], n2.interface_list[0]])
         t.add_port_mirror_service(name='pm1', from_interface_name='blahname',
diff --git a/test/sliver_test.py b/test/sliver_test.py
index afee6f6..82be6ad 100644
--- a/test/sliver_test.py
+++ b/test/sliver_test.py
@@ -77,7 +77,7 @@ def testCapacitiesLabels(self):
             Labels(vlan_range='1-8000')
 
         with self.assertRaises(LabelException):
-            Labels(asn='600000')
+            Labels(asn='60000000000')
 
         with self.assertRaises(LabelException):
             Labels(vlan='4098')
diff --git a/test/substrate_topology_test.py b/test/substrate_topology_test.py
index 2e08238..8c01e27 100644
--- a/test/substrate_topology_test.py
+++ b/test/substrate_topology_test.py
@@ -313,6 +313,7 @@ def testRENCSiteAd(self):
                                node_id=sp.node_id + '-DAC')
             link_idx += 1
 
+        self.topo.validate()
         #
         # delegations
         #
@@ -629,6 +630,7 @@ def testUKYSiteAd(self):
                                node_id=sp.node_id + '-DAC')
             link_idx += 1
 
+        self.topo.validate()
         #
         # delegations
         #
@@ -931,6 +933,7 @@ def testLBNLSiteAd(self):
                                node_id=sp.node_id + '-DAC')
             link_idx += 1
 
+        self.topo.validate()
         #
         # delegations
         #
@@ -1012,7 +1015,7 @@ def testNetworkAd(self):
         dp_ns = switch.add_network_service(name=switch.name+'-ns',
                                            node_id=switch.node_id + '-ns',
                                            nstype=f.ServiceType.MPLS,
-                                           labels=f.Labels(vlan_range='1-100'))
+                                           labels=f.Labels(vlan_range=['1-100', '201-300']))
         dp_l3ns = switch.add_network_service(name=switch.name + '-l3ns',
                                              node_id=switch.node_id + '-l3ns',
                                              nstype=f.ServiceType.FABNetv4,
@@ -1129,7 +1132,7 @@ def testNetworkAd(self):
                                             ltype=f.LinkType.L2Path,
                                             interfaces=[fac2.interface_list[0], # only one interface available
                                                         facility_port_facing_port])
-
+        self.topo.validate()
         delegation1 = 'primary'
         print('RUNNING NETWORK AD DELEGATIONS')
         self.topo.single_delegation(delegation_id=delegation1,
@@ -1475,6 +1478,8 @@ def testRENCI_non_save(self):
         pools.build_index_by_delegation_id()
         pools.validate_pools()
 
+        self.topo.validate()
+
         # form delegation using pools
         self.topo.single_delegation(delegation_id=delegation1,
                                     label_pools=pools,
diff --git a/test/zz_neo4j_pg_test.py b/test/zz_neo4j_pg_test.py
index 765999c..0f62fdd 100644
--- a/test/zz_neo4j_pg_test.py
+++ b/test/zz_neo4j_pg_test.py
@@ -12,6 +12,10 @@
 
 
 class Neo4jTests(unittest.TestCase):
+    """
+    Please note this depends on substrate_topology_test.py executing first as it
+    creates graphml files needed here.
+    """
 
     neo4j = {"url": "neo4j://0.0.0.0:7687",
              "user": "neo4j",