Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
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)