[CORD-2961] Removing AddressManager syncstep from Fabric Service
Change-Id: Icf5ba5be0c2d94d8c3020253a64ca682b1644f60
diff --git a/xos/synchronizer/steps/.gitignore b/xos/synchronizer/steps/.gitignore
new file mode 100644
index 0000000..c96a04f
--- /dev/null
+++ b/xos/synchronizer/steps/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/xos/synchronizer/steps/sync_addressmanagerserviceinstance.py b/xos/synchronizer/steps/sync_addressmanagerserviceinstance.py
deleted file mode 100644
index 8c15676..0000000
--- a/xos/synchronizer/steps/sync_addressmanagerserviceinstance.py
+++ /dev/null
@@ -1,185 +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 requests
-from synchronizers.new_base.syncstep import SyncStep, DeferredException
-from synchronizers.new_base.modelaccessor import *
-
-from xosconfig import Config
-from multistructlog import create_logger
-
-log = create_logger(Config().get('logging'))
-
-DATAPLANE_IP = "dataPlaneIp"
-PREFIX = "prefix"
-NEXT_HOP = "nextHop"
-
-class SyncAddressManagerServiceInstance(SyncStep):
- provides=[AddressManagerServiceInstance]
- observes = AddressManagerServiceInstance
- requested_interval=30
-
- def get_fabric_onos_service_internal(self):
- # There will be a ServiceInstanceLink from the FabricService to the Fabric ONOS App
- fs = FabricService.objects.first()
- for link in fs.subscribed_links.all():
- if link.provider_service_instance:
- # cast from ServiceInstance to ONOSApp
- service_instance = link.provider_service_instance.leaf_model
- # cast from Service to ONOSService
- return service_instance.owner.leaf_model
-
- return None
-
- def get_fabric_onos_service(self):
- fos = self.get_fabric_onos_service_internal()
- if not fos:
- raise Exception("Fabric ONOS service not found")
- return fos
-
- def get_node_tag(self, node, tagname):
- tags = Tag.objects.filter(content_type=model_accessor.get_content_type_id(node),
- object_id=node.id,
- name=tagname)
- if tags:
- return tags[0].value
- else:
- return None
-
- def fetch_pending(self, deleted):
- # If fetch_pending is being called for delete, then just execute the standard delete logic.
- if deleted:
- return super(SyncAddressManagerServiceInstance, self).fetch_pending(deleted)
-
- fs = FabricService.objects.first()
- if (not fs) or (not fs.autoconfig):
- log.info("Not FabricServer or not autoconfig. Returning []");
- return []
-
- objs = super(SyncAddressManagerServiceInstance, self).fetch_pending(deleted)
- objs = list(objs)
-
- # Check that each is a valid VSG tenant or instance
- for address_si in objs[:]:
- sub = self.get_subscriber(address_si)
- if sub:
- # TODO: This check is making assumptions about the subscriber service. Consider breaking hardcoded
- # dependency.
- if (not hasattr(sub, "instance")) or (not sub.instance):
- log.info("Skipping %s because it has no instance" % address_si)
- objs.remove(address_si)
- else:
- # Maybe the Address is for an instance
- # TODO: tenant_for_instance_id needs to be a real database field
- instance_id = address_si.get_attribute("tenant_for_instance_id")
- if not instance_id:
- log.info("Skipping %s because it has no tenant_for_instance_id" % address_si)
- objs.remove(address_si)
- else:
- instances = Instance.objects.filter(id=instance_id)
- if not instances:
- log.error("Skipping %s because it appears to be linked to a dead instance" % address_si)
- objs.remove(address_si)
- elif not instances[0].instance_name:
- log.info("Skipping %s because it has no instance.instance_name" % address_si)
- objs.remove(address_si)
-
- return objs
-
- def get_subscriber(self, address_si):
- links = address_si.provided_links.all()
- for link in links:
- if not link.subscriber_service_instance:
- continue
- # cast from ServiceInstance to VSGTEnant or similar
- sub = link.subscriber_service_instance.leaf_model
- # TODO: check here to make sure it's an appropriate type of ServiceInstance ?
- return sub
- return None
-
- def get_routes_url(self, fos):
- url = 'http://%s:%s/onos/routeservice/routes' % (fos.rest_hostname, fos.rest_port)
-
- log.info("url: %s" % url)
- return url
-
- def sync_record(self, address_si):
- fos = self.get_fabric_onos_service()
-
- data = self.map_tenant_to_route(address_si)
- if not data:
- # Raise an exception so the synchronizer does not mark this record as synced
- raise Exception("map_tenant_to_route returned no data for %s" % address_si)
-
- r = self.post_route(fos, data)
-
- log.info("Posted %s: status: %s result '%s'" % (address_si, r.status_code, r.text))
-
- def delete_record(self, address_si):
- pass
- # Disabled for now due to lack of feedback state field
- # self.delete_route(self.get_fabric_onos_service(), self.map_tenant_to_route(address_si))
-
-
- def map_tenant_to_route(self, address_si):
- instance = None
- # Address setup is kind of hacky right now, we'll
- # need to revisit. The idea is:
- # * Look up the instance corresponding to the address
- # * Look up the node running the instance
- # * Get the "dataPlaneIp" tag, push to the fabric
-
- sub = self.get_subscriber(address_si)
- if sub:
- # TODO: This check is making assumptions about the subscriber service. Consider breaking hardcoded
- # dependency.
- if hasattr(sub, "instance"):
- instance = sub.instance
- else:
- instance_id = address_si.get_attribute("tenant_for_instance_id")
- instances = Instance.objects.filter(id=instance_id)
- if instances:
- instance = instances[0]
-
- if not instance:
- return None
-
- node = instance.node
- dataPlaneIp = node.dataPlaneIp
-
- if not dataPlaneIp:
- raise DeferredException("No IP found for node %s tenant %s -- skipping" % (str(node), str(address_si)))
-
- data = {
- PREFIX : "%s/32" % address_si.public_ip,
- NEXT_HOP : dataPlaneIp.split('/')[0]
- }
-
- return data
-
- def delete_route(self, fos, route):
- url = self.get_routes_url(fos)
-
- r = requests.delete(url, json=route, auth=(fos.rest_username, fos.rest_password))
-
- log.info("status: %s" % r.status_code)
- log.info('result: %s' % r.text)
-
- return r
-
- def post_route(self, fos, route):
- url = self.get_routes_url(fos)
- return requests.post(url, json=route, auth=(fos.rest_username, fos.rest_password))
-
diff --git a/xos/synchronizer/steps/sync_host.yaml b/xos/synchronizer/steps/sync_host.yaml
deleted file mode 100644
index 0ca1639..0000000
--- a/xos/synchronizer/steps/sync_host.yaml
+++ /dev/null
@@ -1,29 +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.
-
-
----
-- hosts: 127.0.0.1
- connection: local
-
- tasks:
- - name: Add host entry for fabric
- uri:
- url: http://{{ rest_hostname }}:{{ rest_port }}/{{ rest_endpoint }}
- method: POST
- user: onos
- password: rocks
- body: '{{ rest_body }}'
- body_format: json
\ No newline at end of file
diff --git a/xos/synchronizer/steps/test_config.yaml b/xos/synchronizer/steps/test_config.yaml
deleted file mode 100644
index 270d0a9..0000000
--- a/xos/synchronizer/steps/test_config.yaml
+++ /dev/null
@@ -1,30 +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.
-
-
-name: test-model-policies
-accessor:
- username: xosadmin@opencord.org
- password: "sample"
- kind: "testframework"
-logging:
- version: 1
- handlers:
- console:
- class: logging.StreamHandler
- loggers:
- 'multistructlog':
- handlers:
- - console
diff --git a/xos/synchronizer/steps/test_sync_addressmanagerserviceinstance.py b/xos/synchronizer/steps/test_sync_addressmanagerserviceinstance.py
deleted file mode 100644
index fa6a073..0000000
--- a/xos/synchronizer/steps/test_sync_addressmanagerserviceinstance.py
+++ /dev/null
@@ -1,304 +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 functools
-import unittest
-from mock import patch, call, Mock, PropertyMock
-import requests_mock
-
-import os, sys
-
-# Hack to load synchronizer framework
-test_path=os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
-xos_dir=os.path.join(test_path, "../../..")
-if not os.path.exists(os.path.join(test_path, "new_base")):
- xos_dir=os.path.join(test_path, "../../../../../../orchestration/xos/xos")
- services_dir = os.path.join(xos_dir, "../../xos_services")
-# END Hack to load synchronizer framework
-
-def match_json(desired, req):
- if desired!=req.json():
- print >> sys.stderr, "mismatch: '%s' != '%s'" % (desired, req.json())
- return False
- return True
-
-# generate model from xproto
-def get_models_fn(service_name, xproto_name):
- name = os.path.join(service_name, "xos", xproto_name)
- if os.path.exists(os.path.join(services_dir, name)):
- return name
- else:
- name = os.path.join(service_name, "xos", "synchronizer", "models", xproto_name)
- if os.path.exists(os.path.join(services_dir, name)):
- return name
- raise Exception("Unable to find service=%s xproto=%s" % (service_name, xproto_name))
-# END generate model from xproto
-
-class TestSyncAddressManagerServiceInstance(unittest.TestCase):
-
- def setUp(self):
- global MockObjectList, model_accessor, SyncStep
-
- self.sys_path_save = sys.path
- sys.path.append(xos_dir)
- sys.path.append(os.path.join(xos_dir, 'synchronizers', 'new_base'))
-
- # Setting up the config module
- from xosconfig import Config
- config = os.path.join(test_path, "test_config.yaml")
- Config.clear()
- Config.init(config, "synchronizer-config-schema.yaml")
- # END Setting up the config module
-
- from synchronizers.new_base.mock_modelaccessor_build import build_mock_modelaccessor
- build_mock_modelaccessor(xos_dir, services_dir, [get_models_fn("fabric", "fabric.xproto"),
- get_models_fn("addressmanager", "addressmanager.xproto"),
- get_models_fn("onos-service", "onos.xproto")])
- import synchronizers.new_base.modelaccessor
- from synchronizers.new_base.syncstep import SyncStep
- from sync_addressmanagerserviceinstance import SyncAddressManagerServiceInstance, model_accessor
-
- from mock_modelaccessor import MockObjectList
-
- self.sync_step = SyncAddressManagerServiceInstance()
-
- # import all class names to globals
- for (k, v) in model_accessor.all_model_classes.items():
- globals()[k] = v
-
- # Some of the functions we call have side-effects. For example, creating a VSGServiceInstance may lead to creation of
- # tags. Ideally, this wouldn't happen, but it does. So make sure we reset the world.
- model_accessor.reset_all_object_stores()
-
- # TODO: this should be addressed in the mock model accessor
- model_accessor.get_content_type_id = lambda x: x.self_content_type_id
-
- AddressManagerServiceInstance.get_attribute = None
-
- self.service = FabricService()
- self.onos_service = ONOSService(rest_hostname = "fabric_host", rest_port=1234)
- self.onos_app = ONOSApp(owner = self.onos_service)
-
- self.onos_dependency = ServiceDependency(subscriber_service = self.service,
- provider_service_instance = self.onos_app)
- self.onos_service.provideded_links = MockObjectList(initial = [self.onos_dependency])
- self.service.subscribed_links = MockObjectList(initial = [self.onos_dependency])
-
- self.amsi_service_instance = AddressManagerServiceInstance(public_ip = "1.2.3.4",
- public_mac="11:22:33:44:55:66",
- provided_links = MockObjectList())
- self.amsi_inst = AddressManagerServiceInstance(public_ip = "5.6.7.8",
- public_mac="55:66:77:88:99:00",
- provided_links = MockObjectList())
-
- def tearDown(self):
- sys.path = self.sys_path_save
-
- def test_get_fabric_onos_service_internal(self):
- with patch.object(FabricService.objects, "get_items") as fabricservice_objects:
- fabricservice_objects.return_value =[self.service]
-
- osi = self.sync_step.get_fabric_onos_service_internal()
- self.assertEqual(osi, self.onos_service)
-
- def test_get_fabric_onos_service_internal_nolinks(self):
- with patch.object(FabricService.objects, "get_items") as fabricservice_objects:
- fabricservice_objects.return_value =[self.service]
-
- self.service.subscribed_links = MockObjectList(initial=[])
-
- osi = self.sync_step.get_fabric_onos_service_internal()
- self.assertEqual(osi, None)
-
- def test_get_fabric_onos_service(self):
- with patch.object(FabricService.objects, "get_items") as fabricservice_objects:
- fabricservice_objects.return_value =[self.service]
-
- osi = self.sync_step.get_fabric_onos_service()
- self.assertEqual(osi, self.onos_service)
-
- def test_get_fabric_onos_service_nolinks(self):
- with patch.object(FabricService.objects, "get_items") as fabricservice_objects:
- fabricservice_objects.return_value =[self.service]
-
- self.service.subscribed_links = MockObjectList(initial=[])
-
- with self.assertRaises(Exception) as e:
- osi = self.sync_step.get_fabric_onos_service()
-
- self.assertEqual(e.exception.message, "Fabric ONOS service not found")
-
- def test_get_node_tag(self):
- with patch.object(Tag.objects, "get_items") as tag_objects:
- node = Node(id=6745)
- tag = Tag(content_type = model_accessor.get_content_type_id(node),
- object_id = node.id,
- name="foo",
- value="bar")
- tag_objects.return_value = [tag]
-
- self.assertEqual(self.sync_step.get_node_tag(node, "foo"), "bar")
-
- def test_fetch_pending(self):
- with patch.object(FabricService.objects, "get_items") as fabricservice_objects, \
- patch.object(AddressManagerServiceInstance, "get_attribute") as get_attribute, \
- patch.object(Instance.objects, "get_items") as instance_objects, \
- patch.object(SyncStep, "fetch_pending") as syncstep_fetch_pending:
- fabricservice_objects.return_value =[self.service]
-
- node = Node(dataPlaneIp = "11.22.33.44")
- instance1 = Instance(id=3445, node=node, instance_name="instance1")
- instance2 = Instance(id=3446, node=node, instance_name="instance2")
- instance_objects.return_value = [instance1, instance2]
-
- # for self.amsi_inst...
- get_attribute.return_value = instance1.id
-
- # for self.amsi_service_instance...
- some_service_instance = ServiceInstance(instance=instance2)
- some_link = ServiceInstanceLink(subscriber_service_instance=some_service_instance, provider_service_instance=self.amsi_service_instance)
- some_service_instance.subscribed_links = MockObjectList(initial=[some_link])
- self.amsi_service_instance.provided_links = MockObjectList(initial=[some_link])
-
- syncstep_fetch_pending.return_value = [self.amsi_inst, self.amsi_service_instance]
-
- objs = self.sync_step.fetch_pending(deleted = False)
- self.assertEqual(len(objs), 2)
-
- def test_fetch_pending_no_attribute(self):
- with patch.object(FabricService.objects, "get_items") as fabricservice_objects, \
- patch.object(AddressManagerServiceInstance, "get_attribute") as get_attribute, \
- patch.object(Instance.objects, "get_items") as instance_objects, \
- patch.object(SyncStep, "fetch_pending") as syncstep_fetch_pending:
- fabricservice_objects.return_value = [self.service]
- syncstep_fetch_pending.return_value = [self.amsi_inst, self.amsi_service_instance]
-
- node = Node(dataPlaneIp="11.22.33.44")
- instance2 = Instance(id=3446, node=node, instance_name="instance1")
- instance_objects.return_value = [instance2]
-
- # for self.amsi_inst, see that it has no instance
- get_attribute.return_value = None
-
- # for self.amsi_service_instance...
- some_service_instance = ServiceInstance(instance=instance2)
- some_link = ServiceInstanceLink(subscriber_service_instance=some_service_instance,
- provider_service_instance=self.amsi_service_instance)
- some_service_instance.subscribed_links = MockObjectList(initial=[some_link])
- self.amsi_service_instance.provided_links = MockObjectList(initial=[some_link])
-
- objs = self.sync_step.fetch_pending(deleted=False)
-
- self.assertEqual(len(objs), 1)
-
- def test_fetch_pending_no_subscriber_instance(self):
- with patch.object(FabricService.objects, "get_items") as fabricservice_objects, \
- patch.object(AddressManagerServiceInstance, "get_attribute") as get_attribute, \
- patch.object(Instance.objects, "get_items") as instance_objects, \
- patch.object(SyncStep, "fetch_pending") as syncstep_fetch_pending:
- fabricservice_objects.return_value =[self.service]
-
- node = Node(dataPlaneIp = "11.22.33.44")
- instance1 = Instance(id=3445, node=node, instance_name="instance1")
- instance_objects.return_value = [instance1]
-
- # for self.amsi_inst...
- get_attribute.return_value = instance1.id
-
- # for self.amsi_service_instance...
- some_service_instance = ServiceInstance(instance=None)
- some_link = ServiceInstanceLink(subscriber_service_instance=some_service_instance, provider_service_instance=self.amsi_service_instance)
- some_service_instance.subscribed_links = MockObjectList(initial=[some_link])
- self.amsi_service_instance.provided_links = MockObjectList(initial=[some_link])
-
- syncstep_fetch_pending.return_value = [self.amsi_inst, self.amsi_service_instance]
-
- objs = self.sync_step.fetch_pending(deleted = False)
- self.assertEqual(len(objs), 1)
-
- @requests_mock.Mocker()
- def test_sync_record_instance(self, m):
- with patch.object(FabricService.objects, "get_items") as fabricservice_objects, \
- patch.object(AddressManagerServiceInstance, "get_attribute") as get_attribute, \
- patch.object(Instance.objects, "get_items") as instance_objects:
- fabricservice_objects.return_value = [self.service]
-
- node = Node(dataPlaneIp = "11.22.33.44")
- instance = Instance(id=3445, node=node)
- instance_objects.return_value = [instance]
-
- get_attribute.return_value = instance.id
-
- m.post("http://fabric_host:1234/onos/routeservice/routes",
- status_code=200,
- additional_matcher=functools.partial(match_json,{u'prefix': u'5.6.7.8/32', u'nextHop': u'11.22.33.44'}))
-
- self.sync_step.sync_record(self.amsi_inst)
-
- @requests_mock.Mocker()
- def test_sync_record_service_instance(self, m):
- with patch.object(FabricService.objects, "get_items") as fabricservice_objects, \
- patch.object(Instance.objects, "get_items") as instance_objects:
- fabricservice_objects.return_value = [self.service]
-
- node = Node(dataPlaneIp = "55.66.77.88")
- instance = Instance(id=5443, node=node)
- instance_objects.return_value = [instance]
-
- some_service_instance = ServiceInstance(instance=instance)
- some_link = ServiceInstanceLink(subscriber_service_instance=some_service_instance, provider_service_instance=self.amsi_service_instance)
- some_service_instance.subscribed_links = MockObjectList(initial=[some_link])
- self.amsi_service_instance.provided_links = MockObjectList(initial=[some_link])
-
- m.post("http://fabric_host:1234/onos/routeservice/routes",
- status_code=200,
- additional_matcher=functools.partial(match_json,{u'prefix': u'1.2.3.4/32', u'nextHop': u'55.66.77.88'}))
-
- self.sync_step.sync_record(self.amsi_service_instance)
-
- def test_get_subscriber(self):
- some_service_instance = ServiceInstance()
- some_link = ServiceInstanceLink(subscriber_service_instance=some_service_instance,
- provider_service_instance=self.amsi_service_instance)
- some_service_instance.subscribed_links = MockObjectList(initial=[some_link])
- self.amsi_service_instance.provided_links = MockObjectList(initial=[some_link])
-
- self.assertEqual(self.sync_step.get_subscriber(self.amsi_service_instance), some_service_instance)
-
- def test_get_routes_url(self):
- url = self.sync_step.get_routes_url(self.onos_service)
- self.assertEqual(url, "http://fabric_host:1234/onos/routeservice/routes")
-
- @requests_mock.Mocker()
- def test_delete_route(self, m):
- m.delete("http://fabric_host:1234/onos/routeservice/routes",
- status_code=200,
- additional_matcher=functools.partial(match_json,{u'prefix': u'5.6.7.8/32', u'nextHop': u'55.66.77.88'}))
-
- route = {u'prefix': u'5.6.7.8/32', u'nextHop': u'55.66.77.88'}
-
- self.sync_step.delete_route(self.onos_service, route)
-
- @requests_mock.Mocker()
- def test_post_route(self, m):
- m.post("http://fabric_host:1234/onos/routeservice/routes",
- status_code=200,
- additional_matcher=functools.partial(match_json,{u'prefix': u'5.6.7.8/32', u'nextHop': u'55.66.77.88'}))
-
- route = {u'prefix': u'5.6.7.8/32', u'nextHop': u'55.66.77.88'}
-
- self.sync_step.post_route(self.onos_service, route)
-
-if __name__ == "__main__":
- unittest.main()
\ No newline at end of file