[CORD-2962] Refactoring vrouter and adding support for static routes

Change-Id: Ie2719ca94296559caee4a1e433631cbd43019bf9
diff --git a/xos/synchronizer/steps/helpers.py b/xos/synchronizer/steps/helpers.py
new file mode 100644
index 0000000..63585aa
--- /dev/null
+++ b/xos/synchronizer/steps/helpers.py
@@ -0,0 +1,30 @@
+# 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.
+
+class Helpers():
+    @staticmethod
+    def format_url(url):
+        if 'http' in url:
+            return url
+        else:
+            return 'http://%s' % url
+
+    @staticmethod
+    def get_onos_info(onos_service):
+        return {
+            'url': Helpers.format_url(onos_service.rest_hostname),
+            'port': onos_service.rest_port,
+            'user': onos_service.rest_username,
+            'pass': onos_service.rest_password
+        }
diff --git a/xos/synchronizer/steps/sync_routes.py b/xos/synchronizer/steps/sync_routes.py
new file mode 100644
index 0000000..5086933
--- /dev/null
+++ b/xos/synchronizer/steps/sync_routes.py
@@ -0,0 +1,83 @@
+
+# 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 requests
+from requests.auth import HTTPBasicAuth
+from synchronizers.new_base.syncstep import SyncStep, DeferredException
+from synchronizers.new_base.modelaccessor import VRouterStaticRoute
+
+from helpers import Helpers
+from multistructlog import create_logger
+from xosconfig import Config
+
+log = create_logger(Config().get('logging'))
+
+class SyncRoutes(SyncStep):
+    provides = [VRouterStaticRoute]
+    observes = VRouterStaticRoute
+
+    # Get fabric service info
+    def get_onos_fabric_service(self, model):
+        vrouter_service = model.vrouter.owner
+        fabric_service = vrouter_service.subscriber_services[0]
+        onos_fabric_service = fabric_service.subscriber_services[0]
+
+        return onos_fabric_service
+
+    def sync_record(self, model):
+        onos_fabric_service = self.get_onos_fabric_service(model)
+
+        onos = Helpers.get_onos_info(onos_fabric_service.leaf_model)
+        onos_basic_auth = HTTPBasicAuth(onos['user'], onos['pass'])
+
+        data = {
+          "prefix": model.prefix,
+          "nextHop": model.next_hop
+        }
+
+        url = '%s:%s/onos/routeservice/routes' % (onos['url'], onos['port'])
+        request = requests.post(url, json=data, auth=onos_basic_auth)
+
+        if request.status_code != 204:
+            log.error("Request failed", response=request.text)
+            raise Exception("Failed to add static route %s via %s in ONOS" % (model.prefix, model.next_hop))
+        else:
+            try:
+                print request.json()
+            except Exception:
+                print request.text
+
+    def delete_record(self, model):
+        onos_fabric_service = self.get_onos_fabric_service(model)
+
+        onos = Helpers.get_onos_info(onos_fabric_service.leaf_model)
+        onos_basic_auth = HTTPBasicAuth(onos['user'], onos['pass'])
+
+        data = {
+          "prefix": model.prefix,
+          "nextHop": model.next_hop
+        }
+
+        url = '%s:%s/onos/routeservice/routes' % (onos['url'], onos['port'])
+        request = requests.delete(url, json=data, auth=onos_basic_auth)
+
+        if request.status_code != 204:
+            log.error("Request failed", response=request.text)
+            raise Exception("Failed to delete static route %s via %s in ONOS" % (model.prefix, model.next_hop))
+        else:
+            try:
+                print request.json()
+            except Exception:
+                print request.text
diff --git a/xos/synchronizer/steps/sync_vrouterapp.py b/xos/synchronizer/steps/sync_vrouterapp.py
deleted file mode 100644
index 6c83700..0000000
--- a/xos/synchronizer/steps/sync_vrouterapp.py
+++ /dev/null
@@ -1,85 +0,0 @@
-
-# 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 requests
-import json
-from synchronizers.new_base.syncstep import SyncStep
-from synchronizers.new_base.modelaccessor import *
-from xos.logger import Logger, logging
-
-from requests.auth import HTTPBasicAuth
-logger = Logger(level=logging.INFO)
-
-
-class SyncVRouterApp(SyncStep):
-    provides = [VRouterApp]
-
-    observes = VRouterApp
-
-    requested_interval = 0
-
-    def __init__(self, *args, **kwargs):
-        super(SyncVRouterApp, self).__init__(*args, **kwargs)
-
-    def get_onos_fabric_addr(self, app):
-        vrouter_service = VRouterService.objects.get(id=app.vrouter_service_id)
-
-        return "http://%s:%s/onos/v1/network/configuration/" % (vrouter_service.rest_hostname, vrouter_service.rest_port)
-
-    def get_onos_fabric_auth(self, app):
-        vrouter_service = VRouterService.objects.get(id=app.vrouter_service_id)
-
-        return HTTPBasicAuth(vrouter_service.rest_user, vrouter_service.rest_pass)
-
-    def sync_record(self, app):
-
-        logger.info("Sync'ing Edited vRouterApps: %s" % app.name)
-
-        onos_addr = self.get_onos_fabric_addr(app)
-
-        data = {}
-        data["controlPlaneConnectPoint"] = app.control_plane_connect_point
-        data["ospfEnabled"] = app.ospf_enabled
-        data["interfaces"] = app.interfaces
-
-        url = onos_addr + "apps/" + app.name + "/router/"
-
-        print "POST %s for app %s" % (url, app.name)
-
-        # XXX fixme - hardcoded auth
-        auth = self.get_onos_fabric_auth(app)
-        r = requests.post(url, data=json.dumps(data), auth=auth)
-        if (r.status_code != 200):
-            print r
-            raise Exception("Received error from vrouter app update (%d)" % r.status_code)
-
-    def delete_record(self, app):
-
-        logger.info("Sync'ing Deleted vRouterApps: %s" % app.name)
-
-        onos_addr = self.get_onos_fabric_addr()
-
-        url = onos_addr + "apps/" + app.name + "/"
-
-        print "DELETE %s for app %s" % (url, app.name)
-
-        auth = self.get_onos_fabric_auth(app)
-        r = requests.delete(url, auth=auth)
-        if (r.status_code != 204):
-            print r
-            raise Exception("Received error from vrouter app deletion (%d)" % r.status_code)
\ No newline at end of file
diff --git a/xos/synchronizer/steps/sync_vrouterdevice.py b/xos/synchronizer/steps/sync_vrouterdevice.py
deleted file mode 100644
index 179ec91..0000000
--- a/xos/synchronizer/steps/sync_vrouterdevice.py
+++ /dev/null
@@ -1,82 +0,0 @@
-
-# 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 requests
-import json
-from synchronizers.new_base.syncstep import SyncStep
-from synchronizers.new_base.modelaccessor import *
-from xos.logger import Logger, logging
-
-from requests.auth import HTTPBasicAuth
-logger = Logger(level=logging.INFO)
-
-
-class SyncVRouterDevice(SyncStep):
-    provides = [VRouterDevice]
-
-    observes = VRouterDevice
-
-    requested_interval = 0
-
-    def __init__(self, *args, **kwargs):
-        super(SyncVRouterDevice, self).__init__(*args, **kwargs)
-
-    def get_onos_fabric_addr(self, app):
-        vrouter_service = VRouterService.objects.get(id=app.vrouter_service_id)
-
-        return "http://%s:%s/onos/v1/network/configuration/" % (vrouter_service.rest_hostname, vrouter_service.rest_port)
-
-    def get_onos_fabric_auth(self, app):
-        vrouter_service = VRouterService.objects.get(id=app.vrouter_service_id)
-
-        return HTTPBasicAuth(vrouter_service.rest_user, vrouter_service.rest_pass)
-
-    def sync_record(self, device):
-
-        logger.info("Sync'ing Edited vRouterDevice: %s" % device.name)
-
-        onos_addr = self.get_onos_fabric_addr(device)
-
-        data = {}
-        data["driver"] = device.driver
-
-        url = onos_addr + "devices/" + device.openflow_id + "/" + device.config_key + "/"
-
-        print "POST %s for device %s" % (url, device.name)
-
-        auth = self.get_onos_fabric_auth(device)
-        r = requests.post(url, data=json.dumps(data), auth=auth)
-        if (r.status_code != 200):
-            print r
-            raise Exception("Received error from vrouter device update (%d)" % r.status_code)
-
-    def delete_record(self, device):
-
-        logger.info("Sync'ing Deleted vRouterDevice: %s" % device.name)
-
-        onos_addr = self.get_onos_fabric_addr()
-
-        url = onos_addr + "devices/" + device.openflow_id + "/"
-
-        print "DELETE %s for device %s" % (url, device.name)
-
-        auth = self.get_onos_fabric_auth(device)
-        r = requests.delete(url, auth=auth)
-        if (r.status_code != 204):
-            print r
-            raise Exception("Received error from vrouter device deletion (%d)" % r.status_code)
\ No newline at end of file
diff --git a/xos/synchronizer/steps/sync_vrouterports.py b/xos/synchronizer/steps/sync_vrouterports.py
deleted file mode 100644
index fe8eb1c..0000000
--- a/xos/synchronizer/steps/sync_vrouterports.py
+++ /dev/null
@@ -1,105 +0,0 @@
-
-# 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 requests
-import json
-import urllib
-from synchronizers.new_base.syncstep import SyncStep
-from synchronizers.new_base.modelaccessor import *
-from xos.logger import Logger, logging
-
-from requests.auth import HTTPBasicAuth
-logger = Logger(level=logging.INFO)
-
-
-class SyncVRouterPort(SyncStep):
-    provides = [VRouterPort]
-
-    observes = VRouterPort
-
-    requested_interval = 0
-
-    def __init__(self, *args, **kwargs):
-        super(SyncVRouterPort, self).__init__(*args, **kwargs)
-
-    def get_onos_fabric_addr(self, app):
-        vrouter_service = VRouterService.objects.get(id=app.vrouter_service_id)
-
-        return "http://%s:%s/onos/v1/network/configuration/" % (vrouter_service.rest_hostname, vrouter_service.rest_port)
-
-    def get_onos_fabric_auth(self, app):
-        vrouter_service = VRouterService.objects.get(id=app.vrouter_service_id)
-
-        return HTTPBasicAuth(vrouter_service.rest_user, vrouter_service.rest_pass)
-
-    def sync_record(self, port):
-
-        logger.info("Sync'ing Edited vRouterPort: %s" % port.name)
-
-        # NOTE port is now related to service,
-        # probably it makes more sense to relate them to a device (and device is related to service)
-        onos_addr = self.get_onos_fabric_addr(port)
-
-        # NOTE
-        # from a port read all interfaces
-        # from interfaces read all ips
-
-        ifaces = []
-        for interface in port.interfaces.all():
-            iface = {
-                'name': interface.name,
-                'mac': interface.mac,
-                'vlan': interface.vlan,
-                'ips': []
-            }
-
-            for ip in interface.ips.all():
-                iface["ips"].append(ip.ip)
-
-            ifaces.append(iface)
-
-        data = {}
-        data[port.openflow_id] = {
-            'interfaces': ifaces
-        }
-
-        url = onos_addr + "ports/"
-
-        print "POST %s for port %s" % (url, port.name)
-
-        auth = self.get_onos_fabric_auth(port)
-        r = requests.post(url, data=json.dumps(data), auth=auth)
-        if (r.status_code != 200):
-            print r
-            raise Exception("Received error from vrouter port update (%d)" % r.status_code)
-
-    def delete_record(self, port):
-
-        logger.info("Sync'ing Deleted vRouterPort: %s" % port.name)
-
-        onos_addr = self.get_onos_fabric_addr()
-
-        url = onos_addr + "ports/" + urllib.quote(port.openflow_id, safe='') + "/"
-
-        print "DELETE %s for port %s" % (url, port.name)
-
-        auth = self.get_onos_fabric_auth(port)
-        r = requests.delete(url, auth=auth)
-        if (r.status_code != 204):
-            print r
-            raise Exception("Received error from vrouter port deletion (%d)" % r.status_code)
\ No newline at end of file