[CORD-3091] Pulling NNI and PON ports

Change-Id: I001782ffd8a092371f4939869c9c6dda2360bf98
diff --git a/xos/synchronizer/models/models.py b/xos/synchronizer/models/models.py
index eeb5e74..9431488 100644
--- a/xos/synchronizer/models/models.py
+++ b/xos/synchronizer/models/models.py
@@ -12,12 +12,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import random
+
 from core.models.xosbase import *
+from xos.exceptions import XOSValidationError
 
 from models_decl import VOLTService_decl
 from models_decl import VOLTServiceInstance_decl
 from models_decl import OLTDevice_decl
 from models_decl import PONPort_decl
+from models_decl import NNIPort_decl
 from models_decl import ONUDevice_decl
 
 class VOLTService(VOLTService_decl):
@@ -45,7 +49,44 @@
 
 class PONPort(PONPort_decl):
     class Meta:
-        proxy = True 
+        proxy = True
+
+    def generate_tag(self):
+        # NOTE this method will loop if available c_tags are ended
+        tag = random.randint(16, 4096)
+        if tag in self.get_used_s_tags():
+            return self.generate_tag()
+        return tag
+
+    def get_used_s_tags(self):
+        same_olt_device = OLTDevice.objects.filter(device_id=self.olt_device)
+        return [s.c_tag for s in same_olt_device]
+
+    def save(self, *args, **kwargs):
+        # validate s_tag
+        if hasattr(self, 's_tag') and self.s_tag is not None:
+            is_update_with_same_tag = False
+
+            if not self.is_new:
+                # if it is an update, but the tag is the same, skip validation
+                existing = PONPort.objects.filter(s_tag=self.s_tag)
+
+                if len(existing) > 0 and existing[0].s_tag == self.s_tag and existing[0].id == self.id:
+                    is_update_with_same_tag = True
+
+            if self.s_tag in self.get_used_s_tags() and not is_update_with_same_tag:
+                raise XOSValidationError(
+                    "The s_tag you specified (%s) has already been used on device %s" % (self.s_tag, self.onu_device))
+
+        if not hasattr(self, "s_tag") or self.s_tag is None:
+            self.s_tag = self.generate_tag()
+
+        super(PONPort, self).save(*args, **kwargs)
+
+
+class NNIPort(NNIPort_decl):
+    class Meta:
+        proxy = True
 
 
 class ONUDevice(ONUDevice_decl):
diff --git a/xos/synchronizer/models/volt.xproto b/xos/synchronizer/models/volt.xproto
index 79c753e..0eda4e0 100644
--- a/xos/synchronizer/models/volt.xproto
+++ b/xos/synchronizer/models/volt.xproto
@@ -48,13 +48,26 @@
     optional string outer_tpid = 19 [help_text = "Outer VLAN id field EtherType", null = False, db_index = False, blank = False];
 }
 
-message PONPort (XOSBase){
+message PortBase (XOSBase){
+    option gui_hidden = True;
+
+    required string name = 1 [db_index = True, null = False, blank = False];
+    required int32 port_no = 3 [help_text = "Port ID", null = False, db_index = False, blank = False];
+
+    optional string admin_state = 4 [help_text = "admin_state", null = True, db_index = False, blank = False, feedback_state = True];
+    optional string oper_status = 5 [help_text = "oper_status", null = True, db_index = False, blank = False, feedback_state = True];
+}
+
+message PONPort (PortBase){
     option verbose_name = "PON Port";
 
-    required string name = 1 [db_index = True, null = False, blank = False, unique_with="olt_device"];
-    required manytoone olt_device->OLTDevice:ports = 2 [db_index = True, null = False, blank = False];
-    required string port_id = 3 [help_text = "Port ID", max_length = 254, null = False, db_index = False, blank = False];
-    required int32 s_tag = 4 [help_text = "S Tag", null = False, db_index = False, blank = False];
+    required manytoone olt_device->OLTDevice:pon_ports = 1 [db_index = True, null = False, blank = False];
+    required int32 s_tag = 2 [help_text = "S Tag", null = False, db_index = False, blank = False];
+}
+
+message NNIPort (PortBase) {
+    option verbose_name = "NNI Port";
+    required manytoone olt_device->OLTDevice:nni_ports = 1 [db_index = True, null = False, blank = False];
 }
 
 message ONUDevice (XOSBase){