From 731ed8c5d4d2d230df109cd2e8cc3499933db373 Mon Sep 17 00:00:00 2001 From: JinLi Date: Tue, 5 Dec 2017 19:53:27 -0800 Subject: [PATCH] Auto generate backend for core plug_in Adds the logic to auto generate binding_urls and user this binding_url to retrieve ipaddress for port. Change-Id: I3c83ec3f23fae271c775c9b862bc9ba0c9b9e1ff --- gluon/backends/models/net_l3vpn.py | 77 +++++++++++++++++++++------- gluon/models/test/api.yaml | 9 +++- gluon/particleGenerator/generator.py | 22 ++++++++ 3 files changed, 87 insertions(+), 21 deletions(-) diff --git a/gluon/backends/models/net_l3vpn.py b/gluon/backends/models/net_l3vpn.py index 8f9f67b..8c6af69 100644 --- a/gluon/backends/models/net_l3vpn.py +++ b/gluon/backends/models/net_l3vpn.py @@ -13,10 +13,12 @@ # License for the specific language governing permissions and limitations # under the License. +import json from oslo_log import log as logging from gluon.backends import backend_base from gluon.common import exception as exc +from gluon.particleGenerator import generator LOG = logging.getLogger(__name__) @@ -26,39 +28,71 @@ logger = LOG class MyData(object): pass -DriverData = MyData() -DriverData.service = u'net-l3vpn' -DriverData.version = 'v1.0' -DriverData.proton_base = 'proton' -DriverData.ports_name = 'ports' -DriverData.binding_name = 'vpnbindings' + +def createDriverData(): + service_list = generator.get_service_list() + drivers = dict() + for service in service_list: + model = generator.load_model_for_service(service) + generator.verify_model(model) + driverData = MyData() + driverData.service = str(model['info']['name']) + driverData.version = 'v' + str(model['info']['version']) + driverData.proton_base = 'proton' + driverData.ports_name = 'ports' + driverData.binding_names = \ + generator.get_service_binding(driverData.service) + drivers[service] = driverData + return drivers + + +DriverData = createDriverData() class Provider(backend_base.ProviderBase): def driver_for(self, backend, dummy_net, dummy_subnet): - if backend['service'] == DriverData.service: - return Driver(backend, dummy_net, dummy_subnet) + service = backend['service'] + if service in DriverData: + driverData = DriverData[service] + return Driver(backend, dummy_net, dummy_subnet, driverData) else: return None class Driver(backend_base.Driver): - def __init__(self, backend, dummy_net, dummy_subnet): + def __init__(self, backend, dummy_net, dummy_subnet, driverData): super(Driver, self).__init__(backend, dummy_net, dummy_subnet) + self.driverData = driverData self._port_url = \ "{0:s}/{1:s}/{2:s}/{3:s}/{4:s}".format(backend["url"], - DriverData.proton_base, - DriverData.service, - DriverData.version, - DriverData.ports_name) - self._binding_url = \ - "{0:s}/{1:s}/{2:s}/{3:s}/{4:s}".format(backend["url"], - DriverData.proton_base, - DriverData.service, - DriverData.version, - DriverData.binding_name) + driverData.proton_base, + driverData.service, + driverData.version, + driverData.ports_name) + self._base_url = \ + "{0:s}/{1:s}/{2:s}/{3:s}".format(backend["url"], + driverData.proton_base, + driverData.service, + driverData.version) + self._binding_url = None + + def get_binding_url(self, port_id): + for binding_name in self.driverData.binding_names: + binding_url = "{0:s}/{1:s}".format(self._base_url, binding_name) + url = binding_url + "/" + port_id + try: + svc_bind_data = self._client.json_get(url) + except exc.GluonClientException: + svc_bind_data = None + if svc_bind_data: + self._binding_url = binding_url + break + if self._binding_url is None: + self._binding_url = \ + "{0:s}/{1:s}".format(self._base_url, + self.driverData.binding_names[0]) def port(self, port_id): url = self._port_url + "/" + port_id @@ -67,6 +101,8 @@ class Driver(backend_base.Driver): # The untagged interface has the same UUID as the port # First we get the service binding to retrive the ipaddress # + if self._binding_url is None: + self.get_binding_url(port_id) url = self._binding_url + "/" + port_id try: svc_bind_data = self._client.json_get(url) @@ -80,6 +116,9 @@ class Driver(backend_base.Driver): port_list = self._client.json_get(self._port_url) ret_port_list = [] for port in port_list: + if self._binding_url is None: + self.get_binding_url(port.id) + url = self._binding_url + "/" + port.id try: svc_bind_data = self._client.json_get(url) diff --git a/gluon/models/test/api.yaml b/gluon/models/test/api.yaml index a44c950..42439b4 100644 --- a/gluon/models/test/api.yaml +++ b/gluon/models/test/api.yaml @@ -1,7 +1,7 @@ file_version: "1.0" imports: base/base.yaml info: - name: test_api + name: test version: 1.0 description: "Test API Specification" author: @@ -64,4 +64,9 @@ objects: values: - one - two - - three \ No newline at end of file + - three + TestBinding: + api: + name: TestBinding + plural_name: TestBindings + extends: BaseServiceBinding diff --git a/gluon/particleGenerator/generator.py b/gluon/particleGenerator/generator.py index af30d1f..e977b5b 100644 --- a/gluon/particleGenerator/generator.py +++ b/gluon/particleGenerator/generator.py @@ -409,3 +409,25 @@ def build_api(root, service_list): def get_db_gen(): return GenData.DBGeneratorInstance + + +# Get the binding name for a serivce. For example the binding for net_l3vpn +# would be VpnBinding, and the binding for ietf-sfc would be both +# SfDataPlaneLocator and SffDataPlaneLocator. +# One reason for getting the binding name is to get the port's ipaddress stored +# in binding. One example of using the binding name is when building the +# binding_url in the core plug_in backend in gluon.backends.models.net_l3vpn.py +# param service: service name +# return list of binding names, could be more than one binding per service +def get_service_binding(service): + binding_names = [] + model = load_model_for_service(service) + for obj_name, obj_val in model['api_objects'].items(): + if 'extends' in obj_val and \ + obj_val.get('extends') == 'BaseServiceBinding': + binding_names.append(obj_val['api']['plural_name']) + if not binding_names: + raise_obj_error(service, + 'Service %s does not have binding defined', + (service)) + return binding_names