diff -Nru neutron-plugin-contrail-1.10/debian/changelog neutron-plugin-contrail-1.20~20141023/debian/changelog --- neutron-plugin-contrail-1.10/debian/changelog 2014-09-22 12:27:28.000000000 +0000 +++ neutron-plugin-contrail-1.20~20141023/debian/changelog 2014-10-23 22:20:23.000000000 +0000 @@ -1,4 +1,4 @@ -neutron-plugin-contrail (1.10) precise; urgency=low +neutron-plugin-contrail (1.20~20141023) precise; urgency=low * Initial release. diff -Nru neutron-plugin-contrail-1.10/.git/HEAD neutron-plugin-contrail-1.20~20141023/.git/HEAD --- neutron-plugin-contrail-1.10/.git/HEAD 2014-09-12 11:42:25.000000000 +0000 +++ neutron-plugin-contrail-1.20~20141023/.git/HEAD 2014-10-23 17:14:15.000000000 +0000 @@ -1 +1 @@ -d341c7d910698d6cca0502a6dc0ee07bddcd68e8 +df73691e9009152ca80a910d3d7ce9cde0153275 Binary files /tmp/usZPL9Ky_0/neutron-plugin-contrail-1.10/.git/index and /tmp/yO5HJvydJO/neutron-plugin-contrail-1.20~20141023/.git/index differ diff -Nru neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/driver.py neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/driver.py --- neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/driver.py 2014-09-12 11:42:26.000000000 +0000 +++ neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/driver.py 2014-10-23 17:14:15.000000000 +0000 @@ -2,6 +2,8 @@ # Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. # +import uuid + from neutron.common import exceptions as n_exc from neutron.openstack.common import log as logging import neutron.services.loadbalancer.drivers.abstract_driver as abstract_driver @@ -68,6 +70,7 @@ - left network: backend, determined by the pool subnet """ props = ServiceInstanceType() + if_list = [] vmi = self._get_virtual_ip_interface(vip) if not vmi: @@ -81,6 +84,10 @@ right_ip_address = self._get_interface_address(vmi) if right_ip_address is None: return None + right_if = ServiceInstanceInterfaceType( + virtual_network=right_virtual_network, + ip_address=right_ip_address) + if_list.append(right_if) pool_attrs = pool.get_loadbalancer_pool_properties() backnet_id = utils.get_subnet_network_id( @@ -92,13 +99,15 @@ LOG.error(ex) return None left_virtual_network = ':'.join(vnet.get_fq_name()) - - # add in order [left, right] same as in template - left_if = ServiceInstanceInterfaceType( - virtual_network=left_virtual_network) - right_if = ServiceInstanceInterfaceType( - virtual_network=right_virtual_network, ip_address=right_ip_address) - props.set_interface_list([left_if, right_if]) + left_if = ServiceInstanceInterfaceType( + virtual_network=left_virtual_network) + if_list.append(left_if) + + # set interfaces and ha + props.set_interface_list(if_list) + props.set_ha_mode('active-standby') + scale_out = ServiceScaleOutType(max_instances=2, auto_scale=False) + props.set_scale_out(scale_out) return props @@ -154,7 +163,6 @@ try: si_obj = self._api.service_instance_read(fq_name=fq_name) update = self._service_instance_update_props(si_obj, props) - # TODO: update template if necessary if update: self._api.service_instance_update(si_obj) @@ -172,7 +180,8 @@ def _clear_loadbalancer_instance(self, tenant_id, pool_id): try: - project = self._api.project_read(id=tenant_id) + project = self._api.project_read( + id=str(uuid.UUID(tenant_id))) except NoIdError as ex: LOG.error(ex) return @@ -180,6 +189,19 @@ fq_name.append(pool_id) try: + si_obj = self._api.service_instance_read(fq_name=fq_name) + except NoIdError as ex: + LOG.error(ex) + return + + pool_back_refs = si_obj.get_loadbalancer_pool_back_refs() + for pool_back_ref in pool_back_refs or []: + pool_obj = self._api.loadbalancer_pool_read( + id=pool_back_ref['uuid']) + pool_obj.del_service_instance(si_obj) + self._api.loadbalancer_pool_update(pool_obj) + + try: self._api.service_instance_delete(fq_name=fq_name) except RefsExistError as ex: LOG.error(ex) @@ -199,12 +221,13 @@ """Driver may call the code below in order to update the status. self.plugin.update_status(context, Vip, id, constants.ACTIVE) """ - if vip['pool_id']: - self._update_loadbalancer_instance(vip['pool_id'], vip['id']) - elif old_vip['pool_id']: + if old_vip['pool_id'] != vip['pool_id']: self._clear_loadbalancer_instance( old_vip['tenant_id'], old_vip['pool_id']) + if vip['pool_id']: + self._update_loadbalancer_instance(vip['pool_id'], vip['id']) + def delete_vip(self, context, vip): """A real driver would invoke a call to his backend and try to delete the Vip. @@ -231,15 +254,13 @@ """ if pool['vip_id']: self._update_loadbalancer_instance(pool['id'], pool['vip_id']) - else: - self._clear_loadbalancer_instance(pool['tenant_id'], pool['id']) def delete_pool(self, context, pool): """Driver can call the code below in order to delete the pool. self.plugin._delete_db_pool(context, pool["id"]) or set the status to ERROR if deletion failed """ - self._clear_loadbalancer_instance(pool['tenant_id'], pool['id']) + pass def stats(self, context, pool_id): pass diff -Nru neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_db.py neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_db.py --- neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_db.py 2014-09-12 11:42:26.000000000 +0000 +++ neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_db.py 2014-10-23 17:14:15.000000000 +0000 @@ -2,6 +2,10 @@ # Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. # +import requests +import time +import uuid + from oslo.config import cfg from neutron.extensions import loadbalancer from neutron.extensions.loadbalancer import LoadBalancerPluginBase @@ -21,8 +25,50 @@ admin_tenant_name = cfg.CONF.keystone_authtoken.admin_tenant_name api_srvr_ip = cfg.CONF.APISERVER.api_server_ip api_srvr_port = cfg.CONF.APISERVER.api_server_port - self._api = VncApi(admin_user, admin_password, admin_tenant_name, - api_srvr_ip, api_srvr_port) + try: + auth_host = cfg.CONF.keystone_authtoken.auth_host + except cfg.NoSuchOptError: + auth_host = "127.0.0.1" + + try: + auth_protocol = cfg.CONF.keystone_authtoken.auth_protocol + except cfg.NoSuchOptError: + auth_protocol = "http" + + try: + auth_port = cfg.CONF.keystone_authtoken.auth_port + except cfg.NoSuchOptError: + auth_port = "35357" + + try: + auth_url = cfg.CONF.keystone_authtoken.auth_url + except cfg.NoSuchOptError: + auth_url = "/v2.0/tokens" + + try: + auth_type = cfg.CONF.keystone_authtoken.auth_type + except cfg.NoSuchOptError: + auth_type = "keystone" + + try: + api_server_url = cfg.CONF.APISERVER.api_server_url + except cfg.NoSuchOptError: + api_server_url = "/" + + # Retry till a api-server is up + connected = False + while not connected: + try: + self._api = VncApi( + admin_user, admin_password, admin_tenant_name, + api_srvr_ip, api_srvr_port, api_server_url, + auth_host=auth_host, auth_port=auth_port, + auth_protocol=auth_protocol, auth_url=auth_url, + auth_type=auth_type) + connected = True + except requests.exceptions.RequestException as e: + time.sleep(3) + self._pool_manager = \ loadbalancer_pool.LoadbalancerPoolManager(self._api) self._vip_manager = virtual_ip.VirtualIpManager(self._api) @@ -83,7 +129,7 @@ raise loadbalancer.HealthMonitorNotFound(monitor_id=m['id']) if not context.is_admin: - tenant_id = context.tenant_id + tenant_id = str(uuid.UUID(context.tenant_id)) if tenant_id != pool.parent_uuid or \ tenant_id != monitor.parent_uuid: raise n_exc.NotAuthorized() @@ -100,7 +146,7 @@ res = { 'id': monitor.uuid, - 'tenant_id': monitor.parent_uuid + 'tenant_id': monitor.parent_uuid.replace('-', '') } return res @@ -111,11 +157,12 @@ pool = self._api.loadbalancer_pool_read(id=pool_id) except NoIdError: raise loadbalancer.PoolNotFound(pool_id=id) - if not context.is_admin and context.tenant_id != pool.parent_uuid: + tenant_id = str(uuid.UUID(context.tenant_id)) + if not context.is_admin and tenant_id != pool.parent_uuid: raise loadbalancer.PoolNotFound(pool_id=id) in_list = False - for mref in pool.get_loadbalancer_healthmonitor_refs(): + for mref in pool.get_loadbalancer_healthmonitor_refs() or []: if mref['uuid'] == id: in_list = True break @@ -128,7 +175,7 @@ 'pool_id': pool_id, 'monitor_id': id, 'status': self._pool_manager._get_object_status(pool), - 'tenant_id': pool.parent_uuid + 'tenant_id': pool.parent_uuid.replace('-', '') } return self._pool_manager._fields(res, fields) @@ -137,7 +184,8 @@ pool = self._api.loadbalancer_pool_read(id=pool_id) except NoIdError: raise loadbalancer.PoolNotFound(pool_id=id) - if not context.is_admin and context.tenant_id != pool.parent_uuid: + tenant_id = str(uuid.UUID(context.tenant_id)) + if not context.is_admin and tenant_id != pool.parent_uuid: raise loadbalancer.PoolNotFound(pool_id=id) try: diff -Nru neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_healthmonitor.py neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_healthmonitor.py --- neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_healthmonitor.py 2014-09-12 11:42:26.000000000 +0000 +++ neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_healthmonitor.py 2014-10-23 17:14:15.000000000 +0000 @@ -2,6 +2,8 @@ # Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. # +import uuid + from neutron.extensions import loadbalancer from neutron.openstack.common import uuidutils from vnc_api.vnc_api import IdPermsType, NoIdError @@ -14,7 +16,7 @@ class LoadbalancerHealthmonitorManager(ResourceManager): _loadbalancer_health_type_mapping = { 'admin_state': 'admin_state_up', - 'type': 'type', + 'monitor_type': 'type', 'delay': 'delay', 'timeout': 'timeout', 'max_retries': 'max_retries', @@ -36,7 +38,7 @@ def make_dict(self, health_monitor, fields=None): res = {'id': health_monitor.uuid, - 'tenant_id': health_monitor.parent_uuid, + 'tenant_id': health_monitor.parent_uuid.replace('-', ''), 'status': self._get_object_status(health_monitor)} props = health_monitor.get_loadbalancer_healthmonitor_properties() @@ -45,13 +47,25 @@ if value is not None: res[mapping] = value + pool_ids = [] + pool_back_refs = health_monitor.get_loadbalancer_pool_back_refs() + for pool_back_ref in pool_back_refs or []: + pool_id = {} + pool_id['pool_id'] = pool_back_ref['uuid'] + pool_ids.append(pool_id) + res['pools'] = pool_ids + return self._fields(res, fields) def resource_read(self, id): return self._api.loadbalancer_healthmonitor_read(id=id) def resource_list(self, tenant_id=None): - return self._api.loadbalancer_healthmonitors_list(parent_id=tenant_id) + if tenant_id: + parent_id = str(uuid.UUID(tenant_id)) + else: + parent_id = None + return self._api.loadbalancer_healthmonitors_list(parent_id=parent_id) def resource_update(self, obj): return self._api.loadbalancer_healthmonitor_update(obj) @@ -60,7 +74,10 @@ return self._api.loadbalancer_healthmonitor_delete(id=id) def get_exception_notfound(self, id=None): - return loadbalancer.HealthMonitorNotFound(pool_id=id) + return loadbalancer.HealthMonitorNotFound(monitor_id=id) + + def get_exception_inuse(self, id=None): + return loadbalancer.HealthMonitorInUse(monitor_id=id) @property def neutron_name(self): diff -Nru neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_member.py neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_member.py --- neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_member.py 2014-09-12 11:42:26.000000000 +0000 +++ neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_member.py 2014-10-23 17:14:15.000000000 +0000 @@ -32,6 +32,10 @@ setattr(props, key, member[mapping]) return props + def _get_member_pool_id(self, member): + pool_uuid = member.parent_uuid + return pool_uuid + def make_dict(self, member, fields=None): res = {'id': member.uuid, 'pool_id': member.parent_uuid, @@ -39,7 +43,7 @@ try: pool = self._api.loadbalancer_pool_read(id=member.parent_uuid) - res['tenant_id'] = pool.parent_uuid + res['tenant_id'] = pool.parent_uuid.replace('-', '') except NoIdError: pass @@ -66,11 +70,11 @@ return {} member_list = [] - for pool in pool_list: + for pool in pool_list['loadbalancer-pools']: pool_members = self._api.loadbalancer_members_list( parent_id=pool['uuid']) if 'loadbalancer-members' in pool_members: - member_list.expand(pool_members['loadbalancer-members']) + member_list.extend(pool_members['loadbalancer-members']) response = {'loadbalancer-members': member_list} return response @@ -87,7 +91,7 @@ pool_members = self._api.loadbalancer_members_list( parent_id=pool) if 'loadbalancer-members' in pool_members: - member_list.expand(pool_members['loadbalancer-members']) + member_list.extend(pool_members['loadbalancer-members']) response = [] for m in member_list: @@ -106,6 +110,9 @@ def get_exception_notfound(self, id=None): return loadbalancer.MemberNotFound(member_id=id) + def get_exception_inuse(self, id=None): + pass + @property def neutron_name(self): return "member" @@ -146,3 +153,38 @@ member_db.set_loadbalancer_member_properties(props) return True return False + + def update_object(self, member_db, id, m): + if 'pool_id' in m and self._get_member_pool_id(member_db) != m['pool_id']: + try: + pool = self._api.loadbalancer_pool_read(id=m['pool_id']) + except NoIdError: + raise loadbalancer.PoolNotFound(pool_id=m['pool_id']) + + db_props = member_db.get_loadbalancer_member_properties() + members = pool.get_loadbalancer_members() + for member in members or []: + member_obj = self._api.loadbalancer_member_read( + id=member['uuid']) + props = member_obj.get_loadbalancer_member_properties() + if ((props.get_address() == db_props.get_address()) and + (props.get_protocol_port() == db_props.get_protocol_port())): + raise loadbalancer.MemberExists( + address=props.get_address(), + port=props.get_protocol_port(), + pool=m['pool_id']) + + # delete member from old pool + props = member_db.get_loadbalancer_member_properties() + obj_uuid = member_db.uuid + self._api.loadbalancer_member_delete(id=member_db.uuid) + + # create member for the new pool with same uuid and props + id_perms = IdPermsType(enable=True) + member_obj = LoadbalancerMember( + obj_uuid, pool, loadbalancer_member_properties=props, + id_perms=id_perms) + member_obj.uuid = obj_uuid + self._api.loadbalancer_member_create(member_obj) + + return True diff -Nru neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_pool.py neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_pool.py --- neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_pool.py 2014-09-12 11:42:26.000000000 +0000 +++ neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/loadbalancer_pool.py 2014-10-23 17:14:15.000000000 +0000 @@ -2,13 +2,15 @@ # Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. # +import uuid + from neutron.extensions import loadbalancer from neutron.openstack.common import uuidutils -from vnc_api.vnc_api import IdPermsType, NoIdError +from vnc_api.vnc_api import IdPermsType, NoIdError, HttpError from vnc_api.vnc_api import LoadbalancerPool, LoadbalancerPoolType from resource_manager import ResourceManager - +from resource_manager import LoadbalancerMethodInvalid class LoadbalancerPoolManager(ResourceManager): @@ -33,7 +35,7 @@ def make_dict(self, pool, fields=None): res = { 'id': pool.uuid, - 'tenant_id': pool.parent_uuid, + 'tenant_id': pool.parent_uuid.replace('-', ''), 'name': pool.display_name, 'description': self._get_object_description(pool), 'status': self._get_object_status(pool), @@ -48,31 +50,47 @@ res['provider'] = pool.get_loadbalancer_pool_provider() # vip_id + res['vip_id'] = None vip_refs = pool.get_virtual_ip_back_refs() if vip_refs is not None: res['vip_id'] = vip_refs[0]['uuid'] # members + res['members'] = [] members = pool.get_loadbalancer_members() if members is not None: res['members'] = [member['uuid'] for member in members] # health_monitors + res['health_monitors'] = [] hm_refs = pool.get_loadbalancer_healthmonitor_refs() if hm_refs is not None: res['health_monitors'] = [hm['uuid'] for hm in hm_refs] # TODO: health_monitor_status + res['health_monitors_status'] = [] + return self._fields(res, fields) def resource_read(self, id): return self._api.loadbalancer_pool_read(id=id) def resource_list(self, tenant_id=None): - return self._api.loadbalancer_pools_list(parent_id=tenant_id) + if tenant_id: + parent_id = str(uuid.UUID(tenant_id)) + else: + parent_id = None + return self._api.loadbalancer_pools_list(parent_id=parent_id) def resource_update(self, obj): - return self._api.loadbalancer_pool_update(obj) + try: + return self._api.loadbalancer_pool_update(obj) + except HttpError as e: + if 'LoadbalancerMethodType' in e.content: + pool_props = obj.get_loadbalancer_pool_properties() + lb_method = pool_props.get_loadbalancer_method() + raise LoadbalancerMethodInvalid(lb_method=lb_method, + pool_id=obj.uuid) def resource_delete(self, id): return self._api.loadbalancer_pool_delete(id=id) @@ -80,6 +98,9 @@ def get_exception_notfound(self, id=None): return loadbalancer.PoolNotFound(pool_id=id) + def get_exception_inuse(self, id=None): + return loadbalancer.PoolInUse(pool_id=id) + @property def neutron_name(self): return "pool" diff -Nru neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/plugin.py neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/plugin.py --- neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/plugin.py 2014-09-12 11:42:26.000000000 +0000 +++ neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/plugin.py 2014-10-23 17:14:15.000000000 +0000 @@ -6,6 +6,8 @@ from neutron.plugins.common import constants from neutron.services import service_base +from vnc_api.vnc_api import NoIdError + LOG = logging.getLogger(__name__) @@ -59,7 +61,10 @@ self._pool_driver[pool_id] = driver driver.create_pool(context, p) except Exception as ex: - self._api.loadbalancer_pool_delete(pool_id) + try: + self._api.loadbalancer_pool_delete(pool_id) + except NoIdError: + pass raise ex return p @@ -92,7 +97,10 @@ try: driver.create_vip(context, v) except Exception as ex: - self._api.virtual_ip_delete(v['id']) + try: + self._api.virtual_ip_delete(v['id']) + except NoIdError: + pass raise ex return v diff -Nru neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/resource_manager.py neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/resource_manager.py --- neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/resource_manager.py 2014-09-12 11:42:26.000000000 +0000 +++ neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/resource_manager.py 2014-10-23 17:14:15.000000000 +0000 @@ -5,11 +5,15 @@ from abc import ABCMeta, abstractmethod, abstractproperty from eventlet import greenthread from neutron.common import exceptions as n_exc +from neutron.extensions import loadbalancer from neutron.plugins.common import constants from vnc_api.vnc_api import NoIdError, RefsExistError import six import uuid +class LoadbalancerMethodInvalid(n_exc.BadRequest): + message = _("Method %(lb_method)s not supported for pool %(pool_id)s") + @six.add_metaclass(ABCMeta) class ResourceManager(object): @@ -68,6 +72,12 @@ pass @abstractproperty + def get_exception_inuse(self, id): + """ Returns the correct NotFound exception. + """ + pass + + @abstractproperty def neutron_name(self): """ Resource name in a request from neutron. """ @@ -161,6 +171,15 @@ return None return id_perms.description + def _get_object_tenant_id(self, obj): + proj_fq_name = obj.get_fq_name()[0:2] + try: + proj = self._api.project_read(fq_name=proj_fq_name) + except NoIdError: + return None + + return proj.uuid + def get_resource(self, context, id, fields=None): """ Implement GET by uuid. """ @@ -168,7 +187,9 @@ obj = self.resource_read(id=id) except NoIdError: raise self.get_exception_notfound(id=id) - if not context.is_admin and context.tenant_id != obj.parent_uuid: + tenant_id = str(uuid.UUID(context.tenant_id)) + project_id = self._get_object_tenant_id(obj) + if not context.is_admin and tenant_id != project_id: raise self.get_exception_notfound(id=id) return self.make_dict(obj, fields) @@ -215,14 +236,17 @@ obj = self.resource_read(id=id) except NoIdError: raise self.get_exception_notfound(id=id) - if context.tenant_id != obj.parent_uuid: + tenant_id = str(uuid.UUID(context.tenant_id)) + project_id = self._get_object_tenant_id(obj) + if tenant_id != project_id: raise n_exc.NotAuthorized() - # TODO: possible exceptions: RefsExistError try: self.resource_delete(id=id) except NoIdError: raise self.get_exception_notfound(id=id) + except RefsExistError: + raise self.get_exception_inuse(id=id) def update_properties_subr(self, props, resource): """ Update the DB properties object from the neutron parameters. diff -Nru neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/virtual_ip.py neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/virtual_ip.py --- neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/virtual_ip.py 2014-09-12 11:42:26.000000000 +0000 +++ neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/loadbalancer/virtual_ip.py 2014-10-23 17:14:15.000000000 +0000 @@ -81,7 +81,7 @@ port_id = self._get_interface_params(vip, props) res = {'id': vip.uuid, - 'tenant_id': vip.parent_uuid, + 'tenant_id': vip.parent_uuid.replace('-', ''), 'name': vip.display_name, 'description': self._get_object_description(vip), 'subnet_id': props.subnet_id, @@ -107,7 +107,11 @@ return self._api.virtual_ip_read(id=id) def resource_list(self, tenant_id=None): - return self._api.virtual_ips_list(parent_id=tenant_id) + if tenant_id: + parent_id = str(uuid.UUID(tenant_id)) + else: + parent_id = None + return self._api.virtual_ips_list(parent_id=parent_id) def resource_update(self, obj): return self._api.virtual_ip_update(obj) @@ -118,6 +122,9 @@ def get_exception_notfound(self, id=None): return loadbalancer.VipNotFound(vip_id=id) + def get_exception_inuse(self, id=None): + pass + @property def neutron_name(self): return "vip" @@ -147,8 +154,10 @@ if ip_address and ip_address != attributes.ATTR_NOT_SPECIFIED: iip_obj.set_instance_ip_address(ip_address) self._api.instance_ip_create(iip_obj) + iip = self._api.instance_ip_read(id=iip_obj.uuid) + vip_address = iip.get_instance_ip_address() - return vmi + return vmi, vip_address def _delete_virtual_interface(self, vmi_list): if vmi_list is None: @@ -167,6 +176,16 @@ for ref in ip_refs: self._api.instance_ip_delete(id=ref['uuid']) + fip_refs = vmi.get_floating_ip_back_refs() + for ref in fip_refs or []: + try: + fip = self._api.floating_ip_read(id=ref['uuid']) + except NoIdError as ex: + LOG.error(ex) + continue + fip.set_virtual_machine_interface_list([]) + self._api.floating_ip_update(fip) + self._api.virtual_machine_interface_delete(id=interface_id) def create(self, context, vip): @@ -186,29 +205,34 @@ project_id = pool.parent_uuid if str(uuid.UUID(tenant_id)) != project_id: raise n_exc.NotAuthorized() - # TODO: check that the pool has no vip configured - # if pool.protocol != v['protocol']: - # raise loadbalancer.ProtocolMismatch( - # vip_proto=v['protocol'], pool_proto=pool.protocol) + protocol = pool.get_loadbalancer_pool_properties().get_protocol() + if protocol != v['protocol']: + raise loadbalancer.ProtocolMismatch( + vip_proto=v['protocol'], pool_proto=protocol) + if pool.get_virtual_ip_back_refs(): + raise loadbalancer.VipExists(pool_id=v['pool_id']) else: pool = None obj_uuid = uuidutils.generate_uuid() name = self._get_resource_name('virtual-ip', project, v['name'], obj_uuid) - props = self.make_properties(v) id_perms = IdPermsType(enable=True, description=v['description']) - vip = VirtualIp(name, project, virtual_ip_properties=props, - id_perms=id_perms, display_name=v['name']) + vip = VirtualIp(name, project, id_perms=id_perms, + display_name=v['name']) vip.uuid = obj_uuid if pool: vip.set_loadbalancer_pool(pool) - vmi = self._create_virtual_interface(project, obj_uuid, v['subnet_id'], - v.get('address')) + vmi, vip_address = self._create_virtual_interface(project, + obj_uuid, v['subnet_id'], v.get('address')) vip.set_virtual_machine_interface(vmi) + props = self.make_properties(v) + props.set_address(vip_address) + vip.set_virtual_ip_properties(props) + self._api.virtual_ip_create(vip) return self.make_dict(vip) @@ -218,9 +242,9 @@ except NoIdError: loadbalancer.VipNotFound(vip_id=id) + super(VirtualIpManager, self).delete(context, id) self._delete_virtual_interface( vip.get_virtual_machine_interface_refs()) - super(VirtualIpManager, self).delete(context, id) def _update_virtual_ip_properties(self, props, id, vip): """ @@ -242,12 +266,15 @@ if 'session_persistence' in vip: sp = vip['session_persistence'] - if props.persistence_type != sp['type']: - props.persistence_type = sp['type'] + + new_type = sp.get('type', None) + if props.persistence_type != new_type: + props.persistence_type = new_type change = True - if 'cookie_name' in sp and \ - props.persistence_cookie_name != sp['cookie_name']: - props.persistence_cookie_name != sp['cookie_name'] + new_cookie_name = sp.get('cookie_name', None) + if props.persistence_cookie_name != new_cookie_name and \ + props.persistence_type == 'APP_COOKIE': + props.persistence_cookie_name = new_cookie_name change = True return change @@ -267,11 +294,21 @@ raise loadbalancer.PoolNotFound(pool_id=v['pool_id']) if vip_db.parent_uuid != pool.parent_uuid: raise n_exc.NotAuthorized() - # TODO: check that the pool has no vip configured - # TODO: check that the protocol matches - # TODO: check that the pool is in valid state - # TODO: check that the provider is the same. - vip_db.set_localbalancer_pool(pool) + + # check that the pool has no vip configured + if pool.get_virtual_ip_back_refs(): + raise loadbalancer.VipExists(pool_id=pool_obj.uuid) + + # check that the protocol matches + pool_props = pool.get_loadbalancer_pool_properties() + vip_props = vip_db.get_virtual_ip_properties() + if pool_props.get_protocol() != vip_props.get_protocol(): + raise loadbalancer.ProtocolMismatch( + vip_proto=vip_props.get_protocol(), + pool_proto=pool_props.get_protocol()) + + # update vip + vip_db.set_loadbalancer_pool(pool) return True return False diff -Nru neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/quota/driver.py neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/quota/driver.py --- neutron-plugin-contrail-1.10/neutron_plugin_contrail/plugins/opencontrail/quota/driver.py 2014-09-12 11:42:26.000000000 +0000 +++ neutron-plugin-contrail-1.20~20141023/neutron_plugin_contrail/plugins/opencontrail/quota/driver.py 2014-10-23 17:14:15.000000000 +0000 @@ -88,6 +88,17 @@ @classmethod def get_tenant_quotas(cls, context, resources, tenant_id): try: + default_project = cls._get_vnc_conn().project_read( + fq_name=['default-domain', 'default-project']) + default_quota = default_project.get_quota() + except vnc_exc.NoIdError: + default_quota = None + return cls._get_tenant_quotas(context, resources, tenant_id, + default_quota) + + @classmethod + def _get_tenant_quotas(cls, context, resources, tenant_id, default_quota): + try: proj_id = str(uuid.UUID(tenant_id)) proj_obj = cls._get_vnc_conn().project_read(id=proj_id) quota = proj_obj.get_quota() @@ -100,21 +111,34 @@ qn2c = cls.quota_neutron_to_contrail_type quotas = {} for resource in resources: + quota_res = None if quota and resource in qn2c: quota_res = getattr(quota, qn2c[resource], None) + if quota_res is None and default_quota and resource in qn2c: + quota_res = getattr(default_quota, qn2c[resource], None) if quota_res is None: - quota_res = quota.get_defaults() - quotas[resource] = quota_res - else: - quotas[resource] = resources[resource].default + quota_res = default_quota.get_defaults() + if quota_res is None: + quota_res = resources[resource].default + quotas[resource] = quota_res return quotas @classmethod def get_all_quotas(cls, context, resources): + try: + default_project = cls._get_vnc_conn().project_read( + fq_name=['default-domain', 'default-project']) + default_quota = default_project.get_quota() + except vnc_exc.NoIdError: + default_quota = None + project_list = cls._get_vnc_conn().projects_list()['projects'] ret_list = [] for project in project_list: - quotas = cls.get_tenant_quotas(context, resources, project['uuid']) + if default_quota and (project['uuid'] == default_project.uuid): + continue + quotas = cls._get_tenant_quotas(context, resources, project['uuid'], + default_quota) quotas['tenant_id'] = project['uuid'] ret_list.append(quotas) return ret_list @@ -133,7 +157,7 @@ for k,v in quota.__dict__.items(): if k != 'defaults': - quota.__dict__[k] = quota.defaults + quota.__dict__[k] = None proj_obj.set_quota(quota) cls._get_vnc_conn().project_update(proj_obj) @@ -142,7 +166,7 @@ try: proj_id = str(uuid.UUID(tenant_id)) proj_obj = cls._get_vnc_conn().project_read(id=proj_id) - quota = proj_obj.get_quota() + quota = proj_obj.get_quota() or vnc_api.QuotaType() except vnc_exc.NoIdError: return except Exception as e: