CORD-2509 migrate progran service from static to dynamic load

Change-Id: Ic2bbd8d0107d39b8a94663ec47c46cadbf8632d6
diff --git a/xos/synchronizer/models/models.py b/xos/synchronizer/models/models.py
new file mode 100644
index 0000000..3544d25
--- /dev/null
+++ b/xos/synchronizer/models/models.py
@@ -0,0 +1,135 @@
+# 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 xos.exceptions import XOSValidationError
+
+from models_decl import ProgranService_decl
+from models_decl import ENodeB_decl
+from models_decl import Handover_decl
+from models_decl import ProgranServiceInstance_decl
+
+class ProgranService(ProgranService_decl):
+    class Meta:
+        proxy = True
+    def save(self, *args, **kwargs):
+
+        existing_services = ProgranService.objects.all()
+
+        if len(existing_services) > 0 and not self.delete:
+            raise XOSValidationError("A ProgranService already exists, you should not have more than one")
+
+        super(ProgranService, self).save(*args, **kwargs)
+
+
+class ENodeB(ENodeB_decl):
+    class Meta:
+        proxy = True
+
+    def save(self, *args, **kwargs):
+
+        # remove all the profiles related to this enodeb (clearing the relation, not the models)
+        if self.deleted:
+            self.profiles.clear()
+
+        # prevent enbId duplicates
+        try:
+            instance_with_same_id = ENodeB.objects.get(enbId=self.enbId)
+
+            if (not self.pk and instance_with_same_id) or (self.pk and self.pk != instance_with_same_id.pk):
+                raise XOSValidationError("A ENodeB with enbId '%s' already exists" % self.enbId)
+        except self.DoesNotExist:
+            pass
+
+        if self.is_new and not self.created_by:
+            # NOTE if created_by is null it has been created by XOS
+            self.created_by = "XOS"
+
+        super(ENodeB, self).save(*args, **kwargs)
+
+
+class Handover(Handover_decl):
+    class Meta:
+        proxy = True
+
+    def save(self, *args, **kwargs):
+        if self.is_new and not self.created_by:
+            # NOTE if created_by is null it has been created by XOS
+            self.created_by = "XOS"
+        super(Handover, self).save(*args, **kwargs)
+
+
+
+class ProgranServiceInstance(ProgranServiceInstance_decl):
+    class Meta:
+        proxy = True
+
+    def save(self, *args, **kwargs):
+
+        # TODO we should not allow name changes as name is the mapping with the backend
+
+        # name is mandatory
+        if not self.name:
+            raise XOSValidationError("name is mandatory for ProgranServiceInstances")
+
+        # NOTE this check is disabled as when Progran create a profile it fails
+        # if self.DlUeAllocRbRate > self.DlAllocRBRate:
+        #     raise XOSValidationError("DlUeAllocRbRate (%s) cannot be bigger than DlAllocRBRate (%s)" % (self.DlUeAllocRbRate, self.DlAllocRBRate))
+
+        # prevent name duplicates
+        try:
+            instances_with_same_name = ProgranServiceInstance.objects.get(name=self.name)
+
+            if (not self.pk and instances_with_same_name) or (self.pk and self.pk != instances_with_same_name.pk):
+                raise XOSValidationError("A ProgranServiceInstance with name '%s' already exists" % self.name)
+        except self.DoesNotExist:
+            pass
+
+        if self.is_new and not self.created_by:
+            # NOTE if created_by is null it has been created by XOS
+            self.created_by = "XOS"
+
+
+        # check that the sum of upload and download rate for a single enodeb is not greater than 95
+        if not self.deleted:
+            limit = 95
+            same_enodeb = ProgranServiceInstance.objects.filter(enodeb_id=self.enodeb_id)
+
+            total_up = self.UlAllocRBRate
+            total_down = self.DlAllocRBRate
+
+            for p in same_enodeb:
+                if p.pk != self.pk:
+                    total_up = total_up + p.UlAllocRBRate
+                    total_down = total_down + p.DlAllocRBRate
+
+            if total_up > limit:
+                raise XOSValidationError("UlAllocRBRate for the enodeb associated with this profile is greater than %s" % limit)
+
+            if total_down > limit:
+                raise XOSValidationError("DlAllocRBRate for the enodeb associated with this profile is greater than %s" % limit)
+
+        caller_kind = "xos"
+
+        if "caller_kind" in kwargs:
+            caller_kind = kwargs.pop("caller_kind")
+
+        print "Profile %s has been saved by %s" % (self.name, caller_kind)
+
+        if caller_kind == "xos":
+            print "Setting no_sync to false for profile %s" % self.name
+            self.no_sync = False
+
+        super(ProgranServiceInstance, self).save(*args, **kwargs)
+
+
diff --git a/xos/synchronizer/models/progran.xproto b/xos/synchronizer/models/progran.xproto
new file mode 100644
index 0000000..47e21db
--- /dev/null
+++ b/xos/synchronizer/models/progran.xproto
@@ -0,0 +1,63 @@
+option app_label = "progran";
+option name = "progran";
+option legacy = "True";
+
+message ProgranService (Service){
+    option verbose_name = "Progran Service";
+    required string onos_address = 1 [help_text = "Address of the progran ONOS", default = "onos-progran",  max_length = 254, null = False, db_index = False, blank = False];
+    required string onos_port = 2 [help_text = "Port of the progran ONOS", default = "8183", max_length = 254, null = False, db_index = False, blank = False];
+    required string onos_username = 3 [help_text = "Username of the progran ONOS", default = "karaf", max_length = 254, null = False, db_index = False, blank = False];
+    required string onos_password = 4 [help_text = "Password of the progran ONOS", default = "karaf", max_length = 254, null = False, db_index = False, blank = False];
+}
+
+message ENodeB (XOSBase){
+    option verbose_name = "eNodeB";
+    required string description = 1 [db_index = False, max_length = 256, null = False, blank = False];
+    required string enbId = 2 [help_text = "ID of this enodeb", db_index = False, max_length = 256, null = False, blank = False];
+    required string ipAddr = 3 [help_text = "IP address of this enodeb", db_index = False, max_length = 256, null = False, blank = False];
+    optional string created_by = 4 [null = True, blank = True, gui_hidden = True];
+    optional bool previously_sync = 5 [null = False, blank = True, default=False, gui_hidden = True];
+}
+
+message Handover (XOSBase){
+    option verbose_name = "Handover";
+    required int32 A3offset = 1 [default = 1, db_index = False, null = False, blank = False];
+    required int32 HysteresisA3 = 2 [default = 0, db_index = False, null = False, blank = False];
+    required int32 A3TriggerQuantity = 3 [default = 0, db_index = False, null = False, blank = False];
+    required int32 A5TriggerType = 4 [default = 0, db_index = False, null = False, blank = False];
+    required int32 A5Thresh1Rsrp = 5 [default = 74, db_index = False, null = False, blank = False];
+    required int32 A5Thresh1Rsrq = 6 [default = 10, db_index = False, null = False, blank = False];
+    required int32 A5Thresh2Rsrp = 7 [default = 78, db_index = False, null = False, blank = False];
+    required int32 A5Thresh2Rsrq = 8 [default = 10, db_index = False, null = False, blank = False];
+    required int32 HysteresisA5 = 9 [default = 1, db_index = False, null = False, blank = False];
+    required int32 A5TriggerQuantity = 10 [default = 0, db_index = False, null = False, blank = False];
+    optional string created_by = 11 [null = True, blank = True, gui_hidden = True];
+}
+
+message ProgranServiceInstance (ServiceInstance){
+    option verbose_name = "Progran Service Instance";
+    option description = "Represent a Profile in the Progran ONOS Application";
+    option owner_class_name="ProgranService";
+
+    required string DlSchedType = 1 [default = "RR", choices = "(('RR', 'Round Robin'), ('PF', 'Proportional Fairness'), ('MAXCI', 'Maximum C/I'))", max_length = 30, blank = False, null = False, db_index = False];
+    required int32 DlAllocRBRate = 2 [default = "0", db_index = False, null = False, blank = False];
+    required string UlSchedType = 3 [default = "RR", choices = "(('RR', 'Round Robin'), ('PF', 'Proportional Fairness'), ('MAXCI', 'Maximum C/I'))", max_length = 30, blank = False, null = False, db_index = False];
+    required int32 UlAllocRBRate = 4 [default = "0", db_index = False, null = False, blank = False];
+    required string start = 5 [content_type = "date", null = True, blank = True];
+    required string end = 6 [content_type = "date", null = True, blank = True];
+    required int32 AdmControl = 7 [default = "0", choices = "(('0', 'ALL'), ('1', 'Voice Only'), ('2', 'Data Only'))", blank = False, null = False, db_index = False];
+    required int32 CellIndividualOffset = 8 [db_index = False, null = False, blank = False];
+    required string mmeip = 9 [db_index = False, default = "0.0.0.0", max_length = 256, null = False, blank = False];
+    required string mmeport = 10 [db_index = False, default = "8080", max_length = 256, null = False, blank = False];
+    required int32 DlWifiRate = 11 [default = 100, db_index = False, null = False, blank = False];
+    required int32 DlUeAllocRbRate = 12 [default = "0", help_text = "DL Per UE allocation", db_index = False, null = True, blank = True];
+    required string SubsProfile = 13 [ db_index = False, null = True, blank = True];
+    optional bool Status = 14 [ db_index = False, null = False, blank = True, default = False];
+    optional manytoone enodeb->ENodeB:profiles = 15 [null = True, blank = True];
+    required manytoone handover->Handover:profiles = 16 [null = False, blank = False];
+    optional int32 active_enodeb_id = 17 [null = True, blank = True, gui_hidden = True];
+    optional string created_by = 17 [null = True, blank = True, gui_hidden = True];
+    optional bool previously_sync = 18 [null = False, blank = True, default=False, gui_hidden = True];
+}
+
+
diff --git a/xos/synchronizer/progran_config.yml b/xos/synchronizer/progran_config.yml
index 20892af..d3b209c 100644
--- a/xos/synchronizer/progran_config.yml
+++ b/xos/synchronizer/progran_config.yml
@@ -27,6 +27,7 @@
 dependency_graph: "/opt/xos/synchronizers/progran/model_deps"
 steps_dir: "/opt/xos/synchronizers/progran/steps"
 sys_dir: "/opt/xos/synchronizers/progran/sys"
+models_dir: "/opt/xos/synchronizers/progran/models"
 #model_policies_dir: "/opt/xos/synchronizers/progran/model_policies"
 
 logging: