From ac2462a58450a34a0dbb6a6feb5644037f2886c2 Mon Sep 17 00:00:00 2001 From: Takashi Kajinami Date: Thu, 23 Mar 2023 18:34:21 +0900 Subject: [PATCH] Clear implementations for neutron LBaaS v1 These resources were hidden some releases ago so we no longer need to maintain the implementations. Story: 2010678 Task: 47760 Change-Id: Id9684396e495f46890a915e7d05d9fd2ddc24b63 --- .../clients/os/neutron/neutron_constraints.py | 4 - .../openstack/heat/instance_group.py | 4 +- .../openstack/neutron/loadbalancer.py | 753 +----------- heat/scaling/lbutils.py | 3 +- heat/tests/autoscaling/test_lbutils.py | 37 - heat/tests/clients/test_neutron_client.py | 3 - .../openstack/heat/test_instance_group.py | 65 - .../neutron/test_neutron_loadbalancer.py | 1093 ----------------- setup.cfg | 1 - 9 files changed, 9 insertions(+), 1954 deletions(-) delete mode 100644 heat/tests/openstack/neutron/test_neutron_loadbalancer.py diff --git a/heat/engine/clients/os/neutron/neutron_constraints.py b/heat/engine/clients/os/neutron/neutron_constraints.py index b81549bc96..dc120e84ab 100644 --- a/heat/engine/clients/os/neutron/neutron_constraints.py +++ b/heat/engine/clients/os/neutron/neutron_constraints.py @@ -121,7 +121,3 @@ class ProviderConstraint(constraints.BaseCustomConstraint): {'provider': value, 'providers': names} ) raise exception.StackValidationFailed(message=not_found_message) - - -class LBaasV1ProviderConstraint(ProviderConstraint): - service_type = 'LOADBALANCER' diff --git a/heat/engine/resources/openstack/heat/instance_group.py b/heat/engine/resources/openstack/heat/instance_group.py index 86b19f1812..345e56daea 100644 --- a/heat/engine/resources/openstack/heat/instance_group.py +++ b/heat/engine/resources/openstack/heat/instance_group.py @@ -96,7 +96,9 @@ class InstanceGroup(stack_resource.StackResource): ), LOAD_BALANCER_NAMES: properties.Schema( properties.Schema.LIST, - _('List of LoadBalancer resources.') + _('List of LoadBalancer resources. Currently only ' + 'the AWS::ElasticLoadBalancing::LoadBalancer resource type is ' + 'supported.') ), TAGS: properties.Schema( properties.Schema.LIST, diff --git a/heat/engine/resources/openstack/neutron/loadbalancer.py b/heat/engine/resources/openstack/neutron/loadbalancer.py index 49ff9372c5..56d92d4fc7 100644 --- a/heat/engine/resources/openstack/neutron/loadbalancer.py +++ b/heat/engine/resources/openstack/neutron/loadbalancer.py @@ -11,23 +11,16 @@ # License for the specific language governing permissions and limitations # under the License. -from heat.common import exception from heat.common.i18n import _ -from heat.engine import attributes -from heat.engine.clients import progress -from heat.engine import constraints -from heat.engine import properties -from heat.engine import resource -from heat.engine.resources.openstack.neutron import neutron +from heat.engine.resources.openstack.heat import none_resource from heat.engine import support -from heat.engine import translation DEPR_MSG = _('Neutron LBaaS v1 is deprecated in the Liberty release ' 'and is planned to be removed in a future release. ' 'Going forward, the LBaaS V2 should be used.') -class HealthMonitor(neutron.NeutronResource): +class HealthMonitor(none_resource.NoneResource): """A resource for managing health monitors for loadbalancers in Neutron. A health monitor is used to determine whether or not back-end members of @@ -41,10 +34,6 @@ class HealthMonitor(neutron.NeutronResource): - HTTPS: used to send a secure HTTP request to the member. """ - required_service_extension = 'lbaas' - - entity = 'health_monitor' - support_status = support.SupportStatus( status=support.HIDDEN, version='9.0.0', @@ -56,146 +45,8 @@ class HealthMonitor(neutron.NeutronResource): ) ) - PROPERTIES = ( - DELAY, TYPE, MAX_RETRIES, TIMEOUT, ADMIN_STATE_UP, - HTTP_METHOD, EXPECTED_CODES, URL_PATH, - ) = ( - 'delay', 'type', 'max_retries', 'timeout', 'admin_state_up', - 'http_method', 'expected_codes', 'url_path', - ) - ATTRIBUTES = ( - ADMIN_STATE_UP_ATTR, DELAY_ATTR, EXPECTED_CODES_ATTR, HTTP_METHOD_ATTR, - MAX_RETRIES_ATTR, TIMEOUT_ATTR, TYPE_ATTR, URL_PATH_ATTR, TENANT_ID, - ) = ( - 'admin_state_up', 'delay', 'expected_codes', 'http_method', - 'max_retries', 'timeout', 'type', 'url_path', 'tenant_id', - ) - - properties_schema = { - DELAY: properties.Schema( - properties.Schema.INTEGER, - _('The minimum time in milliseconds between regular connections ' - 'of the member.'), - required=True, - update_allowed=True - ), - TYPE: properties.Schema( - properties.Schema.STRING, - _('One of predefined health monitor types.'), - required=True, - constraints=[ - constraints.AllowedValues(['PING', 'TCP', 'HTTP', 'HTTPS']), - ] - ), - MAX_RETRIES: properties.Schema( - properties.Schema.INTEGER, - _('Number of permissible connection failures before changing the ' - 'member status to INACTIVE.'), - required=True, - update_allowed=True - ), - TIMEOUT: properties.Schema( - properties.Schema.INTEGER, - _('Maximum number of milliseconds for a monitor to wait for a ' - 'connection to be established before it times out.'), - required=True, - update_allowed=True - ), - ADMIN_STATE_UP: properties.Schema( - properties.Schema.BOOLEAN, - _('The administrative state of the health monitor.'), - default=True, - update_allowed=True - ), - HTTP_METHOD: properties.Schema( - properties.Schema.STRING, - _('The HTTP method used for requests by the monitor of type ' - 'HTTP.'), - update_allowed=True - ), - EXPECTED_CODES: properties.Schema( - properties.Schema.STRING, - _('The list of HTTP status codes expected in response from the ' - 'member to declare it healthy.'), - update_allowed=True - ), - URL_PATH: properties.Schema( - properties.Schema.STRING, - _('The HTTP path used in the HTTP request used by the monitor to ' - 'test a member health.'), - update_allowed=True - ), - } - - attributes_schema = { - ADMIN_STATE_UP_ATTR: attributes.Schema( - _('The administrative state of this health monitor.'), - type=attributes.Schema.STRING - ), - DELAY_ATTR: attributes.Schema( - _('The minimum time in milliseconds between regular connections ' - 'of the member.'), - type=attributes.Schema.STRING - ), - EXPECTED_CODES_ATTR: attributes.Schema( - _('The list of HTTP status codes expected in response ' - 'from the member to declare it healthy.'), - type=attributes.Schema.LIST - ), - HTTP_METHOD_ATTR: attributes.Schema( - _('The HTTP method used for requests by the monitor of ' - 'type HTTP.'), - type=attributes.Schema.STRING - ), - MAX_RETRIES_ATTR: attributes.Schema( - _('Number of permissible connection failures before changing ' - 'the member status to INACTIVE.'), - type=attributes.Schema.STRING - ), - TIMEOUT_ATTR: attributes.Schema( - _('Maximum number of milliseconds for a monitor to wait for a ' - 'connection to be established before it times out.'), - type=attributes.Schema.STRING - ), - TYPE_ATTR: attributes.Schema( - _('One of predefined health monitor types.'), - type=attributes.Schema.STRING - ), - URL_PATH_ATTR: attributes.Schema( - _('The HTTP path used in the HTTP request used by the monitor ' - 'to test a member health.'), - type=attributes.Schema.STRING - ), - TENANT_ID: attributes.Schema( - _('Tenant owning the health monitor.'), - type=attributes.Schema.STRING - ), - } - - def handle_create(self): - properties = self.prepare_properties( - self.properties, - self.physical_resource_name()) - health_monitor = self.client().create_health_monitor( - {'health_monitor': properties})['health_monitor'] - self.resource_id_set(health_monitor['id']) - - def handle_update(self, json_snippet, tmpl_diff, prop_diff): - if prop_diff: - self.client().update_health_monitor( - self.resource_id, {'health_monitor': prop_diff}) - - def handle_delete(self): - try: - self.client().delete_health_monitor(self.resource_id) - except Exception as ex: - self.client_plugin().ignore_not_found(ex) - else: - return True - - -class Pool(neutron.NeutronResource): +class Pool(none_resource.NoneResource): """A resource for managing load balancer pools in Neutron. A load balancing pool is a logical set of devices, such as web servers, @@ -205,10 +56,6 @@ class Pool(neutron.NeutronResource): VIP address. There is only one pool for a VIP. """ - required_service_extension = 'lbaas' - - entity = 'pool' - support_status = support.SupportStatus( status=support.HIDDEN, version='9.0.0', @@ -220,404 +67,13 @@ class Pool(neutron.NeutronResource): ) ) - PROPERTIES = ( - PROTOCOL, SUBNET_ID, SUBNET, LB_METHOD, NAME, DESCRIPTION, - ADMIN_STATE_UP, VIP, MONITORS, PROVIDER, - ) = ( - 'protocol', 'subnet_id', 'subnet', 'lb_method', 'name', 'description', - 'admin_state_up', 'vip', 'monitors', 'provider', - ) - _VIP_KEYS = ( - VIP_NAME, VIP_DESCRIPTION, VIP_SUBNET, VIP_ADDRESS, - VIP_CONNECTION_LIMIT, VIP_PROTOCOL_PORT, - VIP_SESSION_PERSISTENCE, VIP_ADMIN_STATE_UP, - ) = ( - 'name', 'description', 'subnet', 'address', - 'connection_limit', 'protocol_port', - 'session_persistence', 'admin_state_up', - ) - - _VIP_SESSION_PERSISTENCE_KEYS = ( - VIP_SESSION_PERSISTENCE_TYPE, VIP_SESSION_PERSISTENCE_COOKIE_NAME, - ) = ( - 'type', 'cookie_name', - ) - - ATTRIBUTES = ( - ADMIN_STATE_UP_ATTR, NAME_ATTR, PROTOCOL_ATTR, SUBNET_ID_ATTR, - LB_METHOD_ATTR, DESCRIPTION_ATTR, TENANT_ID, VIP_ATTR, PROVIDER_ATTR, - ) = ( - 'admin_state_up', 'name', 'protocol', 'subnet_id', - 'lb_method', 'description', 'tenant_id', 'vip', 'provider', - ) - - properties_schema = { - PROTOCOL: properties.Schema( - properties.Schema.STRING, - _('Protocol for balancing.'), - required=True, - constraints=[ - constraints.AllowedValues(['TCP', 'HTTP', 'HTTPS']), - ] - ), - SUBNET_ID: properties.Schema( - properties.Schema.STRING, - support_status=support.SupportStatus( - status=support.HIDDEN, - version='5.0.0', - message=_('Use property %s.') % SUBNET, - previous_status=support.SupportStatus( - status=support.DEPRECATED, - version='2014.2' - ) - ), - constraints=[ - constraints.CustomConstraint('neutron.subnet') - ] - ), - SUBNET: properties.Schema( - properties.Schema.STRING, - _('The subnet for the port on which the members ' - 'of the pool will be connected.'), - support_status=support.SupportStatus(version='2014.2'), - required=True, - constraints=[ - constraints.CustomConstraint('neutron.subnet') - ] - ), - LB_METHOD: properties.Schema( - properties.Schema.STRING, - _('The algorithm used to distribute load between the members of ' - 'the pool.'), - required=True, - constraints=[ - constraints.AllowedValues(['ROUND_ROBIN', - 'LEAST_CONNECTIONS', 'SOURCE_IP']), - ], - update_allowed=True - ), - NAME: properties.Schema( - properties.Schema.STRING, - _('Name of the pool.') - ), - DESCRIPTION: properties.Schema( - properties.Schema.STRING, - _('Description of the pool.'), - update_allowed=True - ), - ADMIN_STATE_UP: properties.Schema( - properties.Schema.BOOLEAN, - _('The administrative state of this pool.'), - default=True, - update_allowed=True - ), - PROVIDER: properties.Schema( - properties.Schema.STRING, - _('LBaaS provider to implement this load balancer instance.'), - support_status=support.SupportStatus(version='5.0.0'), - constraints=[ - constraints.CustomConstraint('neutron.lb.provider') - ], - ), - VIP: properties.Schema( - properties.Schema.MAP, - _('IP address and port of the pool.'), - schema={ - VIP_NAME: properties.Schema( - properties.Schema.STRING, - _('Name of the vip.') - ), - VIP_DESCRIPTION: properties.Schema( - properties.Schema.STRING, - _('Description of the vip.') - ), - VIP_SUBNET: properties.Schema( - properties.Schema.STRING, - _('Subnet of the vip.'), - constraints=[ - constraints.CustomConstraint('neutron.subnet') - ] - ), - VIP_ADDRESS: properties.Schema( - properties.Schema.STRING, - _('IP address of the vip.'), - constraints=[ - constraints.CustomConstraint('ip_addr') - ] - ), - VIP_CONNECTION_LIMIT: properties.Schema( - properties.Schema.INTEGER, - _('The maximum number of connections per second ' - 'allowed for the vip.') - ), - VIP_PROTOCOL_PORT: properties.Schema( - properties.Schema.INTEGER, - _('TCP port on which to listen for client traffic ' - 'that is associated with the vip address.'), - required=True - ), - VIP_SESSION_PERSISTENCE: properties.Schema( - properties.Schema.MAP, - _('Configuration of session persistence.'), - schema={ - VIP_SESSION_PERSISTENCE_TYPE: properties.Schema( - properties.Schema.STRING, - _('Method of implementation of session ' - 'persistence feature.'), - required=True, - constraints=[constraints.AllowedValues( - ['SOURCE_IP', 'HTTP_COOKIE', 'APP_COOKIE'] - )] - ), - VIP_SESSION_PERSISTENCE_COOKIE_NAME: properties.Schema( - properties.Schema.STRING, - _('Name of the cookie, ' - 'required if type is APP_COOKIE.') - ) - } - ), - VIP_ADMIN_STATE_UP: properties.Schema( - properties.Schema.BOOLEAN, - _('The administrative state of this vip.'), - default=True - ), - }, - required=True - ), - MONITORS: properties.Schema( - properties.Schema.LIST, - _('List of health monitors associated with the pool.'), - default=[], - update_allowed=True - ), - } - - attributes_schema = { - ADMIN_STATE_UP_ATTR: attributes.Schema( - _('The administrative state of this pool.'), - type=attributes.Schema.STRING - ), - NAME_ATTR: attributes.Schema( - _('Name of the pool.'), - type=attributes.Schema.STRING - ), - PROTOCOL_ATTR: attributes.Schema( - _('Protocol to balance.'), - type=attributes.Schema.STRING - ), - SUBNET_ID_ATTR: attributes.Schema( - _('The subnet for the port on which the members of the pool ' - 'will be connected.'), - type=attributes.Schema.STRING - ), - LB_METHOD_ATTR: attributes.Schema( - _('The algorithm used to distribute load between the members ' - 'of the pool.'), - type=attributes.Schema.STRING - ), - DESCRIPTION_ATTR: attributes.Schema( - _('Description of the pool.'), - type=attributes.Schema.STRING - ), - TENANT_ID: attributes.Schema( - _('Tenant owning the pool.'), - type=attributes.Schema.STRING - ), - VIP_ATTR: attributes.Schema( - _('Vip associated with the pool.'), - type=attributes.Schema.MAP - ), - PROVIDER_ATTR: attributes.Schema( - _('Provider implementing this load balancer instance.'), - support_status=support.SupportStatus(version='5.0.0'), - type=attributes.Schema.STRING, - ), - } - - def translation_rules(self, props): - client_plugin = self.client_plugin() - return [ - translation.TranslationRule( - props, - translation.TranslationRule.REPLACE, - [self.SUBNET], - value_path=[self.SUBNET_ID] - ), - translation.TranslationRule( - props, - translation.TranslationRule.RESOLVE, - [self.SUBNET], - client_plugin=client_plugin, - finder='find_resourceid_by_name_or_id', - entity=client_plugin.RES_TYPE_SUBNET - ), - translation.TranslationRule( - props, - translation.TranslationRule.RESOLVE, - [self.VIP, self.VIP_SUBNET], - client_plugin=self.client_plugin(), - finder='find_resourceid_by_name_or_id', - entity=client_plugin.RES_TYPE_SUBNET - ) - ] - - def validate(self): - res = super(Pool, self).validate() - if res: - return res - session_p = self.properties[self.VIP].get(self.VIP_SESSION_PERSISTENCE) - if session_p is None: - # session persistence is not configured, skip validation - return - - persistence_type = session_p[self.VIP_SESSION_PERSISTENCE_TYPE] - if persistence_type == 'APP_COOKIE': - if session_p.get(self.VIP_SESSION_PERSISTENCE_COOKIE_NAME): - return - - msg = _('Property cookie_name is required, when ' - 'session_persistence type is set to APP_COOKIE.') - raise exception.StackValidationFailed(message=msg) - - def handle_create(self): - properties = self.prepare_properties( - self.properties, - self.physical_resource_name()) - subnet_id = properties.pop(self.SUBNET) - properties['subnet_id'] = subnet_id - vip_properties = properties.pop(self.VIP) - monitors = properties.pop(self.MONITORS) - - pool = self.client().create_pool({'pool': properties})['pool'] - self.resource_id_set(pool['id']) - - for monitor in monitors: - self.client().associate_health_monitor( - pool['id'], {'health_monitor': {'id': monitor}}) - - vip_arguments = self.prepare_properties( - vip_properties, - '%s.vip' % (self.name,)) - - session_p = vip_arguments.get(self.VIP_SESSION_PERSISTENCE) - if session_p is not None: - prepared_props = self.prepare_properties(session_p, None) - vip_arguments['session_persistence'] = prepared_props - - vip_arguments['protocol'] = self.properties[self.PROTOCOL] - - if vip_arguments.get(self.VIP_SUBNET) is None: - vip_arguments['subnet_id'] = subnet_id - else: - vip_arguments['subnet_id'] = vip_arguments.pop(self.VIP_SUBNET) - - vip_arguments['pool_id'] = pool['id'] - vip = self.client().create_vip({'vip': vip_arguments})['vip'] - - self.metadata_set({'vip': vip['id']}) - - def check_create_complete(self, data): - attributes = self._show_resource() - status = attributes['status'] - if status == 'PENDING_CREATE': - return False - elif status == 'ACTIVE': - vip_attributes = self.client().show_vip( - self.metadata_get()['vip'])['vip'] - vip_status = vip_attributes['status'] - if vip_status == 'PENDING_CREATE': - return False - if vip_status == 'ACTIVE': - return True - if vip_status == 'ERROR': - raise exception.ResourceInError( - resource_status=vip_status, - status_reason=_('error in vip')) - raise exception.ResourceUnknownStatus( - resource_status=vip_status, - result=_('Pool creation failed due to vip')) - elif status == 'ERROR': - raise exception.ResourceInError( - resource_status=status, - status_reason=_('error in pool')) - else: - raise exception.ResourceUnknownStatus( - resource_status=status, - result=_('Pool creation failed')) - - def handle_update(self, json_snippet, tmpl_diff, prop_diff): - if prop_diff: - if self.MONITORS in prop_diff: - monitors = set(prop_diff.pop(self.MONITORS)) - old_monitors = set(self.properties[self.MONITORS]) - for monitor in old_monitors - monitors: - self.client().disassociate_health_monitor( - self.resource_id, monitor) - for monitor in monitors - old_monitors: - self.client().associate_health_monitor( - self.resource_id, {'health_monitor': {'id': monitor}}) - - if prop_diff: - self.client().update_pool(self.resource_id, - {'pool': prop_diff}) - - def _resolve_attribute(self, name): - if name == self.VIP_ATTR: - return self.client().show_vip(self.metadata_get()['vip'])['vip'] - return super(Pool, self)._resolve_attribute(name) - - def handle_delete(self): - if not self.resource_id: - prg = progress.PoolDeleteProgress(True) - return prg - - prg = progress.PoolDeleteProgress() - if not self.metadata_get(): - prg.vip['delete_called'] = True - prg.vip['deleted'] = True - return prg - - def _delete_vip(self): - return self._not_found_in_call( - self.client().delete_vip, self.metadata_get()['vip']) - - def _check_vip_deleted(self): - return self._not_found_in_call( - self.client().show_vip, self.metadata_get()['vip']) - - def _delete_pool(self): - return self._not_found_in_call( - self.client().delete_pool, self.resource_id) - - def check_delete_complete(self, prg): - if not prg.vip['delete_called']: - prg.vip['deleted'] = self._delete_vip() - prg.vip['delete_called'] = True - return False - if not prg.vip['deleted']: - prg.vip['deleted'] = self._check_vip_deleted() - return False - if not prg.pool['delete_called']: - prg.pool['deleted'] = self._delete_pool() - prg.pool['delete_called'] = True - return prg.pool['deleted'] - if not prg.pool['deleted']: - prg.pool['deleted'] = super(Pool, self).check_delete_complete(True) - return prg.pool['deleted'] - return True - - -class PoolMember(neutron.NeutronResource): +class PoolMember(none_resource.NoneResource): """A resource to handle loadbalancer members. A pool member represents the application running on backend server. """ - required_service_extension = 'lbaas' - - entity = 'member' - support_status = support.SupportStatus( status=support.HIDDEN, version='9.0.0', @@ -630,130 +86,14 @@ class PoolMember(neutron.NeutronResource): ) ) - PROPERTIES = ( - POOL_ID, ADDRESS, PROTOCOL_PORT, WEIGHT, ADMIN_STATE_UP, - ) = ( - 'pool_id', 'address', 'protocol_port', 'weight', 'admin_state_up', - ) - ATTRIBUTES = ( - ADMIN_STATE_UP_ATTR, TENANT_ID, WEIGHT_ATTR, ADDRESS_ATTR, - POOL_ID_ATTR, PROTOCOL_PORT_ATTR, - ) = ( - 'admin_state_up', 'tenant_id', 'weight', 'address', - 'pool_id', 'protocol_port', - ) - - properties_schema = { - POOL_ID: properties.Schema( - properties.Schema.STRING, - _('The ID of the load balancing pool.'), - required=True, - update_allowed=True - ), - ADDRESS: properties.Schema( - properties.Schema.STRING, - _('IP address of the pool member on the pool network.'), - required=True, - constraints=[ - constraints.CustomConstraint('ip_addr') - ] - ), - PROTOCOL_PORT: properties.Schema( - properties.Schema.INTEGER, - _('TCP port on which the pool member listens for requests or ' - 'connections.'), - required=True, - constraints=[ - constraints.Range(0, 65535), - ] - ), - WEIGHT: properties.Schema( - properties.Schema.INTEGER, - _('Weight of pool member in the pool (default to 1).'), - constraints=[ - constraints.Range(0, 256), - ], - update_allowed=True - ), - ADMIN_STATE_UP: properties.Schema( - properties.Schema.BOOLEAN, - _('The administrative state of the pool member.'), - default=True - ), - } - - attributes_schema = { - ADMIN_STATE_UP_ATTR: attributes.Schema( - _('The administrative state of this pool member.'), - type=attributes.Schema.STRING - ), - TENANT_ID: attributes.Schema( - _('Tenant owning the pool member.'), - type=attributes.Schema.STRING - ), - WEIGHT_ATTR: attributes.Schema( - _('Weight of the pool member in the pool.'), - type=attributes.Schema.STRING - ), - ADDRESS_ATTR: attributes.Schema( - _('IP address of the pool member.'), - type=attributes.Schema.STRING - ), - POOL_ID_ATTR: attributes.Schema( - _('The ID of the load balancing pool.'), - type=attributes.Schema.STRING - ), - PROTOCOL_PORT_ATTR: attributes.Schema( - _('TCP port on which the pool member listens for requests or ' - 'connections.'), - type=attributes.Schema.STRING - ), - } - - def handle_create(self): - pool = self.properties[self.POOL_ID] - protocol_port = self.properties[self.PROTOCOL_PORT] - address = self.properties[self.ADDRESS] - admin_state_up = self.properties[self.ADMIN_STATE_UP] - weight = self.properties[self.WEIGHT] - - params = { - 'pool_id': pool, - 'address': address, - 'protocol_port': protocol_port, - 'admin_state_up': admin_state_up - } - - if weight is not None: - params['weight'] = weight - - member = self.client().create_member({'member': params})['member'] - self.resource_id_set(member['id']) - - def handle_update(self, json_snippet, tmpl_diff, prop_diff): - if prop_diff: - self.client().update_member( - self.resource_id, {'member': prop_diff}) - - def handle_delete(self): - try: - self.client().delete_member(self.resource_id) - except Exception as ex: - self.client_plugin().ignore_not_found(ex) - else: - return True - - -class LoadBalancer(resource.Resource): +class LoadBalancer(none_resource.NoneResource): """A resource to link a neutron pool with servers. A loadbalancer allows linking a neutron pool with specified servers to some port. """ - required_service_extension = 'lbaas' - support_status = support.SupportStatus( status=support.HIDDEN, version='9.0.0', @@ -766,89 +106,6 @@ class LoadBalancer(resource.Resource): ) ) - PROPERTIES = ( - POOL_ID, PROTOCOL_PORT, MEMBERS, - ) = ( - 'pool_id', 'protocol_port', 'members', - ) - - properties_schema = { - POOL_ID: properties.Schema( - properties.Schema.STRING, - _('The ID of the load balancing pool.'), - required=True, - update_allowed=True - ), - PROTOCOL_PORT: properties.Schema( - properties.Schema.INTEGER, - _('Port number on which the servers are running on the members.'), - required=True, - constraints=[ - constraints.Range(0, 65535), - ] - ), - MEMBERS: properties.Schema( - properties.Schema.LIST, - _('The list of Nova server IDs load balanced.'), - update_allowed=True - ), - } - - default_client_name = 'neutron' - - def handle_create(self): - pool = self.properties[self.POOL_ID] - protocol_port = self.properties[self.PROTOCOL_PORT] - - for member in self.properties[self.MEMBERS] or []: - address = self.client_plugin('nova').server_to_ipaddress(member) - lb_member = self.client().create_member({ - 'member': { - 'pool_id': pool, - 'address': address, - 'protocol_port': protocol_port}})['member'] - self.data_set(member, lb_member['id']) - - def handle_update(self, json_snippet, tmpl_diff, prop_diff): - new_props = json_snippet.properties(self.properties_schema, - self.context) - - # Valid use cases are: - # - Membership controlled by members property in template - # - Empty members property in template; membership controlled by - # "updates" triggered from autoscaling group. - # Mixing the two will lead to undefined behaviour. - if (self.MEMBERS in prop_diff and - (self.properties[self.MEMBERS] is not None or - new_props[self.MEMBERS] is not None)): - members = set(new_props[self.MEMBERS] or []) - rd_members = self.data() - old_members = set(rd_members) - for member in old_members - members: - member_id = rd_members[member] - with self.client_plugin().ignore_not_found: - self.client().delete_member(member_id) - self.data_delete(member) - pool = self.properties[self.POOL_ID] - protocol_port = self.properties[self.PROTOCOL_PORT] - for member in members - old_members: - address = self.client_plugin('nova').server_to_ipaddress( - member) - lb_member = self.client().create_member({ - 'member': { - 'pool_id': pool, - 'address': address, - 'protocol_port': protocol_port}})['member'] - self.data_set(member, lb_member['id']) - - def handle_delete(self): - # FIXME(pshchelo): this deletes members in a tight loop, - # so is prone to OverLimit bug similar to LP 1265937 - for member, member_id in self.data().items(): - with self.client_plugin().ignore_not_found: - self.client().delete_member(member_id) - self.data_delete(member) - def resource_mapping(): return { diff --git a/heat/scaling/lbutils.py b/heat/scaling/lbutils.py index f1c0696fb7..9368881f35 100644 --- a/heat/scaling/lbutils.py +++ b/heat/scaling/lbutils.py @@ -30,8 +30,7 @@ def reconfigure_loadbalancers(load_balancers, id_list): lb.context).data) if 'Instances' in lb.properties_schema: props['Instances'] = id_list - elif 'members' in lb.properties_schema: - props['members'] = id_list + # TODO(tkajinam): We need to add support for Octavia resources else: raise exception.Error( _("Unsupported resource '%s' in LoadBalancerNames") % lb.name) diff --git a/heat/tests/autoscaling/test_lbutils.py b/heat/tests/autoscaling/test_lbutils.py index 82ef9cabe5..f389c352f4 100644 --- a/heat/tests/autoscaling/test_lbutils.py +++ b/heat/tests/autoscaling/test_lbutils.py @@ -25,10 +25,6 @@ from heat.tests import utils lb_stack = ''' heat_template_version: 2013-05-23 resources: - neutron_lb_1: - type: Mock::Neutron::LB - neutron_lb_2: - type: Mock::Neutron::LB aws_lb_1: type: Mock::AWS::LB aws_lb_2: @@ -38,17 +34,6 @@ resources: ''' -class MockedNeutronLB(generic_resource.GenericResource): - properties_schema = { - 'members': properties.Schema( - properties.Schema.LIST, - update_allowed=True) - } - - def handle_update(self, json_snippet, tmpl_diff, prop_diff): - return - - class MockedAWSLB(generic_resource.GenericResource): properties_schema = { 'Instances': properties.Schema( @@ -67,7 +52,6 @@ class LBUtilsTest(common.HeatTestCase): def setUp(self): super(LBUtilsTest, self).setUp() - resource._register_class('Mock::Neutron::LB', MockedNeutronLB) resource._register_class('Mock::AWS::LB', MockedAWSLB) resource._register_class('Mock::Not::LB', generic_resource.GenericResource) @@ -94,27 +78,6 @@ class LBUtilsTest(common.HeatTestCase): lb2.handle_update.assert_called_with(mock.ANY, mock.ANY, prop_diff) - def test_reload_neutron_lb(self): - id_list = ['ID1', 'ID2', 'ID3'] - - lb1 = self.stack['neutron_lb_1'] - lb2 = self.stack['neutron_lb_2'] - lb1.action = mock.Mock(return_value=lb1.CREATE) - lb2.action = mock.Mock(return_value=lb2.CREATE) - - lb1.handle_update = mock.Mock() - lb2.handle_update = mock.Mock() - - prop_diff = {'members': id_list} - - lbutils.reconfigure_loadbalancers([lb1, lb2], id_list) - - # For verification's purpose, we just check the prop_diff - lb1.handle_update.assert_called_with(mock.ANY, mock.ANY, - prop_diff) - lb2.handle_update.assert_called_with(mock.ANY, mock.ANY, - prop_diff) - def test_reload_non_lb(self): id_list = ['ID1', 'ID2', 'ID3'] non_lb = self.stack['non_lb'] diff --git a/heat/tests/clients/test_neutron_client.py b/heat/tests/clients/test_neutron_client.py index bc470b79bc..30e38034da 100644 --- a/heat/tests/clients/test_neutron_client.py +++ b/heat/tests/clients/test_neutron_client.py @@ -178,9 +178,6 @@ class NeutronConstraintsValidate(common.HeatTestCase): class NeutronProviderConstraintsValidate(common.HeatTestCase): scenarios = [ - ('validate_lbaasv1', - dict(constraint_class=nc.LBaasV1ProviderConstraint, - service_type='LOADBALANCER')), ('validate_lbaasv2', dict(constraint_class=lc.LBaasV2ProviderConstraint, service_type='LOADBALANCERV2')) diff --git a/heat/tests/openstack/heat/test_instance_group.py b/heat/tests/openstack/heat/test_instance_group.py index c6c84a54ae..7aed210a39 100644 --- a/heat/tests/openstack/heat/test_instance_group.py +++ b/heat/tests/openstack/heat/test_instance_group.py @@ -17,7 +17,6 @@ from unittest import mock from heat.common import exception from heat.common import grouputils from heat.common import template_format -from heat.engine.clients.os import neutron from heat.engine import resource from heat.engine.resources.openstack.heat import instance_group as instgrp from heat.engine import rsrc_defn @@ -264,70 +263,6 @@ class LoadbalancerReloadTest(common.HeatTestCase): self.check_mocks(group, mocks) lb.update.assert_called_once_with(expected) - def test_members(self): - self.patchobject(neutron.NeutronClientPlugin, 'has_extension', - return_value=True) - - t = template_format.parse(inline_templates.as_template) - t['Resources']['ElasticLoadBalancer'] = { - 'Type': 'OS::Neutron::LoadBalancer', - 'Properties': { - 'protocol_port': 8080, - } - } - stack = utils.parse_stack(t) - - lb = stack['ElasticLoadBalancer'] - lb.update = mock.Mock(return_value=None) - - defn = rsrc_defn.ResourceDefinition( - 'asg', 'OS::Heat::InstanceGroup', - {'Size': 2, - 'AvailabilityZones': ['zoneb'], - "LaunchConfigurationName": "LaunchConfig", - "LoadBalancerNames": ["ElasticLoadBalancer"]}) - group = instgrp.InstanceGroup('asg', defn, stack) - - mocks = self.setup_mocks(group, ['aaaa', 'bbb']) - expected = rsrc_defn.ResourceDefinition( - 'ElasticLoadBalancer', - 'OS::Neutron::LoadBalancer', - {'protocol_port': 8080, - 'members': ['aaaa', 'bbb']}) - - group._lb_reload() - self.check_mocks(group, mocks) - lb.update.assert_called_once_with(expected) - - def test_lb_reload_invalid_resource(self): - t = template_format.parse(inline_templates.as_template) - t['Resources']['ElasticLoadBalancer'] = { - 'Type': 'AWS::EC2::Volume', - 'Properties': { - 'AvailabilityZone': 'nova' - } - } - stack = utils.parse_stack(t) - - lb = stack['ElasticLoadBalancer'] - lb.update = mock.Mock(return_value=None) - - defn = rsrc_defn.ResourceDefinition( - 'asg', 'OS::Heat::InstanceGroup', - {'Size': 2, - 'AvailabilityZones': ['zoneb'], - "LaunchConfigurationName": "LaunchConfig", - "LoadBalancerNames": ["ElasticLoadBalancer"]}) - group = instgrp.InstanceGroup('asg', defn, stack) - - self.setup_mocks(group, ['aaaa', 'bbb']) - error = self.assertRaises(exception.Error, - group._lb_reload) - self.assertEqual( - "Unsupported resource 'ElasticLoadBalancer' in " - "LoadBalancerNames", - str(error)) - def test_lb_reload_static_resolve(self): t = template_format.parse(inline_templates.as_template) properties = t['Resources']['ElasticLoadBalancer']['Properties'] diff --git a/heat/tests/openstack/neutron/test_neutron_loadbalancer.py b/heat/tests/openstack/neutron/test_neutron_loadbalancer.py deleted file mode 100644 index 388c8056e3..0000000000 --- a/heat/tests/openstack/neutron/test_neutron_loadbalancer.py +++ /dev/null @@ -1,1093 +0,0 @@ -# -# 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. - -from unittest import mock - -from neutronclient.common import exceptions -from neutronclient.neutron import v2_0 as neutronV20 -from neutronclient.v2_0 import client as neutronclient -from oslo_config import cfg - -from heat.common import exception -from heat.common.i18n import _ -from heat.common import template_format -from heat.engine.clients.os import neutron -from heat.engine.clients.os import nova -from heat.engine.resources.openstack.neutron import loadbalancer -from heat.engine import scheduler -from heat.tests import common -from heat.tests.openstack.nova import fakes as fakes_nova -from heat.tests import utils - - -health_monitor_template = ''' -heat_template_version: 2015-04-30 -description: Template to test load balancer resources -resources: - monitor: - type: OS::Neutron::HealthMonitor - properties: - type: HTTP - delay: 3 - max_retries: 5 - timeout: 10 -''' - -pool_template_with_vip_subnet = ''' -heat_template_version: 2015-04-30 -description: Template to test load balancer resources -resources: - pool: - type: OS::Neutron::Pool - properties: - protocol: HTTP - subnet: sub123 - lb_method: ROUND_ROBIN - vip: - protocol_port: 80 - subnet: sub9999 -''' - -pool_template_with_provider = ''' -heat_template_version: 2015-04-30 -description: Template to test load balancer resources -resources: - pool: - type: OS::Neutron::Pool - properties: - protocol: HTTP - subnet: sub123 - lb_method: ROUND_ROBIN - provider: test_prov - vip: - protocol_port: 80 - -''' - -pool_template = ''' -heat_template_version: 2015-04-30 -description: Template to test load balancer resources -resources: - pool: - type: OS::Neutron::Pool - properties: - protocol: HTTP - subnet: sub123 - lb_method: ROUND_ROBIN - vip: - protocol_port: 80 - -''' - -pool_template_deprecated = pool_template.replace('subnet', 'subnet_id') - -member_template = ''' -heat_template_version: 2015-04-30 -description: Template to test load balancer member -resources: - member: - type: OS::Neutron::PoolMember - properties: - protocol_port: 8080 - pool_id: pool123 - address: 1.2.3.4 -''' - -lb_template = ''' -heat_template_version: 2015-04-30 -description: Template to test load balancer resources -resources: - lb: - type: OS::Neutron::LoadBalancer - properties: - protocol_port: 8080 - pool_id: pool123 - members: [1234] -''' - - -pool_with_session_persistence_template = ''' -heat_template_version: 2015-04-30 -description: Template to test load balancer resources -resources: - pool: - type: OS::Neutron::Pool - properties: - protocol: HTTP - subnet: sub123 - lb_method: ROUND_ROBIN - vip: - protocol_port: 80 - session_persistence: - type: APP_COOKIE - cookie_name: cookie -''' - - -pool_with_health_monitors_template = ''' -heat_template_version: 2015-04-30 -description: Template to test load balancer resources -resources: - monitor1: - type: OS::Neutron::HealthMonitor - properties: - type: HTTP - delay: 3 - max_retries: 5 - timeout: 10 - - monitor2: - type: OS::Neutron::HealthMonitor - properties: - type: HTTP - delay: 3 - max_retries: 5 - timeout: 10 - - pool: - type: OS::Neutron::Pool - properties: - protocol: HTTP - subnet_id: sub123 - lb_method: ROUND_ROBIN - vip: - protocol_port: 80 - monitors: - - {get_resource: monitor1} - - {get_resource: monitor2} -''' - - -class HealthMonitorTest(common.HeatTestCase): - - def setUp(self): - super(HealthMonitorTest, self).setUp() - mockclient = mock.Mock(spec=neutronclient.Client) - self.patchobject(neutronclient, 'Client', return_value=mockclient) - self.mock_create = mockclient.create_health_monitor - self.mock_delete = mockclient.delete_health_monitor - self.mock_show = mockclient.show_health_monitor - self.mock_update = mockclient.update_health_monitor - self.patchobject(neutron.NeutronClientPlugin, 'has_extension', - return_value=True) - self.create_snippet = { - 'health_monitor': { - 'delay': 3, 'max_retries': 5, 'type': u'HTTP', - 'timeout': 10, 'admin_state_up': True}} - - def create_health_monitor(self): - self.mock_create.return_value = {'health_monitor': {'id': '5678'}} - snippet = template_format.parse(health_monitor_template) - self.stack = utils.parse_stack(snippet) - self.tmpl = snippet - resource_defns = self.stack.t.resource_definitions(self.stack) - return loadbalancer.HealthMonitor( - 'monitor', resource_defns['monitor'], self.stack) - - def test_create(self): - rsrc = self.create_health_monitor() - scheduler.TaskRunner(rsrc.create)() - self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - self.mock_create.assert_called_once_with(self.create_snippet) - - def test_create_failed(self): - self.mock_create.side_effect = exceptions.NeutronClientException() - snippet = template_format.parse(health_monitor_template) - self.stack = utils.parse_stack(snippet) - resource_defns = self.stack.t.resource_definitions(self.stack) - rsrc = loadbalancer.HealthMonitor( - 'monitor', resource_defns['monitor'], self.stack) - error = self.assertRaises(exception.ResourceFailure, - scheduler.TaskRunner(rsrc.create)) - self.assertEqual( - 'NeutronClientException: resources.monitor: ' - 'An unknown exception occurred.', - str(error)) - self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state) - self.mock_create.assert_called_once_with(self.create_snippet) - - def test_delete(self): - self.mock_delete.return_value = None - self.mock_show.side_effect = exceptions.NeutronClientException( - status_code=404) - rsrc = self.create_health_monitor() - scheduler.TaskRunner(rsrc.create)() - scheduler.TaskRunner(rsrc.delete)() - self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) - self.mock_create.assert_called_once_with(self.create_snippet) - self.mock_delete.assert_called_once_with('5678') - - def test_delete_already_gone(self): - self.mock_delete.side_effect = exceptions.NeutronClientException( - status_code=404) - rsrc = self.create_health_monitor() - scheduler.TaskRunner(rsrc.create)() - scheduler.TaskRunner(rsrc.delete)() - self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) - self.mock_create.assert_called_once_with(self.create_snippet) - self.mock_delete.assert_called_once_with('5678') - - def test_delete_failed(self): - self.mock_delete.side_effect = exceptions.NeutronClientException( - status_code=400) - rsrc = self.create_health_monitor() - scheduler.TaskRunner(rsrc.create)() - error = self.assertRaises(exception.ResourceFailure, - scheduler.TaskRunner(rsrc.delete)) - self.assertEqual( - 'NeutronClientException: resources.monitor: ' - 'An unknown exception occurred.', - str(error)) - self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state) - self.mock_create.assert_called_once_with(self.create_snippet) - self.mock_delete.assert_called_once_with('5678') - - def test_attribute(self): - rsrc = self.create_health_monitor() - self.mock_show.return_value = { - 'health_monitor': {'admin_state_up': True, 'delay': 3}} - scheduler.TaskRunner(rsrc.create)() - self.assertIs(True, rsrc.FnGetAtt('admin_state_up')) - self.assertEqual(3, rsrc.FnGetAtt('delay')) - self.mock_create.assert_called_once_with(self.create_snippet) - self.mock_show.assert_called_with('5678') - - def test_attribute_failed(self): - rsrc = self.create_health_monitor() - scheduler.TaskRunner(rsrc.create)() - error = self.assertRaises(exception.InvalidTemplateAttribute, - rsrc.FnGetAtt, 'subnet_id') - self.assertEqual( - 'The Referenced Attribute (monitor subnet_id) is incorrect.', - str(error)) - self.mock_create.assert_called_once_with(self.create_snippet) - - def test_update(self): - rsrc = self.create_health_monitor() - scheduler.TaskRunner(rsrc.create)() - props = self.tmpl['resources']['monitor']['properties'].copy() - props['delay'] = 10 - update_template = rsrc.t.freeze(properties=props) - scheduler.TaskRunner(rsrc.update, update_template)() - self.mock_create.assert_called_once_with(self.create_snippet) - self.mock_update.assert_called_once_with( - '5678', {'health_monitor': {'delay': 10}}) - - -class PoolTest(common.HeatTestCase): - - def setUp(self): - super(PoolTest, self).setUp() - mockclient = mock.Mock(spec=neutronclient.Client) - self.patchobject(neutronclient, 'Client', return_value=mockclient) - self.mock_create = mockclient.create_pool - self.mock_delete = mockclient.delete_pool - self.mock_show = mockclient.show_pool - self.mock_update = mockclient.update_pool - self.mock_associate = mockclient.associate_health_monitor - self.mock_disassociate = mockclient.disassociate_health_monitor - self.mock_create_vip = mockclient.create_vip - self.mock_delete_vip = mockclient.delete_vip - self.mock_show_vip = mockclient.show_vip - - def finder(client, resource_type, name, cmd_resource): - return name - - self.mock_finder = self.patchobject( - neutronV20, 'find_resourceid_by_name_or_id', - side_effect=finder) - self.patchobject(neutron.NeutronClientPlugin, 'has_extension', - return_value=True) - - def create_pool(self, resolve_neutron=True, with_vip_subnet=False): - if resolve_neutron: - if with_vip_subnet: - snippet = template_format.parse(pool_template_with_vip_subnet) - else: - snippet = template_format.parse(pool_template) - else: - snippet = template_format.parse(pool_template_deprecated) - self.stack = utils.parse_stack(snippet) - self.tmpl = snippet - self.mock_create.return_value = {'pool': {'id': '5678'}} - self.mock_show.return_value = {'pool': {'status': 'ACTIVE'}} - self.mock_show_vip.return_value = {'vip': {'status': 'ACTIVE'}} - self.pool_create_snippet = { - 'pool': { - 'subnet_id': 'sub123', 'protocol': u'HTTP', - 'name': utils.PhysName(self.stack.name, 'pool'), - 'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}} - self.vip_create_snippet = { - 'vip': { - 'protocol': u'HTTP', 'name': 'pool.vip', - 'admin_state_up': True, 'subnet_id': u'sub123', - 'pool_id': '5678', 'protocol_port': 80}} - - if with_vip_subnet: - self.stub_SubnetConstraint_validate() - self.vip_create_snippet['vip']['subnet_id'] = 'sub9999' - self.mock_create_vip.return_value = {'vip': {'id': 'xyz'}} - resource_defns = self.stack.t.resource_definitions(self.stack) - return loadbalancer.Pool( - 'pool', resource_defns['pool'], self.stack) - - def _test_create(self, resolve_neutron=True, - with_vip_subnet=False): - rsrc = self.create_pool(resolve_neutron, - with_vip_subnet) - scheduler.TaskRunner(rsrc.create)() - self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - self.mock_create.assert_called_once_with(self.pool_create_snippet) - self.mock_create_vip.assert_called_once_with(self.vip_create_snippet) - - def test_create(self): - self._test_create() - - def test_create_deprecated(self): - self._test_create(resolve_neutron=False, - with_vip_subnet=False) - - def test_create_with_vip_subnet(self): - self._test_create(resolve_neutron=True, - with_vip_subnet=True) - - def test_create_pending(self): - snippet = template_format.parse(pool_template) - self.stack = utils.parse_stack(snippet) - self.mock_create.return_value = {'pool': {'id': '5678'}} - self.mock_create_vip.return_value = {'vip': {'id': 'xyz'}} - self.mock_show.side_effect = [ - {'pool': {'status': 'PENDING_CREATE'}}, - {'pool': {'status': 'ACTIVE'}}, - {'pool': {'status': 'ACTIVE'}}] - self.mock_show_vip.side_effect = [ - {'vip': {'status': 'PENDING_CREATE'}}, - {'vip': {'status': 'ACTIVE'}}] - pool_create_snippet = { - 'pool': { - 'subnet_id': 'sub123', 'protocol': u'HTTP', - 'name': utils.PhysName(self.stack.name, 'pool'), - 'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}} - vip_create_snippet = { - 'vip': { - 'protocol': u'HTTP', 'name': 'pool.vip', - 'admin_state_up': True, 'subnet_id': u'sub123', - 'pool_id': '5678', 'protocol_port': 80}} - - resource_defns = self.stack.t.resource_definitions(self.stack) - rsrc = loadbalancer.Pool( - 'pool', resource_defns['pool'], self.stack) - scheduler.TaskRunner(rsrc.create)() - self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - - self.mock_create.assert_called_once_with(pool_create_snippet) - self.mock_create_vip.assert_called_once_with(vip_create_snippet) - self.mock_show.assert_called_with('5678') - self.mock_show_vip.assert_called_with('xyz') - - def test_create_failed_error_status(self): - cfg.CONF.set_override('action_retry_limit', 0) - - snippet = template_format.parse(pool_template) - self.stack = utils.parse_stack(snippet) - pool_create_snippet = { - 'pool': { - 'subnet_id': 'sub123', 'protocol': u'HTTP', - 'name': utils.PhysName(self.stack.name, 'pool'), - 'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}} - vip_create_snippet = { - 'vip': { - 'protocol': u'HTTP', 'name': 'pool.vip', - 'admin_state_up': True, 'subnet_id': u'sub123', - 'pool_id': '5678', 'protocol_port': 80}} - - self.mock_create.return_value = {'pool': {'id': '5678'}} - self.mock_create_vip.return_value = {'vip': {'id': 'xyz'}} - self.mock_show.return_value = { - 'pool': {'status': 'ERROR', 'name': '5678'}} - resource_defns = self.stack.t.resource_definitions(self.stack) - rsrc = loadbalancer.Pool( - 'pool', resource_defns['pool'], self.stack) - error = self.assertRaises(exception.ResourceFailure, - scheduler.TaskRunner(rsrc.create)) - self.assertEqual( - 'ResourceInError: resources.pool: ' - 'Went to status ERROR due to "error in pool"', - str(error)) - self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state) - self.mock_create.assert_called_once_with(pool_create_snippet) - self.mock_create_vip.assert_called_once_with(vip_create_snippet) - self.mock_show.assert_called_once_with('5678') - - def test_create_failed_unexpected_vip_status(self): - snippet = template_format.parse(pool_template) - self.stack = utils.parse_stack(snippet) - self.mock_create.return_value = {'pool': {'id': '5678'}} - self.mock_create_vip.return_value = {'vip': {'id': 'xyz'}} - self.mock_show.return_value = { - 'pool': {'status': 'ACTIVE', 'name': '5678'}} - self.mock_show_vip.return_value = { - 'vip': {'status': 'SOMETHING', 'name': 'xyz'}} - pool_create_snippet = { - 'pool': { - 'subnet_id': 'sub123', 'protocol': u'HTTP', - 'name': utils.PhysName(self.stack.name, 'pool'), - 'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}} - vip_create_snippet = { - 'vip': { - 'protocol': u'HTTP', 'name': 'pool.vip', - 'admin_state_up': True, 'subnet_id': u'sub123', - 'pool_id': '5678', 'protocol_port': 80}} - - resource_defns = self.stack.t.resource_definitions(self.stack) - rsrc = loadbalancer.Pool( - 'pool', resource_defns['pool'], self.stack) - error = self.assertRaises(exception.ResourceFailure, - scheduler.TaskRunner(rsrc.create)) - self.assertEqual('ResourceUnknownStatus: resources.pool: ' - 'Pool creation failed due to ' - 'vip - Unknown status SOMETHING due to "Unknown"', - str(error)) - self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state) - self.mock_create.assert_called_once_with(pool_create_snippet) - self.mock_create_vip.assert_called_once_with(vip_create_snippet) - self.mock_show.assert_called_once_with('5678') - self.mock_show_vip.assert_called_once_with('xyz') - - def test_create_failed(self): - snippet = template_format.parse(pool_template) - self.stack = utils.parse_stack(snippet) - pool_create_snippet = { - 'pool': { - 'subnet_id': 'sub123', 'protocol': u'HTTP', - 'name': utils.PhysName(self.stack.name, 'pool'), - 'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}} - - self.mock_create.side_effect = exceptions.NeutronClientException() - resource_defns = self.stack.t.resource_definitions(self.stack) - rsrc = loadbalancer.Pool( - 'pool', resource_defns['pool'], self.stack) - error = self.assertRaises(exception.ResourceFailure, - scheduler.TaskRunner(rsrc.create)) - self.assertEqual( - 'NeutronClientException: resources.pool: ' - 'An unknown exception occurred.', - str(error)) - self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state) - self.mock_create.assert_called_once_with(pool_create_snippet) - - def test_create_with_session_persistence(self): - snippet = template_format.parse(pool_with_session_persistence_template) - self.stack = utils.parse_stack(snippet) - self.mock_create.return_value = {'pool': {'id': '5678'}} - self.mock_create_vip.return_value = {'vip': {'id': 'xyz'}} - self.mock_show.return_value = { - 'pool': {'status': 'ACTIVE', 'name': '5678'}} - self.mock_show_vip.return_value = { - 'vip': {'status': 'ACTIVE', 'name': 'xyz'}} - pool_create_snippet = { - 'pool': { - 'subnet_id': 'sub123', 'protocol': u'HTTP', - 'name': utils.PhysName(self.stack.name, 'pool'), - 'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}} - vip_create_snippet = { - 'vip': { - 'protocol': u'HTTP', 'name': 'pool.vip', - 'admin_state_up': True, 'subnet_id': u'sub123', - 'pool_id': '5678', 'protocol_port': 80, - 'session_persistence': { - 'type': 'APP_COOKIE', - 'cookie_name': 'cookie'}}} - - resource_defns = self.stack.t.resource_definitions(self.stack) - rsrc = loadbalancer.Pool( - 'pool', resource_defns['pool'], self.stack) - scheduler.TaskRunner(rsrc.create)() - self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - self.mock_create.assert_called_once_with(pool_create_snippet) - self.mock_create_vip.assert_called_once_with(vip_create_snippet) - self.mock_show.assert_called_once_with('5678') - self.mock_show_vip.assert_called_once_with('xyz') - - def test_create_pool_with_provider(self): - snippet = template_format.parse(pool_template_with_provider) - self.stub_ProviderConstraint_validate() - self.stack = utils.parse_stack(snippet) - self.mock_create.return_value = {'pool': {'id': '5678'}} - self.mock_create_vip.return_value = {'vip': {'id': 'xyz'}} - self.mock_show.return_value = { - 'pool': {'status': 'ACTIVE', 'provider': 'test_prov'}} - self.mock_show_vip.return_value = { - 'vip': {'status': 'ACTIVE', 'name': 'xyz'}} - pool_create_snippet = { - 'pool': { - 'subnet_id': 'sub123', 'protocol': u'HTTP', - 'name': utils.PhysName(self.stack.name, 'pool'), - 'lb_method': 'ROUND_ROBIN', 'admin_state_up': True, - 'provider': 'test_prov'}} - vip_create_snippet = { - 'vip': { - 'protocol': u'HTTP', 'name': 'pool.vip', - 'admin_state_up': True, 'subnet_id': u'sub123', - 'pool_id': '5678', 'protocol_port': 80}} - - resource_defns = self.stack.t.resource_definitions(self.stack) - rsrc = loadbalancer.Pool( - 'pool', resource_defns['pool'], self.stack) - - scheduler.TaskRunner(rsrc.create)() - self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - self.assertEqual("test_prov", rsrc.FnGetAtt("provider")) - self.mock_create.assert_called_once_with(pool_create_snippet) - self.mock_create_vip.assert_called_once_with(vip_create_snippet) - self.mock_show_vip.assert_called_once_with('xyz') - self.mock_show.assert_called_with('5678') - - def test_failing_validation_with_session_persistence(self): - msg = _('Property cookie_name is required, when ' - 'session_persistence type is set to APP_COOKIE.') - snippet = template_format.parse(pool_with_session_persistence_template) - pool = snippet['resources']['pool'] - persistence = pool['properties']['vip']['session_persistence'] - - # When persistence type is set to APP_COOKIE, cookie_name is required - persistence['type'] = 'APP_COOKIE' - persistence['cookie_name'] = None - - self.stack = utils.parse_stack(snippet) - resource_defns = self.stack.t.resource_definitions(self.stack) - resource = loadbalancer.Pool('pool', resource_defns['pool'], - self.stack) - - error = self.assertRaises(exception.StackValidationFailed, - resource.validate) - self.assertEqual(msg, str(error)) - - def test_validation_not_failing_without_session_persistence(self): - snippet = template_format.parse(pool_template) - - self.stack = utils.parse_stack(snippet) - resource_defns = self.stack.t.resource_definitions(self.stack) - resource = loadbalancer.Pool('pool', resource_defns['pool'], - self.stack) - self.stub_SubnetConstraint_validate() - self.assertIsNone(resource.validate()) - - def test_properties_are_prepared_for_session_persistence(self): - snippet = template_format.parse(pool_with_session_persistence_template) - pool = snippet['resources']['pool'] - persistence = pool['properties']['vip']['session_persistence'] - - # change persistence type to HTTP_COOKIE that not require cookie_name - persistence['type'] = 'HTTP_COOKIE' - del persistence['cookie_name'] - - self.stack = utils.parse_stack(snippet) - - self.mock_create.return_value = {'pool': {'id': '5678'}} - self.mock_create_vip.return_value = {'vip': {'id': 'xyz'}} - self.mock_show.return_value = { - 'pool': {'status': 'ACTIVE', 'name': '5678'}} - self.mock_show_vip.return_value = { - 'vip': {'status': 'ACTIVE', 'name': 'xyz'}} - pool_create_snippet = { - 'pool': { - 'subnet_id': 'sub123', 'protocol': u'HTTP', - 'name': utils.PhysName(self.stack.name, 'pool'), - 'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}} - vip_create_snippet = { - 'vip': { - 'protocol': u'HTTP', 'name': 'pool.vip', - 'admin_state_up': True, 'subnet_id': u'sub123', - 'pool_id': '5678', 'protocol_port': 80, - 'session_persistence': {'type': 'HTTP_COOKIE'}}} - - resource_defns = self.stack.t.resource_definitions(self.stack) - resource = loadbalancer.Pool('pool', resource_defns['pool'], - self.stack) - - # assert that properties contain cookie_name property with None value - persistence = resource.properties['vip']['session_persistence'] - self.assertIn('cookie_name', persistence) - self.assertIsNone(persistence['cookie_name']) - - scheduler.TaskRunner(resource.create)() - self.assertEqual((resource.CREATE, resource.COMPLETE), resource.state) - self.mock_create.assert_called_once_with(pool_create_snippet) - self.mock_create_vip.assert_called_once_with(vip_create_snippet) - self.mock_show.assert_called_once_with('5678') - self.mock_show_vip.assert_called_once_with('xyz') - - def test_delete(self): - rsrc = self.create_pool() - scheduler.TaskRunner(rsrc.create)() - self.mock_delete.return_value = None - self.mock_delete_vip.return_value = None - self.mock_show_vip.side_effect = exceptions.NeutronClientException( - status_code=404) - self.mock_show.side_effect = exceptions.NeutronClientException( - status_code=404) - scheduler.TaskRunner(rsrc.delete)() - self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) - self.mock_delete.assert_called_once_with('5678') - self.mock_delete_vip.assert_called_once_with('xyz') - self.mock_show.assert_called_with('5678') - self.assertEqual(2, self.mock_show.call_count) - self.mock_show_vip.assert_called_with('xyz') - self.assertEqual(2, self.mock_show_vip.call_count) - - def test_delete_already_gone(self): - self.mock_delete_vip.side_effect = exceptions.NeutronClientException( - status_code=404) - self.mock_delete.side_effect = exceptions.NeutronClientException( - status_code=404) - - rsrc = self.create_pool() - scheduler.TaskRunner(rsrc.create)() - scheduler.TaskRunner(rsrc.delete)() - self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) - self.mock_delete.assert_called_once_with('5678') - self.mock_delete_vip.assert_called_once_with('xyz') - - def test_delete_vip_failed(self): - self.mock_delete_vip.side_effect = exceptions.NeutronClientException( - status_code=400) - - rsrc = self.create_pool() - scheduler.TaskRunner(rsrc.create)() - error = self.assertRaises(exception.ResourceFailure, - scheduler.TaskRunner(rsrc.delete)) - self.assertEqual( - 'NeutronClientException: resources.pool: ' - 'An unknown exception occurred.', - str(error)) - self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state) - self.mock_delete_vip.assert_called_once_with('xyz') - self.mock_delete.assert_not_called() - - def test_delete_failed(self): - self.mock_delete_vip.side_effect = exceptions.NeutronClientException( - status_code=404) - self.mock_delete.side_effect = exceptions.NeutronClientException( - status_code=400) - - rsrc = self.create_pool() - scheduler.TaskRunner(rsrc.create)() - error = self.assertRaises(exception.ResourceFailure, - scheduler.TaskRunner(rsrc.delete)) - self.assertEqual( - 'NeutronClientException: resources.pool: ' - 'An unknown exception occurred.', - str(error)) - self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state) - self.mock_delete.assert_called_once_with('5678') - self.mock_delete_vip.assert_called_once_with('xyz') - - def test_attribute(self): - rsrc = self.create_pool() - scheduler.TaskRunner(rsrc.create)() - self.mock_show.return_value = { - 'pool': {'admin_state_up': True, 'lb_method': 'ROUND_ROBIN'}} - self.assertIs(True, rsrc.FnGetAtt('admin_state_up')) - self.assertEqual('ROUND_ROBIN', rsrc.FnGetAtt('lb_method')) - - def test_vip_attribute(self): - rsrc = self.create_pool() - scheduler.TaskRunner(rsrc.create)() - self.mock_show_vip.return_value = { - 'vip': {'address': '10.0.0.3', 'name': 'xyz'}} - self.assertEqual({'address': '10.0.0.3', 'name': 'xyz'}, - rsrc.FnGetAtt('vip')) - - def test_attribute_failed(self): - rsrc = self.create_pool() - scheduler.TaskRunner(rsrc.create)() - error = self.assertRaises(exception.InvalidTemplateAttribute, - rsrc.FnGetAtt, 'net_id') - self.assertEqual( - 'The Referenced Attribute (pool net_id) is incorrect.', - str(error)) - - def test_update(self): - rsrc = self.create_pool() - scheduler.TaskRunner(rsrc.create)() - props = self.tmpl['resources']['pool']['properties'].copy() - props['admin_state_up'] = False - update_template = rsrc.t.freeze(properties=props) - scheduler.TaskRunner(rsrc.update, update_template)() - self.mock_update.assert_called_once_with( - '5678', {'pool': {'admin_state_up': False}}) - - def test_update_monitors(self): - snippet = template_format.parse(pool_template) - self.stack = utils.parse_stack(snippet) - self.mock_create.return_value = {'pool': {'id': '5678'}} - self.mock_create_vip.return_value = {'vip': {'id': 'xyz'}} - pool_create_snippet = { - 'pool': { - 'subnet_id': 'sub123', 'protocol': u'HTTP', - 'name': utils.PhysName(self.stack.name, 'pool'), - 'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}} - vip_create_snippet = { - 'vip': { - 'protocol': u'HTTP', 'name': 'pool.vip', - 'admin_state_up': True, 'subnet_id': u'sub123', - 'pool_id': '5678', 'protocol_port': 80}} - - self.mock_show.return_value = { - 'pool': {'status': 'ACTIVE', 'name': '5678'}} - self.mock_show_vip.return_value = { - 'vip': {'status': 'ACTIVE', 'name': 'xyz'}} - - snippet['resources']['pool']['properties']['monitors'] = [ - 'mon123', 'mon456'] - resource_defns = self.stack.t.resource_definitions(self.stack) - rsrc = loadbalancer.Pool('pool', resource_defns['pool'], self.stack) - scheduler.TaskRunner(rsrc.create)() - - props = snippet['resources']['pool']['properties'].copy() - props['monitors'] = ['mon123', 'mon789'] - update_template = rsrc.t.freeze(properties=props) - scheduler.TaskRunner(rsrc.update, update_template)() - associate_calls = [mock.call('5678', - {'health_monitor': {'id': 'mon123'}}), - mock.call('5678', - {'health_monitor': {'id': 'mon456'}}), - mock.call('5678', - {'health_monitor': {'id': 'mon789'}})] - self.mock_associate.assert_has_calls(associate_calls) - self.assertEqual(3, self.mock_associate.call_count) - self.mock_disassociate.assert_called_once_with('5678', 'mon456') - self.mock_create.assert_called_once_with(pool_create_snippet) - self.mock_create_vip.assert_called_once_with(vip_create_snippet) - self.mock_show.assert_called_once_with('5678') - self.mock_show_vip.assert_called_once_with('xyz') - - -class PoolMemberTest(common.HeatTestCase): - - def setUp(self): - super(PoolMemberTest, self).setUp() - self.fc = fakes_nova.FakeClient() - self.mc = mock.Mock(spec=neutronclient.Client) - self.patchobject(neutronclient, 'Client', return_value=self.mc) - self.patchobject(neutron.NeutronClientPlugin, 'has_extension', - return_value=True) - - def create_member(self): - self.mc.create_member.return_value = {'member': {'id': 'member5678'}} - snippet = template_format.parse(member_template) - self.stack = utils.parse_stack(snippet) - self.tmpl = snippet - resource_defns = self.stack.t.resource_definitions(self.stack) - result = loadbalancer.PoolMember( - 'member', resource_defns['member'], self.stack) - return result - - def validate_create_member(self): - self.mc.create_member.assert_called_once_with({ - 'member': { - 'pool_id': 'pool123', 'protocol_port': 8080, - 'address': '1.2.3.4', 'admin_state_up': True}} - ) - - def test_create(self): - rsrc = self.create_member() - - scheduler.TaskRunner(rsrc.create)() - self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - self.assertEqual('member5678', rsrc.resource_id) - self.validate_create_member() - - def test_create_optional_parameters(self): - self.mc.create_member.return_value = {'member': {'id': 'member5678'}} - snippet = template_format.parse(member_template) - snippet['resources']['member']['properties']['admin_state_up'] = False - snippet['resources']['member']['properties']['weight'] = 100 - self.stack = utils.parse_stack(snippet) - resource_defns = self.stack.t.resource_definitions(self.stack) - rsrc = loadbalancer.PoolMember( - 'member', resource_defns['member'], self.stack) - - scheduler.TaskRunner(rsrc.create)() - self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - self.assertEqual('member5678', rsrc.resource_id) - self.mc.create_member.assert_called_once_with({ - 'member': { - 'pool_id': 'pool123', 'protocol_port': 8080, - 'weight': 100, 'admin_state_up': False, - 'address': '1.2.3.4'}} - ) - - def test_attribute(self): - rsrc = self.create_member() - self.mc.show_member.return_value = { - 'member': {'admin_state_up': True, 'weight': 5}} - scheduler.TaskRunner(rsrc.create)() - self.assertIs(True, rsrc.FnGetAtt('admin_state_up')) - self.assertEqual(5, rsrc.FnGetAtt('weight')) - self.mc.show_member.assert_called_with('member5678') - self.validate_create_member() - - def test_update(self): - rsrc = self.create_member() - scheduler.TaskRunner(rsrc.create)() - - props = self.tmpl['resources']['member']['properties'].copy() - props['pool_id'] = 'pool456' - update_template = rsrc.t.freeze(properties=props) - - scheduler.TaskRunner(rsrc.update, update_template)() - self.mc.update_member.assert_called_once_with( - 'member5678', {'member': {'pool_id': 'pool456'}}) - self.validate_create_member() - - def test_delete(self): - rsrc = self.create_member() - self.mc.show_member.side_effect = [exceptions.NeutronClientException( - status_code=404)] - - scheduler.TaskRunner(rsrc.create)() - scheduler.TaskRunner(rsrc.delete)() - self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) - self.mc.delete_member.assert_called_once_with(u'member5678') - self.mc.show_member.assert_called_once_with(u'member5678') - self.validate_create_member() - - def test_delete_missing_member(self): - rsrc = self.create_member() - self.mc.delete_member.side_effect = [exceptions.NeutronClientException( - status_code=404)] - - scheduler.TaskRunner(rsrc.create)() - scheduler.TaskRunner(rsrc.delete)() - self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) - self.validate_create_member() - self.mc.delete_member.assert_called_once_with(u'member5678') - - -class LoadBalancerTest(common.HeatTestCase): - - def setUp(self): - super(LoadBalancerTest, self).setUp() - self.fc = fakes_nova.FakeClient() - - self.mc = mock.Mock(spec=neutronclient.Client) - self.patchobject(neutronclient, 'Client', return_value=self.mc) - self.patchobject(nova.NovaClientPlugin, 'client') - self.patchobject(neutron.NeutronClientPlugin, 'has_extension', - return_value=True) - - def create_load_balancer(self, extra_create_mocks=[]): - nova.NovaClientPlugin.client.return_value = self.fc - results = [{'member': {'id': 'member5678'}}] - for m in extra_create_mocks: - results.append(m) - self.mc.create_member.side_effect = results - snippet = template_format.parse(lb_template) - self.stack = utils.parse_stack(snippet) - resource_defns = self.stack.t.resource_definitions(self.stack) - return loadbalancer.LoadBalancer( - 'lb', resource_defns['lb'], self.stack) - - def validate_create_load_balancer(self, create_count=1): - if create_count > 1: - self.assertEqual(create_count, self.mc.create_member.call_count) - self.mc.create_member.assert_called_with({ - 'member': { - 'pool_id': 'pool123', 'protocol_port': 8080, - 'address': '4.5.6.7'}} - ) - nova.NovaClientPlugin.client.assert_called_with() - self.assertEqual(create_count, - nova.NovaClientPlugin.client.call_count) - else: - self.mc.create_member.assert_called_once_with({ - 'member': { - 'pool_id': 'pool123', 'protocol_port': 8080, - 'address': '1.2.3.4'}} - ) - nova.NovaClientPlugin.client.assert_called_once_with() - - def test_create(self): - rsrc = self.create_load_balancer() - - scheduler.TaskRunner(rsrc.create)() - self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - self.validate_create_load_balancer() - - def test_update(self): - rsrc = self.create_load_balancer( - extra_create_mocks=[{'member': {'id': 'memberxyz'}}]) - - scheduler.TaskRunner(rsrc.create)() - - props = dict(rsrc.properties) - props['members'] = ['5678'] - update_template = rsrc.t.freeze(properties=props) - - scheduler.TaskRunner(rsrc.update, update_template)() - self.validate_create_load_balancer(create_count=2) - self.mc.delete_member.assert_called_once_with(u'member5678') - - def test_update_missing_member(self): - rsrc = self.create_load_balancer() - self.mc.delete_member.side_effect = [ - exceptions.NeutronClientException(status_code=404)] - - scheduler.TaskRunner(rsrc.create)() - - props = dict(rsrc.properties) - props['members'] = [] - update_template = rsrc.t.freeze(properties=props) - - scheduler.TaskRunner(rsrc.update, update_template)() - self.assertEqual((rsrc.UPDATE, rsrc.COMPLETE), rsrc.state) - self.mc.delete_member.assert_called_once_with(u'member5678') - self.validate_create_load_balancer() - - def test_delete(self): - rsrc = self.create_load_balancer() - - scheduler.TaskRunner(rsrc.create)() - scheduler.TaskRunner(rsrc.delete)() - self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) - self.mc.delete_member.assert_called_once_with(u'member5678') - self.validate_create_load_balancer() - - def test_delete_missing_member(self): - rsrc = self.create_load_balancer() - self.mc.delete_member.side_effect = [ - exceptions.NeutronClientException(status_code=404)] - - scheduler.TaskRunner(rsrc.create)() - scheduler.TaskRunner(rsrc.delete)() - self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) - self.mc.delete_member.assert_called_once_with(u'member5678') - self.validate_create_load_balancer() - - -class PoolUpdateHealthMonitorsTest(common.HeatTestCase): - - def setUp(self): - super(PoolUpdateHealthMonitorsTest, self).setUp() - self.mc = mock.Mock(spec=neutronclient.Client) - self.patchobject(neutronclient, 'Client', return_value=self.mc) - self.patchobject(neutronV20, 'find_resourceid_by_name_or_id') - self.patchobject(neutron.NeutronClientPlugin, 'has_extension', - return_value=True) - - def validate_create_pool_with_health_monitors(self): - self.mc.create_health_monitor.assert_called_with({ - 'health_monitor': { - 'delay': 3, 'max_retries': 5, 'type': u'HTTP', - 'timeout': 10, 'admin_state_up': True}} - ) - self.assertEqual(2, self.mc.create_health_monitor.call_count) - neutronV20.find_resourceid_by_name_or_id.assert_called_with( - mock.ANY, - 'subnet', - 'sub123', - cmd_resource=None, - ) - self.mc.create_pool.assert_called_once_with({ - 'pool': { - 'subnet_id': 'sub123', 'protocol': u'HTTP', - 'name': utils.PhysName(self.stack_name, 'pool'), - 'lb_method': 'ROUND_ROBIN', 'admin_state_up': True}} - ) - self.mc.associate_health_monitor.assert_has_calls([mock.call( - '5678', {'health_monitor': {'id': '5555'}}), mock.call( - '5678', {'health_monitor': {'id': '6666'}})], - any_order=True) - self.assertEqual(2, self.mc.associate_health_monitor.call_count) - self.mc.create_vip.assert_called_once_with({ - 'vip': { - 'protocol': u'HTTP', 'name': 'pool.vip', - 'admin_state_up': True, 'subnet_id': u'sub123', - 'pool_id': '5678', 'protocol_port': 80}} - ) - self.mc.show_pool.assert_called_once_with('5678') - self.mc.show_vip.assert_called_once_with('xyz') - - def _create_pool_with_health_monitors(self, stack_name): - self.stack_name = stack_name - self.mc.create_health_monitor.side_effect = [ - {'health_monitor': {'id': '5555'}}, - {'health_monitor': {'id': '6666'}}] - - self.stub_SubnetConstraint_validate() - neutronV20.find_resourceid_by_name_or_id.return_value = 'sub123' - self.mc.create_pool.return_value = {'pool': {'id': '5678'}} - self.mc.create_vip.return_value = {'vip': {'id': 'xyz'}} - self.mc.show_pool.return_value = {'pool': {'status': 'ACTIVE'}} - self.mc.show_vip.return_value = {'vip': {'status': 'ACTIVE'}} - - def test_update_pool_with_references_to_health_monitors(self): - snippet = template_format.parse(pool_with_health_monitors_template) - self.stack = utils.parse_stack(snippet) - self._create_pool_with_health_monitors(self.stack.name) - self.stack.create() - self.assertEqual((self.stack.CREATE, self.stack.COMPLETE), - self.stack.state) - - snippet['resources']['pool']['properties']['monitors'] = [ - {u'get_resource': u'monitor1'}] - updated_stack = utils.parse_stack(snippet) - self.stack.update(updated_stack) - self.assertEqual((self.stack.UPDATE, self.stack.COMPLETE), - self.stack.state) - self.validate_create_pool_with_health_monitors() - self.mc.disassociate_health_monitor.assert_called_once_with( - '5678', mock.ANY) - - def test_update_pool_with_empty_list_of_health_monitors(self): - snippet = template_format.parse(pool_with_health_monitors_template) - self.stack = utils.parse_stack(snippet) - self._create_pool_with_health_monitors(self.stack.name) - - self.stack.create() - self.assertEqual((self.stack.CREATE, self.stack.COMPLETE), - self.stack.state) - - snippet['resources']['pool']['properties']['monitors'] = [] - updated_stack = utils.parse_stack(snippet) - self.stack.update(updated_stack) - self.assertEqual((self.stack.UPDATE, self.stack.COMPLETE), - self.stack.state) - self.mc.disassociate_health_monitor.assert_has_calls( - [mock.call('5678', '5555'), mock.call('5678', '6666')], - any_order=True) - self.assertEqual(2, self.mc.disassociate_health_monitor.call_count) - - self.validate_create_pool_with_health_monitors() - - def test_update_pool_without_health_monitors(self): - snippet = template_format.parse(pool_with_health_monitors_template) - self.stack = utils.parse_stack(snippet) - self._create_pool_with_health_monitors(self.stack.name) - - self.stack.create() - self.assertEqual((self.stack.CREATE, self.stack.COMPLETE), - self.stack.state) - - snippet['resources']['pool']['properties'].pop('monitors') - updated_stack = utils.parse_stack(snippet) - self.stack.update(updated_stack) - self.assertEqual((self.stack.UPDATE, self.stack.COMPLETE), - self.stack.state) - self.mc.disassociate_health_monitor.assert_has_calls( - [mock.call('5678', '5555'), mock.call('5678', '6666')], - any_order=True) - self.assertEqual(2, self.mc.disassociate_health_monitor.call_count) - self.validate_create_pool_with_health_monitors() diff --git a/setup.cfg b/setup.cfg index d83b4690da..ef514ff4b0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -137,7 +137,6 @@ heat.constraints = neutron.lbaas.loadbalancer = heat.engine.clients.os.neutron.lbaas_constraints:LoadbalancerConstraint neutron.lbaas.pool = heat.engine.clients.os.neutron.lbaas_constraints:PoolConstraint neutron.lbaas.provider = heat.engine.clients.os.neutron.lbaas_constraints:LBaasV2ProviderConstraint - neutron.lb.provider = heat.engine.clients.os.neutron.neutron_constraints:LBaasV1ProviderConstraint neutron.network = heat.engine.clients.os.neutron.neutron_constraints:NetworkConstraint neutron.port = heat.engine.clients.os.neutron.neutron_constraints:PortConstraint neutron.port_pair = heat.engine.clients.os.neutron.neutron_constraints:PortPairConstraint