def _exec_event(self, event): """Execute an event function""" event_fn = getattr(self, event['event_type'], None) if event_fn is None: raise exceptions.EventError( error='Event type %s is not supported' % event['event_type']) try: event_fn(lease_id=event['lease_id'], event_id=event['id']) except common_ex.InvalidStatus: now = datetime.datetime.utcnow() if now < event['time'] + datetime.timedelta( seconds=CONF.manager.event_max_retries * 10): # Set the event status UNDONE for retrying the event db_api.event_update(event['id'], {'status': status.event.UNDONE}) else: db_api.event_update(event['id'], {'status': status.event.ERROR}) LOG.exception('Error occurred while handling %s event for ' 'lease %s.', event['event_type'], event['lease_id']) except Exception: db_api.event_update(event['id'], {'status': status.event.ERROR}) LOG.exception('Error occurred while handling %s event for ' 'lease %s.', event['event_type'], event['lease_id']) else: lease = db_api.lease_get(event['lease_id']) with trusts.create_ctx_from_trust(lease['trust_id']) as ctx: self._send_notification( lease, ctx, events=['event.%s' % event['event_type']])
def _heal_reservation(self, reservation, host_ids): """Allocate alternative host(s) for the given reservation. :param reservation: A reservation that has allocations to change :param host_ids: Failed host ids :return: True if all the allocations in the given reservation are successfully allocated """ lease = db_api.lease_get(reservation['lease_id']) ret = True allocations = [ alloc for alloc in reservation['computehost_allocations'] if alloc['compute_host_id'] in host_ids] if reservation['affinity']: old_host_id = allocations[0]['compute_host_id'] new_host_id = self._select_host(reservation, lease) self._pre_reallocate(reservation, old_host_id) if new_host_id is None: for allocation in allocations: db_api.host_allocation_destroy(allocation['id']) LOG.warn('Could not find alternative host for ' 'reservation %s (lease: %s).', reservation['id'], lease['name']) ret = False else: for allocation in allocations: db_api.host_allocation_update( allocation['id'], {'compute_host_id': new_host_id}) self._post_reallocate( reservation, lease, new_host_id, len(allocations)) else: new_host_ids = [] for allocation in allocations: old_host_id = allocation['compute_host_id'] new_host_id = self._select_host(reservation, lease) self._pre_reallocate(reservation, old_host_id) if new_host_id is None: db_api.host_allocation_destroy(allocation['id']) LOG.warn('Could not find alternative host for ' 'reservation %s (lease: %s).', reservation['id'], lease['name']) ret = False continue db_api.host_allocation_update( allocation['id'], {'compute_host_id': new_host_id}) new_host_ids.append(new_host_id) for new_host, num in collections.Counter(new_host_ids).items(): self._post_reallocate(reservation, lease, new_host, num) return ret
def is_stable(cls, lease_id): """Check if the lease status is stable :param lease_id: Lease ID :return: True if the status is in (PENDING, ACTIVE, TERMINATED, ERROR) """ lease = db_api.lease_get(lease_id) return (lease['status'] in cls.STABLE)
def wrapper(*args, **kwargs): # Update a lease status lease_id = kwargs['lease_id'] l = db_api.lease_get(lease_id) if cls.is_valid_transition(l['status'], transition, lease_id=lease_id): db_api.lease_update(lease_id, {'status': transition}) LOG.debug('Status of lease %s changed from %s to %s.', lease_id, l['status'], transition) else: LOG.warn('Aborting %s. ' 'Invalid lease status transition from %s to %s.', func.__name__, l['status'], transition) raise exceptions.InvalidStatus # Executing the wrapped function try: result = func(*args, **kwargs) except Exception as e: LOG.error('Lease %s went into ERROR status. %s', lease_id, str(e)) db_api.lease_update(lease_id, {'status': cls.ERROR}) raise e # Update a lease status if it exists if db_api.lease_get(lease_id): next_status = cls.derive_stable_status(lease_id) if (next_status in result_in and cls.is_valid_transition(transition, next_status, lease_id=lease_id)): db_api.lease_update(lease_id, {'status': next_status}) LOG.debug('Status of lease %s changed from %s to %s.', lease_id, transition, next_status) else: LOG.error('Lease %s went into ERROR status.', lease_id) db_api.lease_update(lease_id, {'status': cls.ERROR}) raise exceptions.InvalidStatus return result
def _reallocate(self, allocation): """Allocate an alternative host. :param: allocation: allocation to change. :return: True if an alternative host was successfully allocated. """ reservation = db_api.reservation_get(allocation['reservation_id']) pool = nova.ReservationPool() # Remove the failed host from the aggregate. if reservation['status'] == status.reservation.ACTIVE: host = db_api.host_get(allocation['compute_host_id']) pool.remove_computehost(reservation['aggregate_id'], host['service_name']) try: self.placement_client.delete_reservation_inventory( host['service_name'], reservation['id']) except openstack_ex.ResourceProviderNotFound: pass # Allocate an alternative host. values = {} lease = db_api.lease_get(reservation['lease_id']) values['start_date'] = max(datetime.datetime.utcnow(), lease['start_date']) values['end_date'] = lease['end_date'] specs = ['vcpus', 'memory_mb', 'disk_gb', 'affinity', 'amount', 'resource_properties'] for key in specs: values[key] = reservation[key] changed_hosts = self.pickup_hosts(reservation['id'], values) if len(changed_hosts['added']) == 0: db_api.host_allocation_destroy(allocation['id']) LOG.warn('Could not find alternative host for reservation %s ' '(lease: %s).', reservation['id'], lease['name']) return False else: new_host_id = changed_hosts['added'].pop() db_api.host_allocation_update( allocation['id'], {'compute_host_id': new_host_id}) if reservation['status'] == status.reservation.ACTIVE: # Add the alternative host into the aggregate. new_host = db_api.host_get(new_host_id) pool.add_computehost(reservation['aggregate_id'], new_host['service_name'], stay_in=True) self.placement_client.update_reservation_inventory( new_host['service_name'], reservation['id'], 1) LOG.warn('Resource changed for reservation %s (lease: %s).', reservation['id'], lease['name']) return True
def update_reservation(self, reservation_id, values): """Update reservation.""" reservation = db_api.reservation_get(reservation_id) lease = db_api.lease_get(reservation['lease_id']) dates_before = { 'start_date': lease['start_date'], 'end_date': lease['end_date'] } dates_after = { 'start_date': values['start_date'], 'end_date': values['end_date'] } fip_reservation = db_api.fip_reservation_get( reservation['resource_id']) if ('network_id' in values and values.get('network_id') != fip_reservation['network_id']): raise manager_ex.CantUpdateFloatingIPReservation( msg="Updating network_id is not supported") required_fips = fip_reservation['required_floatingips'] if ('required_floatingips' in values and values['required_floatingips'] != required_fips and values['required_floatingips'] != []): raise manager_ex.CantUpdateFloatingIPReservation( msg="Updating required_floatingips is not supported except " "with an empty list") self._update_allocations(dates_before, dates_after, reservation_id, reservation['status'], fip_reservation, values) updates = {} if 'amount' in values: updates['amount'] = values.get('amount') if updates: db_api.fip_reservation_update(fip_reservation['id'], updates) if ('required_floatingips' in values and values['required_floatingips'] != required_fips): db_api.required_fip_destroy_by_fip_reservation_id( fip_reservation['id']) for fip_address in values.get('required_floatingips'): fip_address_values = { 'address': fip_address, 'floatingip_reservation_id': fip_reservation['id'] } db_api.required_fip_create(fip_address_values)
def _reallocate(self, allocation): """Allocate an alternative host. :param: allocation: allocation to change. :return: True if an alternative host was successfully allocated. """ reservation = db_api.reservation_get(allocation['reservation_id']) h_reservation = db_api.host_reservation_get( reservation['resource_id']) lease = db_api.lease_get(reservation['lease_id']) pool = nova.ReservationPool() # Remove the old host from the aggregate. if reservation['status'] == status.reservation.ACTIVE: host = db_api.host_get(allocation['compute_host_id']) pool.remove_computehost(h_reservation['aggregate_id'], host['service_name']) # Allocate an alternative host. start_date = max(datetime.datetime.utcnow(), lease['start_date']) new_hostids = self._matching_hosts( reservation['hypervisor_properties'], reservation['resource_properties'], '1-1', start_date, lease['end_date'] ) if not new_hostids: db_api.host_allocation_destroy(allocation['id']) LOG.warn('Could not find alternative host for reservation %s ' '(lease: %s).', reservation['id'], lease['name']) return False else: new_hostid = new_hostids.pop() db_api.host_allocation_update(allocation['id'], {'compute_host_id': new_hostid}) LOG.warn('Resource changed for reservation %s (lease: %s).', reservation['id'], lease['name']) if reservation['status'] == status.reservation.ACTIVE: # Add the alternative host into the aggregate. new_host = db_api.host_get(new_hostid) pool.add_computehost(h_reservation['aggregate_id'], new_host['service_name']) return True
def update_reservation(self, reservation_id, values): """Update reservation.""" reservation = db_api.reservation_get(reservation_id) lease = db_api.lease_get(reservation['lease_id']) if (not [ x for x in values.keys() if x in ['min', 'max', 'hypervisor_properties', 'resource_properties'] ] and values['start_date'] >= lease['start_date'] and values['end_date'] <= lease['end_date']): # Nothing to update return dates_before = { 'start_date': lease['start_date'], 'end_date': lease['end_date'] } dates_after = { 'start_date': values['start_date'], 'end_date': values['end_date'] } host_reservation = db_api.host_reservation_get( reservation['resource_id']) self._update_allocations(dates_before, dates_after, reservation_id, reservation['status'], host_reservation, values) updates = {} if 'min' in values or 'max' in values: count_range = str( values.get('min', host_reservation['count_range'].split( '-')[0])) + '-' + str( values.get( 'max', host_reservation['count_range'].split('-')[1])) updates['count_range'] = count_range if 'hypervisor_properties' in values: updates['hypervisor_properties'] = values.get( 'hypervisor_properties') if 'resource_properties' in values: updates['resource_properties'] = values.get('resource_properties') if updates: db_api.host_reservation_update(host_reservation['id'], updates)
def update_reservation(self, reservation_id, new_values): """Updates an instance reservation with requested parameters. This method allows users to update an instance reservation under the following conditions. - If an instance reservation has not started yet - vcpus, memory_mb disk_gb and amount can be updateable unless Blazar can accommodate the new request. - If an instance reservation has already started - only amount is increasable. """ self._validate_reservation_params(new_values) reservation = db_api.reservation_get(reservation_id) lease = db_api.lease_get(reservation['lease_id']) updatable = [ 'vcpus', 'memory_mb', 'disk_gb', 'affinity', 'amount', 'resource_properties' ] if (not any([k in updatable for k in new_values.keys()]) and new_values['start_date'] >= lease['start_date'] and new_values['end_date'] <= lease['end_date']): # no update because of just shortening the reservation time return if (reservation['status'] == 'active' and any([k in updatable[:-1] for k in new_values.keys()])): msg = "An active reservation only accepts to update amount." raise mgr_exceptions.InvalidStateUpdate(msg) if reservation['status'] == 'error': msg = "An error reservation doesn't accept an updating request." raise mgr_exceptions.InvalidStateUpdate(msg) if new_values.get('affinity', None): new_values['affinity'] = bool_from_string(new_values['affinity'], default=None) for key in updatable: if key not in new_values: new_values[key] = reservation[key] changed_hosts = self.pickup_hosts(reservation_id, new_values) if (reservation['status'] == 'active' and len(changed_hosts['removed']) > 0): err_msg = ("Instance reservation doesn't allow to reduce/replace " "reserved instance slots when the reservation is in " "active status.") raise mgr_exceptions.CantUpdateParameter(err_msg) db_api.instance_reservation_update( reservation['resource_id'], {key: new_values[key] for key in updatable}) self.update_host_allocations(changed_hosts['added'], changed_hosts['removed'], reservation_id) try: self.update_resources(reservation_id) except mgr_exceptions.NovaClientError: raise
def update_lease(self, lease_id, values): if not values: return db_api.lease_get(lease_id) if len(values) == 1 and 'name' in values: db_api.lease_update(lease_id, values) return db_api.lease_get(lease_id) lease = db_api.lease_get(lease_id) start_date = values.get( 'start_date', datetime.datetime.strftime(lease['start_date'], LEASE_DATE_FORMAT)) end_date = values.get( 'end_date', datetime.datetime.strftime(lease['end_date'], LEASE_DATE_FORMAT)) before_end_date = values.get('before_end_date', None) start_date, end_date, now = self._parse_lease_dates(start_date, end_date) values['start_date'] = start_date values['end_date'] = end_date self._check_for_invalid_date_inputs(lease, values, now) with trusts.create_ctx_from_trust(lease['trust_id']): if before_end_date: try: before_end_date = self._date_from_string(before_end_date) self._check_date_within_lease_limits(before_end_date, values) except common_ex.BlazarException as e: LOG.error("Invalid before_end_date param. %s", str(e)) raise e reservations = values.get('reservations', []) existing_reservations = ( db_api.reservation_get_all_by_lease_id(lease_id)) try: invalid_ids = set([r['id'] for r in reservations]).difference( [r['id'] for r in existing_reservations]) except KeyError: raise exceptions.MissingParameter(param='reservation ID') if invalid_ids: raise common_ex.InvalidInput( 'Please enter valid reservation IDs. Invalid reservation ' 'IDs are: %s' % ','.join([str(id) for id in invalid_ids])) try: [ self.plugins[r['resource_type']] for r in (reservations + existing_reservations)] except KeyError: raise exceptions.CantUpdateParameter(param='resource_type') existing_allocs = self._existing_allocations(existing_reservations) if reservations: new_reservations = reservations new_allocs = self._allocation_candidates(values, existing_reservations) else: # User is not updating reservation parameters, e.g., is only # adjusting lease start/end dates. new_reservations = existing_reservations new_allocs = existing_allocs try: self.enforcement.check_update(context.current(), lease, values, existing_allocs, new_allocs, existing_reservations, new_reservations) except common_ex.NotAuthorized as e: LOG.error("Enforcement checks failed. %s", str(e)) raise common_ex.NotAuthorized(e) # TODO(frossigneux) rollback if an exception is raised for reservation in existing_reservations: v = {} v['start_date'] = values['start_date'] v['end_date'] = values['end_date'] try: v.update([r for r in reservations if r['id'] == reservation['id']].pop()) except IndexError: pass resource_type = v.get('resource_type', reservation['resource_type']) if resource_type != reservation['resource_type']: raise exceptions.CantUpdateParameter( param='resource_type') self.plugins[resource_type].update_reservation( reservation['id'], v) event = db_api.event_get_first_sorted_by_filters( 'lease_id', 'asc', { 'lease_id': lease_id, 'event_type': 'start_lease' } ) if not event: raise common_ex.BlazarException( 'Start lease event not found') db_api.event_update(event['id'], {'time': values['start_date']}) event = db_api.event_get_first_sorted_by_filters( 'lease_id', 'asc', { 'lease_id': lease_id, 'event_type': 'end_lease' } ) if not event: raise common_ex.BlazarException( 'End lease event not found') db_api.event_update(event['id'], {'time': values['end_date']}) notifications = ['update'] self._update_before_end_event(lease, values, notifications, before_end_date) try: del values['reservations'] except KeyError: pass db_api.lease_update(lease_id, values) lease = db_api.lease_get(lease_id) with trusts.create_ctx_from_trust(lease['trust_id']) as ctx: self._send_notification(lease, ctx, events=notifications) return lease
def create_lease(self, lease_values): """Create a lease with reservations. Return either the model of created lease or None if any error. """ lease_values['status'] = status.lease.CREATING try: trust_id = lease_values.pop('trust_id') except KeyError: raise exceptions.MissingTrustId() self.validate_params(lease_values, ['name', 'start_date', 'end_date']) # Remove and keep event and reservation values events = lease_values.pop("events", []) reservations = lease_values.pop("reservations", []) for res in reservations: self.validate_params(res, ['resource_type']) # Create the lease without the reservations start_date, end_date, now = self._parse_lease_dates( lease_values['start_date'], lease_values['end_date']) if start_date < now: raise common_ex.InvalidInput( 'Start date must be later than current date') if end_date <= start_date: raise common_ex.InvalidInput( 'End date must be later than start date.') with trusts.create_ctx_from_trust(trust_id) as ctx: # NOTE(priteau): We should not get user_id from ctx, because we are # in the context of the trustee (blazar user). # lease_values['user_id'] is set in blazar/api/v1/service.py lease_values['project_id'] = ctx.project_id lease_values['start_date'] = start_date lease_values['end_date'] = end_date allocations = self._allocation_candidates( lease_values, reservations) try: self.enforcement.check_create( context.current(), lease_values, reservations, allocations) except common_ex.NotAuthorized as e: LOG.error("Enforcement checks failed. %s", str(e)) raise common_ex.NotAuthorized(e) events.append({'event_type': 'start_lease', 'time': start_date, 'status': status.event.UNDONE}) events.append({'event_type': 'end_lease', 'time': end_date, 'status': status.event.UNDONE}) before_end_date = lease_values.get('before_end_date', None) if before_end_date: # incoming param. Validation check try: before_end_date = self._date_from_string( before_end_date) self._check_date_within_lease_limits(before_end_date, lease_values) except common_ex.BlazarException as e: LOG.error("Invalid before_end_date param. %s", str(e)) raise e elif CONF.manager.minutes_before_end_lease > 0: delta = datetime.timedelta( minutes=CONF.manager.minutes_before_end_lease) before_end_date = lease_values['end_date'] - delta if before_end_date: event = {'event_type': 'before_end_lease', 'status': status.event.UNDONE} events.append(event) self._update_before_end_event_date(event, before_end_date, lease_values) try: if trust_id: lease_values.update({'trust_id': trust_id}) lease = db_api.lease_create(lease_values) lease_id = lease['id'] except db_ex.BlazarDBDuplicateEntry: LOG.exception('Cannot create a lease - duplicated lease name') raise exceptions.LeaseNameAlreadyExists( name=lease_values['name']) except db_ex.BlazarDBException: LOG.exception('Cannot create a lease') raise else: try: for reservation in reservations: reservation['lease_id'] = lease['id'] reservation['start_date'] = lease['start_date'] reservation['end_date'] = lease['end_date'] self._create_reservation(reservation) except Exception: LOG.exception("Failed to create reservation for a lease. " "Rollback the lease and associated " "reservations") db_api.lease_destroy(lease_id) raise try: for event in events: event['lease_id'] = lease['id'] db_api.event_create(event) except (exceptions.UnsupportedResourceType, common_ex.BlazarException): LOG.exception("Failed to create event for a lease. " "Rollback the lease and associated " "reservations") db_api.lease_destroy(lease_id) raise else: db_api.lease_update( lease_id, {'status': status.lease.PENDING}) lease = db_api.lease_get(lease_id) self._send_notification(lease, ctx, events=['create']) return lease
def get_lease(self, lease_id): return db_api.lease_get(lease_id)
def heal_reservations(self, failed_resources): """Heal reservations which suffer from resource failures. :param: failed_resources: a list of failed hosts. :return: a dictionary of {reservation id: flags to update} e.g. {'de27786d-bd96-46bb-8363-19c13b2c6657': {'missing_resources': True}} """ reservation_flags = {} failed_allocs = [] for host in failed_resources: failed_allocs += db_api.host_allocation_get_all_by_values( compute_host_id=host['id']) for alloc in failed_allocs: reservation = db_api.reservation_get(alloc['reservation_id']) if reservation['resource_type'] != plugin.RESOURCE_TYPE: continue lease = db_api.lease_get(reservation['lease_id']) host_reservation = None pool = None # Remove the failed host from the aggregate. if reservation['status'] == status.reservation.ACTIVE: host = db_api.host_get(alloc['compute_host_id']) host_reservation = db_api.host_reservation_get( reservation['resource_id']) with trusts.create_ctx_from_trust(lease['trust_id']): pool = nova.ReservationPool() pool.remove_computehost(host_reservation['aggregate_id'], host['service_name']) # Allocate alternative resource. start_date = max(datetime.datetime.utcnow(), lease['start_date']) new_hostids = self._matching_hosts( reservation['hypervisor_properties'], reservation['resource_properties'], '1-1', start_date, lease['end_date']) if not new_hostids: if reservation['id'] not in reservation_flags: reservation_flags[reservation['id']] = {} reservation_flags[reservation['id']].update( {'missing_resources': True}) db_api.host_allocation_destroy(alloc['id']) LOG.warn( 'Could not find alternative host for reservation %s ' '(lease: %s).', reservation['id'], lease['name']) else: new_hostid = new_hostids.pop() db_api.host_allocation_update(alloc['id'], {'compute_host_id': new_hostid}) if reservation['status'] == status.reservation.ACTIVE: # Add the alternative host into the aggregate. new_host = db_api.host_get(new_hostid) with trusts.create_ctx_from_trust(lease['trust_id']): pool.add_computehost(host_reservation['aggregate_id'], new_host['service_name']) if reservation['id'] not in reservation_flags: reservation_flags[reservation['id']] = {} reservation_flags[reservation['id']].update( {'resources_changed': True}) LOG.warn('Resource changed for reservation %s (lease: %s).', reservation['id'], lease['name']) return reservation_flags
def update_lease(self, lease_id, values): if not values: return db_api.lease_get(lease_id) if len(values) == 1 and 'name' in values: db_api.lease_update(lease_id, values) return db_api.lease_get(lease_id) lease = db_api.lease_get(lease_id) start_date = values.get( 'start_date', datetime.datetime.strftime(lease['start_date'], LEASE_DATE_FORMAT)) end_date = values.get( 'end_date', datetime.datetime.strftime(lease['end_date'], LEASE_DATE_FORMAT)) before_end_date = values.get('before_end_date', None) now = datetime.datetime.utcnow() now = datetime.datetime(now.year, now.month, now.day, now.hour, now.minute) if start_date == 'now': start_date = now else: start_date = self._date_from_string(start_date) if end_date == 'now': end_date = now else: end_date = self._date_from_string(end_date) values['start_date'] = start_date values['end_date'] = end_date if (lease['start_date'] < now and values['start_date'] != lease['start_date']): raise common_ex.NotAuthorized( 'Cannot modify the start date of already started leases') if (lease['start_date'] > now and values['start_date'] < now): raise common_ex.NotAuthorized( 'Start date must be later than current date') if lease['end_date'] < now: raise common_ex.NotAuthorized( 'Terminated leases can only be renamed') if (values['end_date'] < now or values['end_date'] < values['start_date']): raise common_ex.NotAuthorized( 'End date must be later than current and start date') with trusts.create_ctx_from_trust(lease['trust_id']): if before_end_date: try: before_end_date = self._date_from_string(before_end_date) self._check_date_within_lease_limits(before_end_date, values) except common_ex.BlazarException as e: LOG.error("Invalid before_end_date param. %s", str(e)) raise e # TODO(frossigneux) rollback if an exception is raised reservations = values.get('reservations', []) for reservation in ( db_api.reservation_get_all_by_lease_id(lease_id)): v = {} v['start_date'] = values['start_date'] v['end_date'] = values['end_date'] try: v.update([r for r in reservations if r['id'] == reservation['id']].pop()) except KeyError: raise exceptions.MissingParameter(param='reservation ID') except IndexError: pass resource_type = v.get('resource_type', reservation['resource_type']) if resource_type != reservation['resource_type']: raise exceptions.CantUpdateParameter( param='resource_type') self.plugins[resource_type].update_reservation( reservation['id'], v) event = db_api.event_get_first_sorted_by_filters( 'lease_id', 'asc', { 'lease_id': lease_id, 'event_type': 'start_lease' } ) if not event: raise common_ex.BlazarException( 'Start lease event not found') db_api.event_update(event['id'], {'time': values['start_date']}) event = db_api.event_get_first_sorted_by_filters( 'lease_id', 'asc', { 'lease_id': lease_id, 'event_type': 'end_lease' } ) if not event: raise common_ex.BlazarException( 'End lease event not found') db_api.event_update(event['id'], {'time': values['end_date']}) notifications = ['update'] self._update_before_end_event(lease, values, notifications, before_end_date) try: del values['reservations'] except KeyError: pass db_api.lease_update(lease_id, values) lease = db_api.lease_get(lease_id) with trusts.create_ctx_from_trust(lease['trust_id']) as ctx: self._send_notification(lease, ctx, events=notifications) return lease
def heal_reservations(self, failed_resources): """Heal reservations which suffer from resource failures. :param: failed_resources: a list of failed hosts. :return: a dictionary of {reservation id: flags to update} e.g. {'de27786d-bd96-46bb-8363-19c13b2c6657': {'missing_resources': True}} """ reservation_flags = {} failed_allocs = [] for host in failed_resources: failed_allocs += db_api.host_allocation_get_all_by_values( compute_host_id=host['id']) for alloc in failed_allocs: reservation = db_api.reservation_get(alloc['reservation_id']) if reservation['resource_type'] != RESOURCE_TYPE: continue pool = None # Remove the failed host from the aggregate. if reservation['status'] == status.reservation.ACTIVE: host = db_api.host_get(alloc['compute_host_id']) pool = nova.ReservationPool() pool.remove_computehost(reservation['aggregate_id'], host['service_name']) # Allocate alternative resource. values = {} lease = db_api.lease_get(reservation['lease_id']) values['start_date'] = max(datetime.datetime.utcnow(), lease['start_date']) values['end_date'] = lease['end_date'] specs = ['vcpus', 'memory_mb', 'disk_gb', 'affinity', 'amount'] for key in specs: values[key] = reservation[key] changed_hosts = self.pickup_hosts(reservation['id'], values) if len(changed_hosts['added']) == 0: if reservation['id'] not in reservation_flags: reservation_flags[reservation['id']] = {} reservation_flags[reservation['id']].update( {'missing_resources': True}) db_api.host_allocation_destroy(alloc['id']) LOG.warn( 'Could not find alternative host for reservation %s ' '(lease: %s).', reservation['id'], lease['name']) else: new_host_id = changed_hosts['added'].pop() db_api.host_allocation_update(alloc['id'], {'compute_host_id': new_host_id}) if reservation['status'] == status.reservation.ACTIVE: # Add the alternative host into the aggregate. new_host = db_api.host_get(new_host_id) pool.add_computehost(reservation['aggregate_id'], new_host['service_name'], stay_in=True) if reservation['id'] not in reservation_flags: reservation_flags[reservation['id']] = {} reservation_flags[reservation['id']].update( {'resources_changed': True}) LOG.warn('Resource changed for reservation %s (lease: %s).', reservation['id'], lease['name']) return reservation_flags