def _event(self): """Tries to commit event. If there is an event in Climate DB to be done, do it and change its status to 'DONE'. """ LOG.debug('Trying to get event from DB.') event = db_api.event_get_first_sorted_by_filters( sort_key='time', sort_dir='asc', filters={'status': 'UNDONE'} ) if not event: return if event['time'] < datetime.datetime.utcnow(): db_api.event_update(event['id'], {'status': 'IN_PROGRESS'}) event_type = event['event_type'] event_fn = getattr(self, event_type, None) if event_fn is None: raise exceptions.EventError(error='Event type %s is not ' 'supported' % event_type) try: eventlet.spawn_n(service_utils.with_empty_context(event_fn), event['lease_id'], event['id']) 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_type]) except Exception: db_api.event_update(event['id'], {'status': 'ERROR'}) LOG.exception(_('Error occurred while event handling.'))
def _event(self): """Tries to commit event. If there is an event in Climate DB to be done, do it and change its status to 'DONE'. """ LOG.debug('Trying to get event from DB.') event = db_api.event_get_first_sorted_by_filters( sort_key='time', sort_dir='asc', filters={'status': 'UNDONE'} ) if not event: return if event['time'] < datetime.datetime.now(): db_api.event_update(event['id'], {'status': 'IN_PROGRESS'}) event_type = event['event_type'] event_fn = getattr(self, event_type, None) if event_fn is None: raise exceptions.EventError(error='Event type %s is not ' 'supported' % event_type) try: eventlet.spawn_n(service_utils.with_empty_context(event_fn), event['lease_id'], event['id']) 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_type]) except Exception: db_api.event_update(event['id'], {'status': 'ERROR'}) LOG.exception(_('Error occurred while event handling.'))
def create_lease(self, lease_values): start_date = lease_values['start_date'] end_date = lease_values['end_date'] if start_date == 'now': start_date = datetime.datetime.utcnow() else: start_date = datetime.datetime.strptime(start_date, "%Y-%m-%d %H:%M") end_date = datetime.datetime.strptime(end_date, "%Y-%m-%d %H:%M") lease_values['start_date'] = start_date lease_values['end_date'] = end_date if not lease_values.get('events'): lease_values['events'] = [] lease_values['events'].append({'event_type': 'start_lease', 'time': start_date, 'status': 'UNDONE'}) lease_values['events'].append({'event_type': 'end_lease', 'time': end_date, 'status': 'UNDONE'}) lease = db_api.lease_create(lease_values) return db_api.lease_get(lease['id'])
def __init__(self, id, autosave=True, action=None, status=None, status_reason=None): if action is None or status is None: # NOTE(sbauza): The lease can be not yet in DB, so lease_get can # return None lease = db_api.lease_get(id) or {} action = lease.get("action", action) status = lease.get("status", status) status_reason = lease.get("status_reason", status_reason) super(LeaseState, self).__init__(id, autosave, action, status, status_reason)
def create_lease(self, lease_values): """Create a lease with reservations. Return either the model of created lease or None if any error. """ # Remove and keep reservation values reservations = lease_values.pop("reservations", []) # Create the lease without the reservations start_date = lease_values["start_date"] end_date = lease_values["end_date"] if start_date == "now": start_date = datetime.datetime.utcnow() else: start_date = datetime.datetime.strptime(start_date, "%Y-%m-%d %H:%M") end_date = datetime.datetime.strptime(end_date, "%Y-%m-%d %H:%M") ctx = context.current() lease_values["user_id"] = ctx.user_id lease_values["tenant_id"] = ctx.tenant_id lease_values["start_date"] = start_date lease_values["end_date"] = end_date if not lease_values.get("events"): lease_values["events"] = [] lease_values["events"].append({"event_type": "start_lease", "time": start_date, "status": "UNDONE"}) lease_values["events"].append({"event_type": "end_lease", "time": end_date, "status": "UNDONE"}) # TODO(scroiset): catch DB Exception when they will become alive # see bug #1237293 try: lease = db_api.lease_create(lease_values) lease_id = lease["id"] except RuntimeError: LOG.exception("Cannot create a lease") else: try: for reservation in reservations: reservation["lease_id"] = lease["id"] reservation["start_date"] = lease["start_date"] reservation["end_date"] = lease["end_date"] resource_type = reservation["resource_type"] self.plugins[resource_type].create_reservation(reservation) except RuntimeError: LOG.exception( "Failed to create reservation for a lease. " "Rollback the lease and associated reservations" ) db_api.lease_destroy(lease_id) else: return db_api.lease_get(lease["id"])
def __init__(self, id, autosave=True, action=None, status=None, status_reason=None): if action is None or status is None: # NOTE(sbauza): The lease can be not yet in DB, so lease_get can # return None lease = db_api.lease_get(id) or {} action = lease.get('action', action) status = lease.get('status', status) status_reason = lease.get('status_reason', status_reason) super(LeaseState, self).__init__(id, autosave, action, status, status_reason)
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_notification', None) now = datetime.datetime.now() 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) 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 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.ClimateException as e: LOG.error("Invalid before_end_date param. %s" % e.message) raise e # TODO(frossigneux) rollback if an exception is raised for reservation in ( db_api.reservation_get_all_by_lease_id(lease_id)): reservation['start_date'] = values['start_date'] reservation['end_date'] = values['end_date'] resource_type = reservation['resource_type'] self.plugins[resource_type].update_reservation( reservation['id'], reservation) 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.ClimateException( '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.ClimateException( '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) 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. """ try: trust_id = lease_values.pop('trust_id') except KeyError: raise exceptions.MissingTrustId() # Remove and keep reservation values reservations = lease_values.pop("reservations", []) # Create the lease without the reservations start_date = lease_values['start_date'] end_date = lease_values['end_date'] now = datetime.datetime.now() 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) end_date = self._date_from_string(end_date) if start_date < now: raise common_ex.NotAuthorized( 'Start date must later than current date') with trusts.create_ctx_from_trust(trust_id) as ctx: lease_values['user_id'] = ctx.user_id lease_values['project_id'] = ctx.project_id lease_values['start_date'] = start_date lease_values['end_date'] = end_date if not lease_values.get('events'): lease_values['events'] = [] lease_values['events'].append({'event_type': 'start_lease', 'time': start_date, 'status': 'UNDONE'}) lease_values['events'].append({'event_type': 'end_lease', 'time': end_date, 'status': 'UNDONE'}) before_end_date = lease_values.get('before_end_notification', 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.ClimateException as e: LOG.error("Invalid before_end_date param. %s" % e.message) raise e elif CONF.manager.notify_hours_before_lease_end > 0: delta = datetime.timedelta( hours=CONF.manager.notify_hours_before_lease_end) before_end_date = lease_values['end_date'] - delta if before_end_date: event = {'event_type': 'before_end_lease', 'status': 'UNDONE'} lease_values['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.ClimateDBDuplicateEntry: LOG.exception('Cannot create a lease - duplicated lease name') raise exceptions.LeaseNameAlreadyExists( name=lease_values['name']) except db_ex.ClimateDBException: 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'] resource_type = reservation['resource_type'] if resource_type in self.plugins: self.plugins[resource_type].create_reservation( reservation) else: raise exceptions.UnsupportedResourceType( resource_type) except (exceptions.UnsupportedResourceType, common_ex.ClimateException): LOG.exception("Failed to create reservation for a lease. " "Rollback the lease and associated " "reservations") db_api.lease_destroy(lease_id) raise else: 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 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_notification', 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) 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 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.ClimateException as e: LOG.error("Invalid before_end_date param. %s" % e.message) raise e # TODO(frossigneux) rollback if an exception is raised for reservation in ( db_api.reservation_get_all_by_lease_id(lease_id)): reservation['start_date'] = values['start_date'] reservation['end_date'] = values['end_date'] resource_type = reservation['resource_type'] self.plugins[resource_type].update_reservation( reservation['id'], reservation) 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.ClimateException( '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.ClimateException( '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) db_api.lease_update(lease_id, values) lease_state = states.LeaseState(id=lease_id, action=states.lease.UPDATE, status=states.lease.COMPLETE, status_reason="Successfully updated lease") lease_state.save() 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. """ try: trust_id = lease_values.pop('trust_id') except KeyError: raise exceptions.MissingTrustId() # Remove and keep reservation values reservations = lease_values.pop("reservations", []) # Create the lease without the reservations start_date = lease_values['start_date'] end_date = lease_values['end_date'] 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) end_date = self._date_from_string(end_date) if start_date < now: raise common_ex.NotAuthorized( 'Start date must later than current date') with trusts.create_ctx_from_trust(trust_id) as ctx: lease_values['user_id'] = ctx.user_id lease_values['project_id'] = ctx.project_id lease_values['start_date'] = start_date lease_values['end_date'] = end_date if not lease_values.get('events'): lease_values['events'] = [] lease_values['events'].append({'event_type': 'start_lease', 'time': start_date, 'status': 'UNDONE'}) lease_values['events'].append({'event_type': 'end_lease', 'time': end_date, 'status': 'UNDONE'}) before_end_date = lease_values.get('before_end_notification', 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.ClimateException as e: LOG.error("Invalid before_end_date param. %s" % e.message) raise e elif CONF.manager.notify_hours_before_lease_end > 0: delta = datetime.timedelta( hours=CONF.manager.notify_hours_before_lease_end) before_end_date = lease_values['end_date'] - delta if before_end_date: event = {'event_type': 'before_end_lease', 'status': 'UNDONE'} lease_values['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.ClimateDBDuplicateEntry: LOG.exception('Cannot create a lease - duplicated lease name') raise exceptions.LeaseNameAlreadyExists( name=lease_values['name']) except db_ex.ClimateDBException: 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'] resource_type = reservation['resource_type'] if resource_type in self.plugins: self.plugins[resource_type].create_reservation( reservation) else: raise exceptions.UnsupportedResourceType( resource_type) except (exceptions.UnsupportedResourceType, common_ex.ClimateException): LOG.exception("Failed to create reservation for a lease. " "Rollback the lease and associated " "reservations") db_api.lease_destroy(lease_id) raise else: lease_state = states.LeaseState(id=lease['id'], action=states.lease.CREATE, status=states.lease.COMPLETE, status_reason="Successfully created lease") lease_state.save() lease = db_api.lease_get(lease['id']) self._send_notification(lease, ctx, events=['create']) return lease
def update_reservation(self, reservation_id, values): """Update reservation.""" reservation = db_api.reservation_get(reservation_id) lease = db_api.lease_get(reservation['lease_id']) pool = rp.ReservationPool() hosts_in_pool = pool.get_computehosts( reservation['resource_id']) if (values['start_date'] < lease['start_date'] or values['end_date'] > lease['end_date']): allocations = [] for allocation in db_api.host_allocation_get_all_by_values( reservation_id=reservation_id): full_periods = db_utils.get_full_periods( allocation['compute_host_id'], values['start_date'], values['end_date'], datetime.timedelta(seconds=1)) if lease['start_date'] < values['start_date']: max_start = values['start_date'] else: max_start = lease['start_date'] if lease['end_date'] < values['end_date']: min_end = lease['end_date'] else: min_end = values['end_date'] if not (len(full_periods) == 0 or (len(full_periods) == 1 and full_periods[0][0] == max_start and full_periods[0][1] == min_end)): allocations.append(allocation) if (hosts_in_pool and self.nova.hypervisors.get( self._get_hypervisor_from_name_or_id( allocation['compute_host_id']) ).__dict__['running_vms'] > 0): raise manager_ex.NotEnoughHostsAvailable() if allocations: host_reservation = ( db_api.host_reservation_get_by_reservation_id( reservation_id)) host_ids = self._matching_hosts( host_reservation['hypervisor_properties'], host_reservation['resource_properties'], str(len(allocations)) + '-' + str(len(allocations)), values['start_date'], values['end_date']) if not host_ids: raise manager_ex.NotEnoughHostsAvailable() if hosts_in_pool: old_hosts = [allocation['compute_host_id'] for allocation in allocations] pool.remove_computehost(reservation['resource_id'], old_hosts) for allocation in allocations: db_api.host_allocation_destroy(allocation['id']) for host_id in host_ids: db_api.host_allocation_create( {'compute_host_id': host_id, 'reservation_id': reservation_id}) if hosts_in_pool: host = db_api.host_get(host_id) pool.add_computehost(reservation['resource_id'], host['service_name'])
def update_lease(self, lease_id, values): if values: db_api.lease_update(lease_id, values) return db_api.lease_get(lease_id)