class ESILEAPObject(object_base.VersionedObject): OBJ_SERIAL_NAMESPACE = 'esi_leap_object' OBJ_PROJECT_NAMESPACE = 'esi_leap' fields = { 'created_at': object_fields.DateTimeField(nullable=True), 'updated_at': object_fields.DateTimeField(nullable=True), } @staticmethod def _from_db_object(context, obj, db_obj): for key in obj.fields: setattr(obj, key, db_obj[key]) obj.obj_reset_changes() obj._context = context return obj @classmethod def _from_db_object_list(cls, context, db_objs): return [ cls._from_db_object(context, cls(), db_obj) for db_obj in db_objs ] def to_dict(self): def _attr_as_dict(field): attr = getattr(self, field) if isinstance(attr, ESILEAPObject): attr = attr.as_dict() return attr return dict((k, getattr(self, k)) for k in self.fields if self.obj_attr_is_set(k))
class Contract(base.ESILEAPObject): dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'name': fields.StringField(nullable=True), 'uuid': fields.UUIDField(), 'project_id': fields.StringField(), 'start_time': fields.DateTimeField(nullable=True), 'end_time': fields.DateTimeField(nullable=True), 'fulfill_time': fields.DateTimeField(nullable=True), 'expire_time': fields.DateTimeField(nullable=True), 'status': fields.StringField(), 'properties': fields.FlexibleDictField(nullable=True), 'offer_uuid': fields.UUIDField(), } @classmethod def get(cls, contract_uuid, context=None): db_contract = cls.dbapi.contract_get_by_uuid(contract_uuid) if db_contract: return cls._from_db_object(context, cls(), db_contract) @classmethod def get_all(cls, filters, context=None): db_contracts = cls.dbapi.contract_get_all(filters) return cls._from_db_object_list(context, db_contracts) def create(self, context=None): updates = self.obj_get_changes() @utils.synchronized(utils.get_offer_lock_name(updates['offer_uuid']), external=True) def _create_contract(): if updates['start_time'] >= updates['end_time']: raise exception.InvalidTimeRange( resource='contract', start_time=str(updates['start_time']), end_time=str(updates['end_time'])) related_offer = self.dbapi.offer_get_by_uuid(updates['offer_uuid']) if related_offer.status != statuses.AVAILABLE: raise exception.OfferNotAvailable( offer_uuid=related_offer.uuid, status=related_offer.status) self.dbapi.offer_verify_contract_availability( related_offer, updates['start_time'], updates['end_time']) db_contract = self.dbapi.contract_create(updates) self._from_db_object(context, self, db_contract) _create_contract() def cancel(self): o = Offer.get(self.offer_uuid) resource = o.resource_object() if resource.get_contract_uuid() == self.uuid: resource.expire_contract(self) self.status = statuses.CANCELLED self.expire_time = datetime.datetime.now() self.save(None) def destroy(self): self.dbapi.contract_destroy(self.uuid) self.obj_reset_changes() def save(self, context=None): updates = self.obj_get_changes() db_contract = self.dbapi.contract_update(self.uuid, updates) self._from_db_object(context, self, db_contract) def fulfill(self, context=None): @utils.synchronized(utils.get_offer_lock_name(self.offer_uuid), external=True) def _fulfill_contract(): o = Offer.get(self.offer_uuid, context) resource = o.resource_object() resource.set_contract(self) # activate contract self.status = statuses.ACTIVE self.fulfill_time = datetime.datetime.now() self.save(context) _fulfill_contract() def expire(self, context=None): # unassign resource o = Offer.get(self.offer_uuid, context) resource = o.resource_object() if resource.get_contract_uuid() == self.uuid: resource.expire_contract(self) # expire contract self.status = statuses.EXPIRED self.expire_time = datetime.datetime.now() self.save(context)
class Offer(base.ESILEAPObject): dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'name': fields.StringField(nullable=True), 'uuid': fields.UUIDField(), 'project_id': fields.StringField(), 'lessee_id': fields.StringField(nullable=True), 'resource_type': fields.StringField(), 'resource_uuid': fields.StringField(), 'start_time': fields.DateTimeField(nullable=True), 'end_time': fields.DateTimeField(nullable=True), 'status': fields.StringField(), 'properties': fields.FlexibleDictField(nullable=True), 'parent_lease_uuid': fields.UUIDField(nullable=True), } @classmethod def get(cls, offer_uuid, context=None): db_offer = cls.dbapi.offer_get_by_uuid(offer_uuid) if db_offer: return cls._from_db_object(context, cls(), db_offer) @classmethod def get_all(cls, filters, context=None): db_offers = cls.dbapi.offer_get_all(filters) return cls._from_db_object_list(context, db_offers) def get_availabilities(self): if self.status != statuses.AVAILABLE: return [] conflicts = self.dbapi.offer_get_conflict_times(self) now = datetime.datetime.now() start_time = self.start_time if self.start_time >= now else now if conflicts: # if the conflicts are all in the past: if conflicts[-1][1] <= start_time: avails = [[start_time, self.end_time]] else: # if the offer starts in the future or # the first conflict time is in the future, # add the $start_time and first conflict start_time # in the array if start_time < conflicts[0][0]: times = [start_time, conflicts[0][0]] for i in range(len(conflicts) - 1): times.append(conflicts[i][1]) times.append(conflicts[i + 1][0]) else: times = [] for i in range(len(conflicts) - 1): # Find the conflict timeframe that started # in the past and will end in the future. # add all times after this if (conflicts[i][0] <= start_time and conflicts[i][1] > start_time) \ or conflicts[i][0] > start_time: times.append(conflicts[i][1]) times.append(conflicts[i + 1][0]) times.append(conflicts[-1][1]) times.append(self.end_time) i = 0 while i < len(times) - 1: if times[i] == times[i + 1]: times.pop(i) times.pop(i) else: i += 1 avails = [[times[j], times[j + 1]] for j in range(0, len(times) - 1, 2)] else: avails = [[start_time, self.end_time]] return avails def get_first_availability(self, start): return self.dbapi.offer_get_first_availability(self.uuid, start) def create(self, context=None): updates = self.obj_get_changes() with utils.lock(utils.get_resource_lock_name(updates['resource_type'], updates['resource_uuid']), external=True): LOG.info('Creating offer') if updates['start_time'] >= updates['end_time']: raise exception.InvalidTimeRange( resource='offer', start_time=str(updates['start_time']), end_time=str(updates['end_time'])) if updates.get('parent_lease_uuid'): # offer is a child of an existing lease parent_lease = lease_obj.Lease.get( updates['parent_lease_uuid']) if parent_lease.status != statuses.ACTIVE: raise exception.LeaseNotActive( updates['parent_lease_uuid']) parent_lease.verify_child_availability(updates['start_time'], updates['end_time']) else: ro = get_resource_object(updates['resource_type'], updates['resource_uuid']) ro.verify_availability(updates['start_time'], updates['end_time']) db_offer = self.dbapi.offer_create(updates) self._from_db_object(context, self, db_offer) def cancel(self): LOG.info('Deleting offer %s', self.uuid) leases = lease_obj.Lease.get_all( { 'offer_uuid': self.uuid, 'status': statuses.LEASE_CAN_DELETE }, None) for lease in leases: lease.cancel() with utils.lock(utils.get_resource_lock_name(self.resource_type, self.resource_uuid), external=True): self.status = statuses.DELETED self.save(None) def expire(self, context=None): LOG.info('Expiring offer %s', self.uuid) leases = lease_obj.Lease.get_all( { 'offer_uuid': self.uuid, 'status': statuses.LEASE_CAN_DELETE }, None) for lease in leases: lease.expire(context) with utils.lock(utils.get_resource_lock_name(self.resource_type, self.resource_uuid), external=True): self.status = statuses.EXPIRED self.save(context) def verify_availability(self, start_time, end_time): return self.dbapi.offer_verify_availability(self, start_time, end_time) def destroy(self): self.dbapi.offer_destroy(self.uuid) self.obj_reset_changes() def save(self, context=None): updates = self.obj_get_changes() db_offer = self.dbapi.offer_update(self.uuid, updates) self._from_db_object(context, self, db_offer) def resource_object(self): return get_resource_object(self.resource_type, self.resource_uuid)
class Contract(base.ESILEAPObject): dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.UUIDField(), 'project_id': fields.StringField(), 'start_date': fields.DateTimeField(nullable=True), 'end_date': fields.DateTimeField(nullable=True), 'status': fields.StringField(), 'properties': fields.FlexibleDictField(nullable=True), 'offer_uuid': fields.UUIDField(), 'marketplace_offer_contract_relationship_id': fields.UUIDField() } @classmethod def get(cls, context, contract_uuid): db_contract = cls.dbapi.contract_get(context, contract_uuid) return cls._from_db_object(context, cls(), db_contract) @classmethod def get_all(cls, context): db_contracts = cls.dbapi.contract_get_all(context) return cls._from_db_object_list(context, db_contracts) @classmethod def get_all_by_project_id(cls, context, project_id): db_contracts = cls.dbapi.contract_get_all_by_project_id( context, project_id) return cls._from_db_object_list(context, db_contracts) @classmethod def get_all_by_offer_uuid(cls, context, offer_uuid): db_contracts = cls.dbapi.contract_get_all_by_offer_uuid( context, offer_uuid) return cls._from_db_object_list(context, db_contracts) @classmethod def get_all_by_status(cls, context, status): db_contracts = cls.dbapi.contract_get_all_by_status( context, status) return cls._from_db_object_list(context, db_contracts) def create(self, context=None): updates = self.obj_get_changes() db_contract = self.dbapi.contract_create(context, updates) self._from_db_object(context, self, db_contract) def destroy(self, context=None): self.dbapi.contract_destroy(context, self.uuid) self.obj_reset_changes() def save(self, context=None): updates = self.obj_get_changes() db_contract = self.dbapi.contract_update( context, self.uuid, updates) self._from_db_object(context, self, db_contract) def fulfill(self, context=None): # fulfill resource o = esi_leap.objects.offer.Offer.get( context, self.offer_uuid) resource = o.resource_object() resource.set_contract(self) # expire contract self.status = statuses.FULFILLED self.save(context) def expire(self, context=None): # unassign resource o = esi_leap.objects.offer.Offer.get( context, self.offer_uuid) resource = o.resource_object() if resource.get_contract_uuid() == self.uuid: resource.set_contract(None) # expire contract self.status = statuses.EXPIRED self.save(context)
class Lease(base.ESILEAPObject): dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'name': fields.StringField(nullable=True), 'uuid': fields.UUIDField(), 'project_id': fields.StringField(), 'owner_id': fields.StringField(), 'resource_type': fields.StringField(), 'resource_uuid': fields.StringField(), 'start_time': fields.DateTimeField(nullable=True), 'end_time': fields.DateTimeField(nullable=True), 'fulfill_time': fields.DateTimeField(nullable=True), 'expire_time': fields.DateTimeField(nullable=True), 'status': fields.StringField(), 'properties': fields.FlexibleDictField(nullable=True), 'offer_uuid': fields.UUIDField(nullable=True), 'parent_lease_uuid': fields.UUIDField(nullable=True), } @classmethod def get(cls, lease_uuid, context=None): db_lease = cls.dbapi.lease_get_by_uuid(lease_uuid) if db_lease: return cls._from_db_object(context, cls(), db_lease) @classmethod def get_all(cls, filters, context=None): db_leases = cls.dbapi.lease_get_all(filters) return cls._from_db_object_list(context, db_leases) def create(self, context=None): updates = self.obj_get_changes() with utils.lock(utils.get_resource_lock_name(updates['resource_type'], updates['resource_uuid']), external=True): if updates['start_time'] >= updates['end_time']: raise exception.InvalidTimeRange( resource='lease', start_time=str(updates['start_time']), end_time=str(updates['end_time'])) # check availability if 'offer_uuid' in updates: # lease is being created from an offer related_offer = offer_obj.Offer.get(updates['offer_uuid']) if related_offer.status != statuses.AVAILABLE: raise exception.OfferNotAvailable( offer_uuid=related_offer.uuid, status=related_offer.status) related_offer.verify_availability(updates['start_time'], updates['end_time']) elif 'parent_lease_uuid' in updates: # lease is a child of an existing lease parent_lease = Lease.get(updates['parent_lease_uuid']) if parent_lease.status != statuses.ACTIVE: raise exception.LeaseNotActive( updates['parent_lease_uuid']) parent_lease.verify_child_availability(updates['start_time'], updates['end_time']) else: ro = get_resource_object(updates['resource_type'], updates['resource_uuid']) ro.verify_availability(updates['start_time'], updates['end_time']) db_lease = self.dbapi.lease_create(updates) self._from_db_object(context, self, db_lease) def cancel(self): leases = Lease.get_all( { 'parent_lease_uuid': self.uuid, 'status': statuses.LEASE_CAN_DELETE }, None) for lease in leases: lease.cancel() offers = offer_obj.Offer.get_all( { 'parent_lease_uuid': self.uuid, 'status': statuses.OFFER_CAN_DELETE }, None) for offer in offers: offer.cancel() with utils.lock(utils.get_resource_lock_name(self.resource_type, self.resource_uuid), external=True): LOG.info('Deleting lease %s', self.uuid) try: resource = self.resource_object() if resource.get_lease_uuid() == self.uuid: resource.expire_lease(self) if self.parent_lease_uuid is not None: parent_lease = Lease.get(self.parent_lease_uuid) resource.set_lease(parent_lease) self.status = statuses.DELETED self.expire_time = datetime.datetime.now() except Exception as e: LOG.info('Error canceling lease: %s: %s' % (type(e).__name__, e)) LOG.info('Setting lease status to WAIT') self.status = statuses.WAIT_CANCEL self.save(None) def destroy(self): self.dbapi.lease_destroy(self.uuid) self.obj_reset_changes() def save(self, context=None): updates = self.obj_get_changes() db_lease = self.dbapi.lease_update(self.uuid, updates) self._from_db_object(context, self, db_lease) def fulfill(self, context=None): with utils.lock(utils.get_resource_lock_name(self.resource_type, self.resource_uuid), external=True): LOG.info('Fulfilling lease %s', self.uuid) try: resource = self.resource_object() resource.set_lease(self) # activate lease self.status = statuses.ACTIVE self.fulfill_time = datetime.datetime.now() except Exception as e: LOG.info('Error fulfilling lease: %s: %s' % (type(e).__name__, e)) LOG.info('Setting lease status to WAIT') self.status = statuses.WAIT_FULFILL self.save(context) def expire(self, context=None): leases = Lease.get_all( { 'parent_lease_uuid': self.uuid, 'status': statuses.LEASE_CAN_DELETE }, None) for lease in leases: lease.expire(context) offers = offer_obj.Offer.get_all( { 'parent_lease_uuid': self.uuid, 'status': statuses.OFFER_CAN_DELETE }, None) for offer in offers: offer.expire(context) with utils.lock(utils.get_resource_lock_name(self.resource_type, self.resource_uuid), external=True): LOG.info('Expiring lease %s', self.uuid) try: resource = self.resource_object() if resource.get_lease_uuid() == self.uuid: resource.expire_lease(self) if self.parent_lease_uuid is not None: parent_lease = Lease.get(self.parent_lease_uuid) resource.set_lease(parent_lease) # expire lease self.status = statuses.EXPIRED self.expire_time = datetime.datetime.now() except Exception as e: LOG.info('Error expiring lease: %s: %s' % (type(e).__name__, e)) LOG.info('Setting lease status to WAIT') self.status = statuses.WAIT_EXPIRE self.save(context) def resource_object(self): return get_resource_object(self.resource_type, self.resource_uuid) def verify_child_availability(self, start_time, end_time): return self.dbapi.lease_verify_child_availability( self, start_time, end_time)
class Offer(base.ESILEAPObject): dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'uuid': fields.UUIDField(), 'project_id': fields.StringField(), 'resource_type': fields.StringField(), 'resource_uuid': fields.StringField(), 'start_date': fields.DateTimeField(nullable=True), 'end_date': fields.DateTimeField(nullable=True), 'status': fields.StringField(), 'properties': fields.FlexibleDictField(nullable=True), } @classmethod def get(cls, context, offer_uuid): db_offer = cls.dbapi.offer_get(context, offer_uuid) return cls._from_db_object(context, cls(), db_offer) @classmethod def get_all(cls, context): db_offers = cls.dbapi.offer_get_all(context) return cls._from_db_object_list(context, db_offers) @classmethod def get_all_by_project_id(cls, context, project_id): db_offers = cls.dbapi.offer_get_all_by_project_id(context, project_id) return cls._from_db_object_list(context, db_offers) @classmethod def get_all_by_status(cls, context, status): db_offers = cls.dbapi.offer_get_all_by_status(context, status) return cls._from_db_object_list(context, db_offers) def send_to_flocx_market(self): auth_plugin = ks_loading.load_auth_from_conf_options( CONF, 'flocx_market') sess = ks_loading.load_session_from_conf_options(CONF, 'flocx_market', auth=auth_plugin) marketplace_offer_dict = self.to_marketplace_dict() adpt = adapter.Adapter(session=sess, service_type='marketplace', interface='public') marketplace_client = flocx_market_client.FlocxMarketClient(adpt) res_status_code = marketplace_client.send_offer(marketplace_offer_dict) return res_status_code def create(self, context=None): updates = self.obj_get_changes() db_offer = self.dbapi.offer_create(context, updates) o = self._from_db_object(context, self, db_offer) return o.send_to_flocx_market() def destroy(self, context=None): self.dbapi.offer_destroy(context, self.uuid) self.obj_reset_changes() def save(self, context=None): updates = self.obj_get_changes() db_offer = self.dbapi.offer_update(context, self.uuid, updates) self._from_db_object(context, self, db_offer) def resource_object(self): return ro_factory.ResourceObjectFactory.get_resource_object( self.resource_type, self.resource_uuid) def expire(self, context=None): # make sure all related contracts are expired contracts = esi_leap.objects.contract.Contract.get_all_by_offer_uuid( context, self.uuid) for c in contracts: if c.status != statuses.EXPIRED: c.expire(context) # expire offer self.status = statuses.EXPIRED self.save(context) def to_marketplace_dict(self): # change fields name offer_dict = self.to_dict() offer_dict['start_time'] = offer_dict.pop('start_date').isoformat() offer_dict['end_time'] = offer_dict.pop('end_date').isoformat() offer_dict['cost'] = offer_dict['properties'].get('floor_price', 0) offer_dict['server_config'] = offer_dict.pop('properties') offer_dict['server_id'] = offer_dict.pop('resource_uuid') offer_dict['provider_id'] = offer_dict.pop('uuid') offer_dict['creator_id'] = offer_dict.pop('project_id') # remove unnecessary feilds offer_dict.pop('created_at') offer_dict.pop('updated_at') offer_dict.pop('id') offer_dict.pop('resource_type') # fake fields offer_dict['marketplace_date_created'] = datetime.datetime.utcnow() return offer_dict
class Offer(base.ESILEAPObject): dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'name': fields.StringField(nullable=True), 'uuid': fields.UUIDField(), 'project_id': fields.StringField(), 'resource_type': fields.StringField(), 'resource_uuid': fields.StringField(), 'start_time': fields.DateTimeField(nullable=True), 'end_time': fields.DateTimeField(nullable=True), 'status': fields.StringField(), 'properties': fields.FlexibleDictField(nullable=True), } @classmethod def get_by_uuid(cls, offer_uuid, context=None): db_offer = cls.dbapi.offer_get_by_uuid(offer_uuid) if db_offer: return cls._from_db_object(context, cls(), db_offer) @classmethod def get_by_name(cls, offer_name, context=None): db_contract = cls.dbapi.offer_get_by_name(offer_name) return cls._from_db_object_list(context, db_contract) @classmethod def get(cls, offer_id, context=None): o_uuid = cls.get_by_uuid(offer_id, context) if o_uuid: return [o_uuid] o_name = cls.get_by_name(offer_id, context) return o_name @classmethod def get_all(cls, context, filters): db_offers = cls.dbapi.offer_get_all(filters) return cls._from_db_object_list(context, db_offers) def get_availabilities(self): if self.status != statuses.AVAILABLE: return [] conflicts = self.dbapi.offer_get_conflict_times(self) if conflicts: a = [self.start_time, conflicts[0][0]] for i in range(len(conflicts) - 1): a.append(conflicts[i][1]) a.append(conflicts[i + 1][0]) a.append(conflicts[-1][1]) a.append(self.end_time) i = 0 while i < len(a) - 1: if a[i] == a[i + 1]: a.pop(i) a.pop(i) else: i += 1 a = [[a[j], a[j + 1]] for j in range(0, len(a) - 1, 2)] else: a = [[self.start_time, self.end_time]] return a def get_first_availability(self, start): return self.dbapi.offer_get_first_availability(self.uuid, start) def create(self, context=None): updates = self.obj_get_changes() self.dbapi.offer_verify_resource_availability(updates['resource_type'], updates['resource_uuid'], updates['start_time'], updates['end_time']) db_offer = self.dbapi.offer_create(updates) self._from_db_object(context, self, db_offer) def cancel(self): contracts = esi_leap.objects.contract.Contract.get_all( None, {'offer_uuid': self.uuid}) for c in contracts: if c.status == statuses.CREATED or c.status == statuses.ACTIVE: c.cancel() self.status = statuses.CANCELLED self.save(None) def destroy(self): self.dbapi.offer_destroy(self.uuid) self.obj_reset_changes() def save(self, context=None): updates = self.obj_get_changes() db_offer = self.dbapi.offer_update( self.uuid, updates) self._from_db_object(context, self, db_offer) def resource_object(self): return ro_factory.ResourceObjectFactory.get_resource_object( self.resource_type, self.resource_uuid) def expire(self, context=None): # make sure all related contracts are expired contracts = esi_leap.objects.contract.Contract.get_all( None, {'offer_uuid': self.uuid}) for c in contracts: if c.status != statuses.EXPIRED: c.expire(context) # expire offer self.status = statuses.EXPIRED self.save(context)
class Contract(base.ESILEAPObject): dbapi = dbapi.get_instance() fields = { 'id': fields.IntegerField(), 'name': fields.StringField(nullable=True), 'uuid': fields.UUIDField(), 'project_id': fields.StringField(), 'start_time': fields.DateTimeField(nullable=True), 'end_time': fields.DateTimeField(nullable=True), 'status': fields.StringField(), 'properties': fields.FlexibleDictField(nullable=True), 'offer_uuid': fields.UUIDField(), } @classmethod def get_by_uuid(cls, contract_uuid, context=None): db_contract = cls.dbapi.contract_get_by_uuid(contract_uuid) if db_contract: return cls._from_db_object(context, cls(), db_contract) @classmethod def get_by_name(cls, contract_name, context=None): db_contract = cls.dbapi.contract_get_by_name(contract_name) return cls._from_db_object_list(context, db_contract) @classmethod def get(cls, contract_id, context=None): c_uuid = cls.get_by_uuid(contract_id, context) if c_uuid: return [c_uuid] c_name = cls.get_by_name(contract_id, context) return c_name @classmethod def get_all(cls, context, filters): db_contracts = cls.dbapi.contract_get_all(filters) return cls._from_db_object_list(context, db_contracts) def create(self, context=None): updates = self.obj_get_changes() updates['uuid'] = uuidutils.generate_uuid() if 'offer_uuid' not in updates: raise exception.ContractNoOfferUUID() related_offer = self.dbapi.offer_get_by_uuid(updates['offer_uuid']) if related_offer is None: raise exception.OfferNotFound(offer_uuid=updates['offer_uuid']) if related_offer.status != statuses.AVAILABLE: raise exception.OfferNotAvailable(offer_uuid=related_offer.uuid, status=related_offer.status) if 'start_time' not in updates: updates['start_time'] = datetime.datetime.now() if 'end_time' not in updates: q = self.dbapi.offer_get_first_availability(related_offer, updates['start_time']) if q is None: updates['end_time'] = related_offer.end_time else: updates['end_time'] = q.start_time self.dbapi.offer_verify_availability(related_offer, updates['start_time'], updates['end_time']) db_contract = self.dbapi.contract_create(updates) self._from_db_object(context, self, db_contract) def cancel(self): o = esi_leap.objects.offer.Offer.get_by_uuid(self.offer_uuid) resource = o.resource_object() if resource.get_contract_uuid() == self.uuid: resource.set_contract(None) self.status = statuses.CANCELLED self.save(None) def destroy(self): self.dbapi.contract_destroy(self.uuid) self.obj_reset_changes() def save(self, context=None): updates = self.obj_get_changes() db_contract = self.dbapi.contract_update( self.uuid, updates) self._from_db_object(context, self, db_contract) def fulfill(self, context=None): # fulfill resource o = esi_leap.objects.offer.Offer.get_by_uuid(self.offer_uuid, context) resource = o.resource_object() resource.set_contract(self) # activate contract self.status = statuses.ACTIVE self.save(context) def expire(self, context=None): # unassign resource o = esi_leap.objects.offer.Offer.get_by_uuid(self.offer_uuid, context) if o.status != statuses.AVAILABLE: raise exception.OfferNotAvailable(offer_uuid=o.uuid, status=o.status) resource = o.resource_object() if resource.get_contract_uuid() == self.uuid: resource.set_contract(None) # expire contract self.status = statuses.EXPIRED self.save(context)