[COMAC-228] Update progran-synchronizer based on XOS 3.0
Change-Id: I8316d0c58602c86a9df3f02501268877596770d6
diff --git a/xos/synchronizer/steps/sync_enodeb.py b/xos/synchronizer/steps/sync_enodeb.py
index 589142e..f9e1961 100644
--- a/xos/synchronizer/steps/sync_enodeb.py
+++ b/xos/synchronizer/steps/sync_enodeb.py
@@ -16,7 +16,7 @@
import os
import sys
-from xossynchronizer.steps.SyncInstanceUsingAnsible import SyncStep
+from xossynchronizer.steps.syncstep import SyncStep
from xossynchronizer.modelaccessor import ENodeB
from xosconfig import Config
diff --git a/xos/synchronizer/steps/sync_imsi.py b/xos/synchronizer/steps/sync_imsi.py
index aabec76..c895fd2 100644
--- a/xos/synchronizer/steps/sync_imsi.py
+++ b/xos/synchronizer/steps/sync_imsi.py
@@ -16,7 +16,7 @@
import os
import sys
-from xossynchronizer.steps.SyncInstanceUsingAnsible import SyncStep
+from xossynchronizer.steps.syncstep import SyncStep
from xossynchronizer.modelaccessor import MCordSubscriberInstance
from xosconfig import Config
diff --git a/xos/synchronizer/steps/sync_imsi_back.py b/xos/synchronizer/steps/sync_imsi_back.py
index e81232c..a462c23 100644
--- a/xos/synchronizer/steps/sync_imsi_back.py
+++ b/xos/synchronizer/steps/sync_imsi_back.py
@@ -20,7 +20,7 @@
import datetime
import time
-from xossynchronizer.steps.SyncInstanceUsingAnsible import SyncStep
+from xossynchronizer.steps.syncstep import SyncStep
from xossynchronizer.modelaccessor import MCordSubscriberInstance
from xosconfig import Config
diff --git a/xos/synchronizer/steps/sync_progranserviceinstance_back.py b/xos/synchronizer/steps/sync_progranserviceinstance_back.py
new file mode 100644
index 0000000..cc1b10c
--- /dev/null
+++ b/xos/synchronizer/steps/sync_progranserviceinstance_back.py
@@ -0,0 +1,191 @@
+
+# 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.
+
+
+import os
+import sys
+
+import datetime
+import time
+
+from xossynchronizer.steps.syncstep import SyncStep
+from xossynchronizer.modelaccessor import ProgranServiceInstance, ENodeB, Handover, ServiceInstanceLink, MCordSubscriberInstance
+
+from xosconfig import Config
+from multistructlog import create_logger
+import requests
+from requests.auth import HTTPBasicAuth
+
+
+
+log = create_logger(Config().get('logging'))
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+sys.path.insert(0, os.path.dirname(__file__))
+from helpers import ProgranHelpers
+
+class SyncProgranServiceInstanceBack(SyncStep):
+ provides = [ProgranServiceInstance]
+
+ observes = ProgranServiceInstance
+
+
+ def call(self, failed=[], deletion=False):
+ """
+ Read profile from progran and save them in xos
+ """
+
+ if deletion == False:
+ # NOTE we won't it to run only after the delete has completed
+ return
+
+ log.debug("Reading profiles from progran")
+ onos = ProgranHelpers.get_progran_onos_info(self.model_accessor)
+ profile_url = "http://%s:%s/onos/progran/profile/" % (onos['url'], onos['port'])
+ r = requests.get(profile_url, auth=HTTPBasicAuth(onos['username'], onos['password']))
+ res = r.json()['ProfileArray']
+
+
+ # remove default profiles
+ res = [p for p in res if "Default" not in p['Name']]
+ pnames = [p['Name'] for p in res]
+ log.debug("Received Profiles: ", profiles=pnames)
+
+ field_mapping = {
+ 'Name': 'name',
+ 'Start': 'start',
+ 'End': 'end',
+ }
+
+ field_transformations = {
+ 'Start': ProgranHelpers.date_to_time,
+ 'End': ProgranHelpers.date_to_time
+ }
+
+ handover_mapping = {
+ 'A5Hysteresis': 'HysteresisA5',
+ 'A3Hysteresis': 'HysteresisA3'
+ }
+
+ updated_profiles = []
+
+ for p in res:
+
+
+ # checking for profiles
+ try:
+ si = ProgranServiceInstance.objects.get(name=p['Name'])
+ log.debug("Profile %s already exists, updating it" % p['Name'])
+
+ except IndexError:
+ si = ProgranServiceInstance()
+
+ si.created_by = "Progran"
+
+ log.debug("Profile %s is new, creating it" % p['Name'])
+
+ if not si.is_new:
+ # update IMSI association
+ xos_imsis_for_profile = [i.subscriber_service_instance.leaf_model for i in si.provided_links.all()]
+ progran_imsis_for_profile = p['IMSIRuleArray']
+
+ log.debug("List of imsis for profile %s in XOS" % p["Name"], imsis=xos_imsis_for_profile)
+ log.debug("List of imsis for profile %s in ONOS" % p["Name"], imsis=progran_imsis_for_profile)
+
+ for i in xos_imsis_for_profile:
+ if not i.imsi_number in progran_imsis_for_profile:
+ log.debug("Removing Imsi %s from profile %s" % (i.imsi_number, p['Name']))
+
+ imsi_link = ServiceInstanceLink.objects.get(subscriber_service_instance_id=i.id)
+
+ # NOTE: this model has already been removed from the backend, no need to synchronize
+ imsi_link.backend_need_delete = False
+ imsi_link.no_sync = True
+ imsi_link.save() # we need to save it to avoid a synchronization loop
+
+ imsi_link.delete()
+ else:
+ # remove from imsi list coming from progran everything we already know about
+ progran_imsis_for_profile.remove(i.imsi_number)
+
+ for i in progran_imsis_for_profile:
+ log.debug("Adding Imsi %s to profile %s" % (i, p['Name']))
+ imsi = MCordSubscriberInstance.objects.get(imsi_number=i)
+ imsi_to_profile = ServiceInstanceLink(provider_service_instance=si,
+ subscriber_service_instance=imsi)
+ imsi_to_profile.save()
+
+ # if the model has not been synchronized yet, skip it
+ if not si.is_new and si.no_sync is False:
+ log.debug("Skipping profile %s as not synchronized" % p['Name'])
+ # NOTE add it to the removed profiles to avoid deletion (this is ugly, I know)
+ updated_profiles.append(si.name)
+ continue
+
+ # ugly fix
+ if 'AdmControl' in p.keys():
+ p['AdmControl'] = str(p['AdmControl'])
+
+ si = ProgranHelpers.update_fields(si, p, field_mapping, field_transformations)
+
+ # checking for handovers
+ handover_dict = p['Handover']
+ handover_dict = ProgranHelpers.convert_keys(handover_dict, handover_mapping)
+ del p['Handover']
+
+ if si.handover_id:
+ handover = si.handover
+ log.debug("handover already exists, updating it", handover=handover_dict)
+ else:
+ handover = Handover()
+ handover = ProgranHelpers.update_fields(handover, handover_dict)
+ log.debug("handover is new, creating it", handover=handover_dict)
+ handover.created_by = "Progran"
+
+ handover = ProgranHelpers.update_fields(handover, handover_dict)
+ handover.save()
+
+ # Assigning handover to profile
+ si.handover = handover
+
+ # si.backend_status = "OK"
+ # si.backend_code = 1
+
+ si.no_sync = True
+ si.previously_sync = True
+
+ if p["MMECfg"]:
+ si.mmeip = str(p["MMECfg"]["IPAddr"])
+ si.mmeport = str(p["MMECfg"]["Port"])
+
+ si.enacted = time.mktime(datetime.datetime.now().timetuple())
+
+ si.save()
+
+ updated_profiles.append(si.name)
+
+ existing_profiles = [p.name for p in ProgranServiceInstance.objects.all() if not p.is_new]
+ deleted_profiles = ProgranHelpers.list_diff(existing_profiles, updated_profiles)
+
+ if len(deleted_profiles) > 0:
+ for p in deleted_profiles:
+ si = ProgranServiceInstance.objects.get(name=p)
+ if si.created_by == 'XOS' and si.previously_sync == False:
+ # don't delete if the profile has been created by XOS and it hasn't been sync'ed yet
+ continue
+ # TODO delete also the associated Handover
+ log.debug("Profiles %s have been removed in progran, removing it from XOS" % str(p))
+ si.delete()
\ No newline at end of file