def do_update(self, context, new_profile_id): if not new_profile_id: raise exception.ProfileNotSpecified() if new_profile_id == self.profile_id: return True if not self.physical_id: return False # Check if profile types match old_profile = db_api.get_profile(context, self.profile_id) new_profile = db_api.get_profile(context, new_profile_id) if old_profile.type != new_profile.type: event_mod.warning(_LW('Node cannot be updated to a different ' 'profile type (%(oldt)s->%(newt)s)') % {'oldt': old_profile.type, 'newt': new_profile.type}) return False res = profile_base.update_object(self, new_profile_id) if res: self.rt['profile'] = profile_base.load(context, new_profile_id) self.profile_id = new_profile_id self.updated_time = datetime.datetime.utcnow() self.store() return res
def do_update(self, context, new_profile_id, **kwargs): '''Additional logic at the beginning of cluster updating progress. Check profile and set cluster status to UPDATING. ''' # Profile type checking is done here because the do_update logic can # be triggered from API or Webhook if not new_profile_id: raise exception.ProfileNotSpecified() if new_profile_id == self.profile_id: return True new_profile = db_api.get_profile(context, new_profile_id) if not new_profile: event_mod.warning(context, self, 'update', _LW('Cluster cannot be updated to a profile ' 'that does not exists')) return False # Check if profile types match old_profile = db_api.get_profile(context, self.profile_id) if old_profile.type != new_profile.type: event_mod.warning(context, self, 'update', _LW('Cluster cannot be updated to a different ' 'profile type (%(oldt)s->%(newt)s)') % { 'oldt': old_profile.type, 'newt': new_profile.type}) return False self.set_status(self.UPDATING) return True
def set_status(self, result, reason=None): """Set action status based on return value from execute.""" timestamp = wallclock() if result == self.RES_OK: status = self.SUCCEEDED ao.Action.mark_succeeded(self.context, self.id, timestamp) elif result == self.RES_ERROR: status = self.FAILED ao.Action.mark_failed(self.context, self.id, timestamp, reason or 'ERROR') elif result == self.RES_TIMEOUT: status = self.FAILED ao.Action.mark_failed(self.context, self.id, timestamp, reason or 'TIMEOUT') elif result == self.RES_CANCEL: status = self.CANCELLED ao.Action.mark_cancelled(self.context, self.id, timestamp) elif result == self.RES_LIFECYCLE_COMPLETE: status = self.SUCCEEDED ao.Action.mark_ready(self.context, self.id, timestamp) else: # result == self.RES_RETRY: retries = self.data.get('retries', 0) # Action failed at the moment, but can be retried # retries time is configurable if retries < cfg.CONF.lock_retry_times: status = self.READY retries += 1 self.data.update({'retries': retries}) ao.Action.abandon(self.context, self.id, {'data': self.data}) # sleep for a while eventlet.sleep(cfg.CONF.lock_retry_interval) dispatcher.start_action(self.id) else: status = self.RES_ERROR if not reason: reason = ('Exceeded maximum number of retries (%d)' '') % cfg.CONF.lock_retry_times ao.Action.mark_failed(self.context, self.id, timestamp, reason) if status == self.SUCCEEDED: EVENT.info(self, consts.PHASE_END, reason or 'SUCCEEDED') elif status == self.READY: EVENT.warning(self, consts.PHASE_ERROR, reason or 'RETRY') else: EVENT.error(self, consts.PHASE_ERROR, reason or 'ERROR') self.status = status self.status_reason = reason
def member_add(self, node, lb_id, pool_id, port, subnet): """Add a member to Neutron lbaas pool. :param node: A node object to be added to the specified pool. :param lb_id: The ID of the loadbalancer. :param pool_id: The ID of the pool for receiving the node. :param port: The port for the new LB member to be created. :param subnet: The subnet to be used by the new LB member. :returns: The ID of the new LB member or None if errors occurred. """ addresses = self._get_node_address(node, version=4) if not addresses: LOG.error(_LE('Node (%(n)s) does not have valid IPv4 address.'), {'n': node.id}) return None try: subnet_obj = self.nc().subnet_get(subnet) net_id = subnet_obj.network_id net = self.nc().network_get(net_id) except exception.InternalError as ex: resource = 'subnet' if subnet in ex.message else 'network' msg = _LE('Failed in getting %(resource)s: %(msg)s.' ) % {'resource': resource, 'msg': six.text_type(ex)} LOG.exception(msg) event.warning(oslo_context.get_current(), self, resource.upper()+'_GET', 'ERROR', msg) return None net_name = net.name if net_name not in addresses: LOG.error(_LE('Node is not in subnet %(subnet)s'), {'subnet': subnet}) return None address = addresses[net_name] try: member = self.nc().pool_member_create(pool_id, address, port, subnet_obj.id) except exception.InternalError as ex: msg = _LE('Failed in creating lb pool member: %s.' ) % six.text_type(ex) LOG.exception(msg) event.warning(oslo_context.get_current(), self, 'POOL_MEMBER_CREATE', 'ERROR', msg) return None res = self._wait_for_lb_ready(lb_id) if res is False: LOG.error(_LE('Failed in creating pool member (%s).') % member.id) return None return member.id
def _handle_exception(self, context, action, status, exception): msg = six.text_type(exception) event_mod.warning(context, self, action, status, msg) self.physical_id = exception.kwargs.get('resource_id', None) if self.physical_id: reason = _('Profile failed in %(action)s resource (%(id)s) due ' 'to: %(msg)s') % {'action': action[:-1] + 'ing', 'id': self.physical_id, 'msg': msg} else: # Exception happens before physical node creatin started. reason = _('Profile failed in creating node due to: %(msg)s') % { 'msg': msg} self.set_status(context, self.ERROR, reason) self.store(context)
def _handle_exception(self, context, action, status, exception): msg = six.text_type(exception) event_mod.warning(context, self, action, status, msg) self.physical_id = exception.kwargs.get('resource_id', None) if self.physical_id: reason = _('Profile failed in %(action)s resource (%(id)s) due ' 'to: %(msg)s') % { 'action': action[:-1] + 'ing', 'id': self.physical_id, 'msg': msg } else: # Exception happens before physical node creatin started. reason = _('Profile failed in creating node due to: %(msg)s') % { 'msg': msg } self.set_status(context, self.ERROR, reason) self.store(context)
def test_warning(self, mock_dump): entity = mock.Mock(id='1234567890') entity.name = 'fake_obj' action = mock.Mock(entity=entity, action='ACTION_NAME') res = event.warning(action, 'P1', 'R1', 'TS1') self.assertIsNone(res) mock_dump.assert_called_once_with(logging.WARNING, action, 'P1', 'R1', 'TS1')
def _wait_for_lb_ready(self, lb_id, timeout=60, ignore_not_found=False): """Keep waiting until loadbalancer is ready This method will keep waiting until loadbalancer resource specified by lb_id becomes ready, i.e. its provisioning_status is ACTIVE and its operating_status is ONLINE. :param lb_id: ID of the load-balancer to check. :param timeout: timeout in seconds. :param ignore_not_found: if set to True, nonexistent loadbalancer resource is also an acceptable result. """ waited = 0 while waited < timeout: try: lb = self.nc().loadbalancer_get(lb_id) except exception.InternalError as ex: msg = _LE('Failed in getting loadbalancer: %s.' ) % six.text_type(ex) LOG.exception(msg) EVENT.warning(oslo_context.get_current(), self, 'LB_GET', 'ERROR', msg) return False if lb is None: lb_ready = ignore_not_found else: lb_ready = ((lb.provisioning_status == 'ACTIVE') and (lb.operating_status == 'ONLINE')) if lb_ready is True: return True LOG.debug(_('Waiting for loadbalancer %(lb)s to become ready'), {'lb': lb_id}) eventlet.sleep(2) waited += 2 return False
def set_status(self, result, reason=None): """Set action status based on return value from execute.""" timestamp = wallclock() if result == self.RES_OK: status = self.SUCCEEDED ao.Action.mark_succeeded(self.context, self.id, timestamp) elif result == self.RES_ERROR: status = self.FAILED ao.Action.mark_failed(self.context, self.id, timestamp, reason or 'ERROR') elif result == self.RES_TIMEOUT: status = self.FAILED ao.Action.mark_failed(self.context, self.id, timestamp, reason or 'TIMEOUT') elif result == self.RES_CANCEL: status = self.CANCELLED ao.Action.mark_cancelled(self.context, self.id, timestamp) else: # result == self.RES_RETRY: status = self.READY # Action failed at the moment, but can be retried # We abandon it and then notify other dispatchers to execute it ao.Action.abandon(self.context, self.id) dispatcher.start_action() if status == self.SUCCEEDED: EVENT.info(self, consts.PHASE_END, reason or 'SUCCEEDED') elif status == self.READY: EVENT.warning(self, consts.PHASE_ERROR, reason or 'RETRY') else: EVENT.error(self, consts.PHASE_ERROR, reason or 'ERROR') self.status = status self.status_reason = reason
def set_status(self, result, reason=None): """Set action status based on return value from execute.""" timestamp = wallclock() if result == self.RES_OK: status = self.SUCCEEDED db_api.action_mark_succeeded(self.context, self.id, timestamp) elif result == self.RES_ERROR: status = self.FAILED db_api.action_mark_failed(self.context, self.id, timestamp, reason=reason or 'ERROR') elif result == self.RES_TIMEOUT: status = self.FAILED db_api.action_mark_failed(self.context, self.id, timestamp, reason=reason or 'TIMEOUT') elif result == self.RES_CANCEL: status = self.CANCELLED db_api.action_mark_cancelled(self.context, self.id, timestamp) else: # result == self.RES_RETRY: status = self.READY # Action failed at the moment, but can be retried # We abandon it and then notify other dispatchers to execute it db_api.action_abandon(self.context, self.id) if status == self.SUCCEEDED: EVENT.info(self.context, self, self.action, status, reason) elif status == self.READY: EVENT.warning(self.context, self, self.action, status, reason) else: EVENT.error(self.context, self, self.action, status, reason) self.status = status self.status_reason = reason
def member_remove(self, lb_id, pool_id, member_id): """Delete a member from Neutron lbaas pool. :param lb_id: The ID of the loadbalancer the operation is targeted at; :param pool_id: The ID of the pool from which the member is deleted; :param member_id: The ID of the LB member. :returns: True if the operation succeeded or False if errors occurred. """ try: self.nc().pool_member_delete(pool_id, member_id) except exception.InternalError as ex: msg = _LE('Failed in removing member %(m)s from pool %(p)s: ' '%(ex)s') % {'m': member_id, 'p': pool_id, 'ex': six.text_type(ex)} LOG.exception(msg) EVENT.warning(oslo_context.get_current(), self, 'POOL_MEMBER_DELETE', 'ERROR', msg) return None res = self._wait_for_lb_ready(lb_id) if res is False: LOG.error(_LE('Failed in deleting pool member (%s).') % member_id) return None return True
def lb_create(self, vip, pool): """Create a LBaaS instance :param vip: A dict containing the properties for the VIP; :param pool: A dict describing the pool of load-balancer members. """ def _cleanup(msg, **kwargs): LOG.error(msg) self.lb_delete(**kwargs) return result = {} # Create loadblancer try: subnet = self.nc().subnet_get(vip['subnet']) except exception.InternalError as ex: msg = _LE('Failed in getting subnet: %s.') % six.text_type(ex) LOG.exception(msg) EVENT.warning(oslo_context.get_current(), self, 'SUBNET_GET', 'ERROR', msg) return False, msg subnet_id = subnet.id try: lb = self.nc().loadbalancer_create(subnet_id, vip.get('address', None), vip['admin_state_up']) except exception.InternalError as ex: msg = _LE('Failed in creating loadbalancer: %s.' ) % six.text_type(ex) LOG.exception(msg) EVENT.warning(oslo_context.get_current(), self, 'LB_CREATE', 'ERROR', msg) return False, msg result['loadbalancer'] = lb.id res = self._wait_for_lb_ready(lb.id) if res is False: msg = _LE('Failed in creating load balancer (%s).') % lb.id _cleanup(msg, **result) return False, msg # Create listener try: listener = self.nc().listener_create(lb.id, vip['protocol'], vip['protocol_port'], vip.get('connection_limit', None), vip['admin_state_up']) except exception.InternalError as ex: msg = _LE('Failed in creating lb listener: %s.' ) % six.text_type(ex) LOG.exception(msg) EVENT.warning(oslo_context.get_current(), self, 'LISTENER_CREATE', 'ERROR', msg) return False, msg result['listener'] = listener.id res = self._wait_for_lb_ready(lb.id) if res is False: msg = _LE('Failed in creating listener (%s).') % listener.id _cleanup(msg, **result) return res, msg # Create pool try: pool = self.nc().pool_create(pool['lb_method'], listener.id, pool['protocol'], pool['admin_state_up']) except exception.InternalError as ex: msg = _LE('Failed in creating lb pool: %s.' ) % six.text_type(ex) LOG.exception(msg) EVENT.warning(oslo_context.get_current(), self, 'POOL_CREATE', 'ERROR', msg) return False, msg result['pool'] = pool.id res = self._wait_for_lb_ready(lb.id) if res is False: msg = _LE('Failed in creating pool (%s).') % pool.id _cleanup(msg, **result) return res, msg return True, result
def lb_delete(self, **kwargs): """Delete a Neutron lbaas instance The following Neutron lbaas resources will be deleted in order: 1)healthmonitor; 2)pool; 3)listener; 4)loadbalancer. """ lb_id = kwargs.pop('loadbalancer') healthmonitor_id = kwargs.pop('healthmonitor', None) if healthmonitor_id: try: self.nc().healthmonitor_delete(healthmonitor_id) except exception.InternalError as ex: msg = _LE('Failed in deleting healthmonitor: %s.' ) % six.text_type(ex) LOG.exception(msg) EVENT.warning(oslo_context.get_current(), self, 'HEALTHMONITOR_DELETE', 'ERROR', msg) return False, msg res = self._wait_for_lb_ready(lb_id) if res is False: msg = _LE('Failed in deleting healthmonitor ' '(%s).') % healthmonitor_id return False, msg pool_id = kwargs.pop('pool', None) if pool_id: try: self.nc().pool_delete(pool_id) except exception.InternalError as ex: msg = _LE('Failed in deleting lb pool: %s.' ) % six.text_type(ex) LOG.exception(msg) EVENT.warning(oslo_context.get_current(), self, 'POOL_DELETE', 'ERROR', msg) return False, msg res = self._wait_for_lb_ready(lb_id) if res is False: msg = _LE('Failed in deleting pool (%s).') % pool_id return False, msg listener_id = kwargs.pop('listener', None) if listener_id: try: self.nc().listener_delete(listener_id) except exception.InternalError as ex: msg = _LE('Failed in deleting listener: %s.' ) % six.text_type(ex) LOG.exception(msg) EVENT.warning(oslo_context.get_current(), self, 'LISTENER_DELETE', 'ERROR', msg) return False, msg res = self._wait_for_lb_ready(lb_id) if res is False: msg = _LE('Failed in deleting listener (%s).') % listener_id return False, msg self.nc().loadbalancer_delete(lb_id) res = self._wait_for_lb_ready(lb_id, ignore_not_found=True) if res is False: msg = _LE('Failed in deleting loadbalancer (%s).') % lb_id return False, msg return True, _('LB deletion succeeded')