[CORD-3094] Waiting for all parameters before configure the fabric to strip vlans

Change-Id: I5743c7d9dfd038ef494ccc79c1194f75af282624
diff --git a/xos/synchronizer/steps/sync_vsg_hw_service_instance.py b/xos/synchronizer/steps/sync_vsg_hw_service_instance.py
index c437610..05b16cb 100644
--- a/xos/synchronizer/steps/sync_vsg_hw_service_instance.py
+++ b/xos/synchronizer/steps/sync_vsg_hw_service_instance.py
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from synchronizers.new_base.SyncInstanceUsingAnsible import SyncStep
+from synchronizers.new_base.syncstep import SyncStep, DeferredException
 from synchronizers.new_base.modelaccessor import model_accessor, VSGHWServiceInstance, ServiceInstance
 
 from xosconfig import Config
@@ -20,10 +20,10 @@
 import requests
 from requests.auth import HTTPBasicAuth
 
-log = create_logger(Config().get('logging'))
 
 class SyncVSGHWServiceInstance(SyncStep):
     provides = [VSGHWServiceInstance]
+    log = create_logger(Config().get('logging'))
 
     observes = VSGHWServiceInstance
 
@@ -55,7 +55,7 @@
         }
 
     def sync_record(self, o):
-        log.info("Sync'ing VSG-HW Service Instance", service_instance=o)
+        self.log.info("Sync'ing VSG-HW Service Instance", service_instance=o)
 
 
         onos = SyncVSGHWServiceInstance.get_fabric_onos_info(o)
@@ -63,12 +63,28 @@
         si = ServiceInstance.objects.get(id=o.id)
 
         mac_address = si.get_westbound_service_instance_properties("mac_address")
+        ip = si.get_westbound_service_instance_properties("ip_address")
         s_tag = si.get_westbound_service_instance_properties("s_tag")
         c_tag = si.get_westbound_service_instance_properties("c_tag")
-        ip = si.get_westbound_service_instance_properties("ip_address")
         dpid = si.get_westbound_service_instance_properties("switch_datapath_id")
         port = si.get_westbound_service_instance_properties("switch_port")
 
+        try:
+            if not mac_address:
+                raise ValueError("mac_address")
+            if not ip:
+                raise ValueError("ip_address")
+            if not s_tag:
+                raise ValueError("s_tag")
+            if not c_tag:
+                raise ValueError("c_tag")
+            if not dpid:
+                raise ValueError("switch_datapath_id")
+            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))
+
         data = {
             'hosts': {
                 mac_address + "/" + str(s_tag): {
@@ -88,15 +104,15 @@
 
         url = onos['url'] + '/onos/v1/network/configuration'
 
-        log.info("Sending requests to ONOS", url=url, body=data)
+        self.log.info("Sending requests to ONOS", url=url, body=data)
 
         r = requests.post(url, json=data, auth=HTTPBasicAuth(onos['user'], onos['pass']))
 
         if r.status_code != 200:
             raise Exception("Failed to terminate subscriber in ONOS: %s" % r.text)
 
-        log.info("ONOS response", res=r.text)
+        self.log.info("ONOS response", res=r.text)
 
     def delete_record(self, o):
-        log.info("Deleting VSG-HW Service Instance", service_instance=o)
+        self.log.info("Deleting VSG-HW Service Instance", service_instance=o)
         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 548e8ab..680fc86 100644
--- a/xos/synchronizer/steps/test_sync_vsg_hw_service_instance.py
+++ b/xos/synchronizer/steps/test_sync_vsg_hw_service_instance.py
@@ -17,6 +17,8 @@
 import functools
 from mock import patch, call, Mock, PropertyMock
 import requests_mock
+import multistructlog
+from multistructlog import create_logger
 
 import os, sys
 
@@ -71,7 +73,7 @@
         build_mock_modelaccessor(xos_dir, services_dir, [get_models_fn("vsg-hw", "vsg-hw.xproto")])
         import synchronizers.new_base.modelaccessor
 
-        from sync_vsg_hw_service_instance import SyncVSGHWServiceInstance, model_accessor
+        from sync_vsg_hw_service_instance import SyncVSGHWServiceInstance, model_accessor, DeferredException
 
         # import all class names to globals
         for (k, v) in model_accessor.all_model_classes.items():
@@ -79,6 +81,7 @@
 
 
         self.sync_step = SyncVSGHWServiceInstance
+        self.sync_step.log = Mock()
 
 
         # mock onos-fabric
@@ -117,6 +120,31 @@
         sys.path = self.sys_path_save
 
     @requests_mock.Mocker()
+    def test_hold_sync(self, m):
+        """
+        If we don't have all the data we need, wait to synchronize
+        """
+
+        for i in ["mac_address", "ip_address", "s_tag", "c_tag", "switch_datapath_id", "switch_port"]:
+
+            def wb_si_prop(prop):
+                # fake prop not present
+                if prop != i:
+                    return prop
+                return ""
+
+            self.si.get_westbound_service_instance_properties = wb_si_prop
+
+            with patch.object(ServiceInstance.objects, "get") as service_instance_mock:
+                service_instance_mock.return_value = self.si
+
+                with self.assertRaises(DeferredException) 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.assertFalse(m.called)
+
+    @requests_mock.Mocker()
     def test_sync_success(self, m):
         expected_conf = {
             'hosts': {