[CORD-3168] Removing subscriber termination when the subscriber status change

Change-Id: I3b4494539d12f577e7d093cce01317e759e6a40c
diff --git a/.gitignore b/.gitignore
index 1163cb2..9a8876a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
 .idea
-*.pyc
\ No newline at end of file
+*.pyc
+.coverage
+xos/htmlcov
\ No newline at end of file
diff --git a/xos/synchronizer/steps/sync_vsg_hw_service_instance.py b/xos/synchronizer/steps/sync_vsg_hw_service_instance.py
index 05b16cb..6f79ca2 100644
--- a/xos/synchronizer/steps/sync_vsg_hw_service_instance.py
+++ b/xos/synchronizer/steps/sync_vsg_hw_service_instance.py
@@ -17,6 +17,7 @@
 
 from xosconfig import Config
 from multistructlog import create_logger
+import urllib
 import requests
 from requests.auth import HTTPBasicAuth
 
@@ -83,7 +84,15 @@
             if not port:
                 raise ValueError("switch_port")
         except ValueError as e:
-            raise DeferredException("Skipping synchronization for VSG-HW Service Instance with id %s as %s is not available" % (o.id, e.message))
+            raise Exception("Skipping synchronization for VSG-HW Service Instance with id %s as westbound value %s is not available" % (o.id, e.message))
+
+        subscriber_status = si.get_westbound_service_instance_properties("status")
+
+        if subscriber_status != "enabled":
+            if o.enacted:
+                return self.delete_record(o)
+            else:
+                raise DeferredException("Deferring synchronization for VSG-HW Service Instance with id %s as subscriber is not enabled" % o.id)
 
         data = {
             'hosts': {
@@ -115,4 +124,23 @@
 
     def delete_record(self, o):
         self.log.info("Deleting VSG-HW Service Instance", service_instance=o)
+        if o.enacted:
+            onos = SyncVSGHWServiceInstance.get_fabric_onos_info(o)
+
+            si = ServiceInstance.objects.get(id=o.id)
+
+            mac_address = si.get_westbound_service_instance_properties("mac_address")
+            s_tag = si.get_westbound_service_instance_properties("s_tag")
+
+            key = "%s/%s" % (mac_address, str(s_tag))
+            key = urllib.quote(key, safe='')
+
+            url = onos['url'] + '/onos/v1/network/configuration/hosts/%s' % key
+
+            r = requests.delete(url, auth=HTTPBasicAuth(onos['user'], onos['pass']))
+
+            if r.status_code != 200:
+                raise Exception("Failed to remove subscriber termination in ONOS: %s" % r.text)
+
+            self.log.info("ONOS response", res=r.text)
         pass
\ No newline at end of file
diff --git a/xos/synchronizer/steps/test_sync_vsg_hw_service_instance.py b/xos/synchronizer/steps/test_sync_vsg_hw_service_instance.py
index 680fc86..b1bddf4 100644
--- a/xos/synchronizer/steps/test_sync_vsg_hw_service_instance.py
+++ b/xos/synchronizer/steps/test_sync_vsg_hw_service_instance.py
@@ -45,6 +45,8 @@
 # END generate model from xproto
 
 def mock_get_westbound_service_instance_properties(prop):
+    if prop == "status":
+        return "enabled"
     return prop
 
 def match_json(desired, req):
@@ -120,9 +122,9 @@
         sys.path = self.sys_path_save
 
     @requests_mock.Mocker()
-    def test_hold_sync(self, m):
+    def test_fail_sync(self, m):
         """
-        If we don't have all the data we need, wait to synchronize
+        If we don't have all the data we need, do not synchronize
         """
 
         for i in ["mac_address", "ip_address", "s_tag", "c_tag", "switch_datapath_id", "switch_port"]:
@@ -138,13 +140,34 @@
             with patch.object(ServiceInstance.objects, "get") as service_instance_mock:
                 service_instance_mock.return_value = self.si
 
-                with self.assertRaises(DeferredException) as e:
+                with self.assertRaises(Exception) as e:
                     self.sync_step().sync_record(self.o)
 
-                self.assertEqual(e.exception.message, "Skipping synchronization for VSG-HW Service Instance with id 1 as %s is not available" % i)
+                self.assertEqual(e.exception.message, "Skipping synchronization for VSG-HW Service Instance with id 1 as westbound value %s is not available" % i)
                 self.assertFalse(m.called)
 
     @requests_mock.Mocker()
+    def test_hold_sync(self, m):
+        with patch.object(ServiceInstance.objects, "get") as service_instance_mock:
+            service_instance_mock.return_value = self.si
+
+            def wb_si_prop(prop):
+                # fake prop not present
+                if prop == "status":
+                    return "suspended"
+                return prop
+
+            self.si.get_westbound_service_instance_properties = wb_si_prop
+
+            self.o.enacted = None
+
+            with self.assertRaises(DeferredException) as e:
+                self.sync_step().sync_record(self.o)
+
+            self.assertEqual(e.exception.message, "Deferring synchronization for VSG-HW Service Instance with id 1 as subscriber is not enabled")
+            self.assertFalse(m.called)
+
+    @requests_mock.Mocker()
     def test_sync_success(self, m):
         expected_conf = {
             'hosts': {
@@ -166,6 +189,8 @@
         def wb_si_prop(prop):
             if prop == "outer_tpid":
                 return None
+            if prop == "status":
+                return "enabled"
             return prop
 
         self.si.get_westbound_service_instance_properties = wb_si_prop
@@ -201,4 +226,42 @@
 
             self.sync_step().sync_record(self.o)
 
+            self.assertTrue(m.called)
+
+    @requests_mock.Mocker()
+    def test_delete(self, m):
+        self.o.enacted = True
+        m.delete("http://onos-fabric:8181/onos/v1/network/configuration/hosts/mac_address%2Fs_tag",
+               status_code=200)
+
+        with patch.object(ServiceInstance.objects, "get") as service_instance_mock:
+            service_instance_mock.return_value = self.si
+
+            self.sync_step().delete_record(self.o)
+
+            self.assertTrue(m.called)
+
+    @requests_mock.Mocker()
+    def test_disable(self, m):
+
+        # if a subscriber was enabled and now is suspended, remove subscriber termination
+
+        m.delete("http://onos-fabric:8181/onos/v1/network/configuration/hosts/mac_address%2Fs_tag",
+                 status_code=200)
+
+        with patch.object(ServiceInstance.objects, "get") as service_instance_mock:
+            service_instance_mock.return_value = self.si
+
+            def wb_si_prop(prop):
+                # fake prop not present
+                if prop == "status":
+                    return "suspended"
+                return prop
+
+            self.si.get_westbound_service_instance_properties = wb_si_prop
+
+            self.o.enacted = True
+
+            self.sync_step().sync_record(self.o)
+
             self.assertTrue(m.called)
\ No newline at end of file
diff --git a/xos/unittest.cfg b/xos/unittest.cfg
index 71be7ca..9679a47 100644
--- a/xos/unittest.cfg
+++ b/xos/unittest.cfg
@@ -3,3 +3,9 @@
 code-directories=synchronizer
                  model_policies
                  steps
+
+[coverage]
+always-on = True
+coverage = synchronizer
+coverage-report = term
+coverage-report = html
\ No newline at end of file