CORD-1849 Split XOS code out of OLT and VTN repos

Change-Id: I1511907372fba0bdb02e8603d916876b9d6ae180
diff --git a/xos/synchronizer/vtnnetport.py b/xos/synchronizer/vtnnetport.py
new file mode 100644
index 0000000..eaa037f
--- /dev/null
+++ b/xos/synchronizer/vtnnetport.py
@@ -0,0 +1,299 @@
+
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+from synchronizers.new_base.modelaccessor import *
+in_synchronizer = True
+
+class VTNNetwork(object):
+    def __init__(self, xos_network=None):
+        self.xos_network = xos_network
+
+    def get_controller_network(self):
+        for cn in self.xos_network.controllernetworks.all():
+            # TODO: find the right one
+            return cn
+        return None
+
+    def get_cn_field(self, fieldname):
+        cn=self.get_controller_network()
+        if not cn:
+            return None
+        return getattr(cn, fieldname)
+
+    @property
+    def id(self):
+        return self.get_cn_field("net_id")
+
+    @property
+    def name(self):
+        return self.xos_network.name
+
+    @property
+    def subnet(self):
+        return self.get_cn_field("subnet")
+
+    @property
+    def gateway(self):
+        return self.get_cn_field("gateway")
+
+    @property
+    def segmentation_id(self):
+        return self.get_cn_field("segmentation_id")
+
+    @property
+    def type(self):
+        return self.xos_network.template.vtn_kind
+
+    @property
+    def providerNetworks(self):
+        slice = self.xos_network.owner
+        service = slice.service
+        if not service:
+            return []
+
+        nets=[]
+        for dep in service.subscribed_dependencies.all():
+            if dep.provider_service:
+                bidirectional = dep.connect_method!="private-unidirectional"
+                for net in dep.provider_service.get_composable_networks():
+                    if not net.controllernetworks.exists():
+                        continue
+
+                    cn = net.controllernetworks.all()[0]
+
+                    if not cn.net_id:
+                        continue
+
+                    nets.append({"id": cn.net_id,
+                                 "name": net.name,
+                                 "bidirectional": bidirectional})
+        return nets
+
+    @property
+    def subscriberNetworks(self):
+        slice = self.xos_network.owner
+        service = slice.service
+        if not service:
+            return []
+
+        nets=[]
+        for dep in service.provided_dependencies.all():
+            if dep.subscriber_service:
+                bidirectional = dep.connect_method!="private-unidirectional"
+                for net in dep.subscriber_service.get_composable_networks():
+                    if not net.controllernetworks.exists():
+                        continue
+
+                    cn = net.controllernetworks.all()[0]
+
+                    if not cn.net_id:
+                        continue
+
+                    nets.append({"id": cn.net_id,
+                                 "name": net.name,
+                                 "bidirectional": bidirectional})
+        return nets
+
+    @property
+    def ownerSliceName(self):
+        if self.xos_network.owner:
+            return self.xos_network.owner.name
+        return None
+
+    @property
+    def ownerServiceName(self):
+        if self.xos_network.owner and self.xos_network.owner.service:
+            return self.xos_network.owner.service.name
+        return None
+
+    def to_dict(self):
+        return {"id": self.id,
+                "name": self.name,
+                "subnet": self.subnet,
+                "gateway": self.gateway,
+                "segmentation_id": self.segmentation_id,
+                "type": self.type,
+                "providerNetworks": self.providerNetworks,
+                "subscriberNetworks": self.subscriberNetworks,
+                "ownerSliceName": self.ownerSliceName,
+                "ownerServiceName": self.ownerServiceName}
+
+    def __eq__(self, other):
+        return self.to_dict() == other.to_dict()
+
+class VTNPort(object):
+    def __init__(self, xos_port=None):
+        self.xos_port = xos_port
+
+    def get_controller_network(self):
+        for cn in self.xos_port.network.controllernetworks.all():
+            # TODO: find the right one
+            return cn
+        return None
+
+    def is_access_network(self):
+        """ Determines whether this port is attached to an access network. Currently we do this by examining the
+            network template's vtn_kind field. See if there is a better way...
+        """
+        return self.xos_port.network.template.vtn_kind in ["VSG", ]
+
+    def get_vm_addresses(self):
+        if not self.is_access_network():
+            # If not an access network, do not apply any addresses
+            return []
+
+        if not self.xos_port.instance:
+            return []
+
+        # See if the Instance has any public address (aka "VrouterTenant) service instances associated with it.
+        # If so, then add each of those to the set of address pairs.
+
+        # TODO: Perhaps this should be implemented as a link instead of a tag...
+
+        tags = Tag.objects.filter(name="vm_public_service_instance", object_id=self.xos_port.instance.id,
+                                            content_type=self.xos_port.instance.self_content_type_id)
+
+        if not tags:
+            # DEPRECATED
+            # Historically, VSG instances are tagged with "vm_vrouter_tenant" instead of "vm_public_service_instance"
+            tags = Tag.objects.filter(name="vm_vrouter_tenant", object_id=self.xos_port.instance.id,
+                                                content_type=self.xos_port.instance.self_content_type_id)
+
+        address_pairs = []
+        for tag in tags:
+            si = ServiceInstance.objects.get(id = int(tag.value))
+
+            # cast from Tenant to descendant class (VRouterTenant, etc)
+            si = si.leaf_model
+
+            if (not hasattr(si, "public_ip")) or (not hasattr(si, "public_mac")):
+                raise Exception("Object %s does not have public_ip and/or public_mac fields" % si)
+            address_pairs.append({"ip_address": si.public_ip,
+                                  "mac_address": si.public_mac})
+
+        return address_pairs
+
+    def get_container_addresses(self):
+        if not self.is_access_network():
+            # If not an access network, do not apply any addresses
+            return []
+
+        if not self.xos_port.instance:
+            return []
+
+        addrs = []
+        for si in ServiceInstance.objects.all():
+            # cast from tenant to its descendant class (VSGTenant, etc)
+            si = si.leaf_model
+
+            if not hasattr(si, "instance_id"):
+                # ignore ServiceInstance that don't have instances
+                continue
+
+            if si.instance_id != self.xos_port.instance.id:
+                # ignore ServiceInstances that don't relate to our instance
+                continue
+
+            # Check to see if there is a link public address (aka VRouterTenant)
+            links = si.subscribed_links.all()
+            for link in links:
+                # cast from ServiceInstance to descendant class (VRouterTenant, etc)
+                pubaddr_si = link.provider_service_instance.leaf_model
+                if hasattr(pubaddr_si, "public_ip") and hasattr(pubaddr_si, "public_mac"):
+                    addrs.append({"ip_address": pubaddr_si.public_ip,
+                                  "mac_address": pubaddr_si.public_mac})
+        return addrs
+
+    @property
+    def vlan_id(self):
+        """ Return the vlan_id associated with this instance. This assumes the instance was tagged with either a
+            vlan_id or s_tag tag.
+        """
+
+        if not self.is_access_network():
+            # If not an access network, do not apply any tags
+            return []
+
+        if not self.xos_port.instance:
+            return None
+
+        tags = Tag.objects.filter(content_type=model_accessor.get_content_type_id(self.xos_port.instance),
+                                  object_id=self.xos_port.instance.id,
+                                  name="vlan_id")
+
+        if not tags:
+            # DEPRECATED
+            # Historically, VSG instances are tagged with "s_tag" instead of "vlan_id"
+            tags = Tag.objects.filter(content_type=model_accessor.get_content_type_id(self.xos_port.instance),
+                                      object_id=self.xos_port.instance.id,
+                                      name="s_tag")
+
+        if not tags:
+            return None
+
+        return tags[0].value
+
+    @property
+    def floating_address_pairs(self):
+        # Floating_address_pairs is the set of WAN addresses that should be
+        # applied to this port.
+
+        # We only want to apply these addresses to an "access" network.
+
+
+        address_pairs = self.get_vm_addresses() + self.get_container_addresses()
+
+        return address_pairs
+
+    @property
+    def id(self):
+        return self.xos_port.port_id
+
+    @property
+    def name(self):
+        return "port-%s" % self.xos_port.id
+
+    @property
+    def network_id(self):
+        cn = self.get_controller_network()
+        if not cn:
+            return None
+        return cn.net_id
+
+    @property
+    def network_name(self):
+        return self.xos_port.network.name
+
+    @property
+    def mac_address(self):
+        return self.xos_port.mac
+
+    @property
+    def ip_address(self):
+        return self.xos_port.ip
+
+    def to_dict(self):
+        return {"id": self.id,
+                "name": self.name,
+                "network_id": self.network_id,
+                "mac_address": self.mac_address,
+                "ip_address": self.ip_address,
+                "floating_address_pairs": self.floating_address_pairs,
+                "vlan_id": self.vlan_id}
+
+    def __eq__(self, other):
+        return self.to_dict() == other.to_dict()
+