OpenStack建立实例完整过程源码详细分析(8)

感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!
如果转载,请保留作者信息。
博客地址:http://blog.csdn.net/gaoxingnengjisuan
邮箱地址:dong.liu@siat.ac.cn


    前面解析完了get_project_quotas方法,现在我们回到方法def _get_quotas(self, context, resources, keys, has_sync, project_id=None):

def _get_quotas(self, context, resources, keys, has_sync, project_id=None):
        """
        这是一个辅助的方法,从数据库获取特定的配额资源信息;
        """

        # 筛选资源;
        if has_sync:
            sync_filt = lambda x: hasattr(x, 'sync')#判断对象x是否包含sync的特性;
        else:
            sync_filt = lambda x: not hasattr(x, 'sync')#判断对象x是否不包含sync的特性;
        desired = set(keys)
        sub_resources = dict((k, v) for k, v in resources.items()
                             if k in desired and sync_filt(v))

        # Make sure we accounted for all of them...
        # 确保所有磁盘配额资源都是已知的,否则引发异常,提示某些磁盘配额资源是未知的;
        if len(keys) != len(sub_resources):
            unknown = desired - set(sub_resources.keys())
            raise exception.QuotaResourceUnknown(unknown=sorted(unknown))

        # Grab and return the quotas (without usages)
        # 获取并返回配额信息;
        quotas = self.get_project_quotas(context, sub_resources,project_id,context.quota_class, usages=False)

        return dict((k, v['limit']) for k, v in quotas.items())
    可见获取了配额信息之后,以字典的方式返回各种资源的配额信息limit值(应该是三种资源:instances、ram、cores):

return dict((k, v['limit']) for k, v in quotas.items())
    我们再回到方法def reserve(self, context, resources, deltas, expire=None, project_id=None):

def reserve(self, context, resources, deltas, expire=None, project_id=None):
        """
        @@@@检测配额和储备资源;
        """

        # 如果expire没有指定,则采用默认参数的值;
        # reservation_expire:这个参数定义了预约(资源配额)的到期时间长度;
        # 参数的默认值为86400;
        if expire is None:
            expire = CONF.reservation_expire
        if isinstance(expire, (int, long)):
            expire = datetime.timedelta(seconds=expire)
        if isinstance(expire, datetime.timedelta):
            expire = timeutils.utcnow() + expire
        if not isinstance(expire, datetime.datetime):
            raise exception.InvalidReservationExpiration(expire=expire)

        # If project_id is None, then we use the project_id in context
        if project_id is None:
            project_id = context.project_id

        # 获取给定对象id值,即project_id确定的对象的配额信息;        
        quotas = self._get_quotas(context, resources, deltas.keys(), has_sync=True, project_id=project_id)

        return db.quota_reserve(context, resources, quotas, deltas, expire,
                                CONF.until_refresh, CONF.max_age,
                                project_id=project_id)
    执行完语句quotas = self._get_quotas(context, resources, deltas.keys(), has_sync=True, project_id=project_id)之后,调试运行得到的返回结果为:

quotas = {instances:10, ram:51200, cores:20}
    至此,方法_get_quotas解析完成,方法主要是完成了为project_id指定对象获取资源配额信息的功能;

b.2.2 解析语句return db.quota_reserve(context, resources, quotas, deltas, expire, CONF.until_refresh, CONF.max_age, project_id=project_id)

    我们来看方法quota_reserve:

def quota_reserve(context, resources, quotas, deltas, expire, until_refresh, max_age, project_id=None):

    elevated = context.elevated()
    # 获取db_session的session;
    # get_session:返回一个SQLAlchemy session,若没有定义,则新建一个SQLAlchemy session;
    session = get_session()
    with session.begin():
        
        # 获取context中的project_id;
        if project_id is None:
            project_id = context.project_id

        # 从quota_usages表中获得当前工程的各种资源的使用情况;
        usages = _get_quota_usages(context, session, project_id)

        # Handle usage refresh
        # 注:deltas.keys() = ['instances', 'ram', 'cores']
        work = set(deltas.keys())
        while work:
            resource = work.pop()

            # Do we need to refresh the usage?
            refresh = False
            if resource not in usages:
                usages[resource] = _quota_usage_create(elevated,project_id,resource,0, 0,until_refresh or None,session=session)
                refresh = True
            elif usages[resource].in_use < 0:
                # Negative in_use count indicates a desync, so try to
                # heal from that...
                refresh = True
            elif usages[resource].until_refresh is not None:
                usages[resource].until_refresh -= 1
                if usages[resource].until_refresh <= 0:
                    refresh = True
            elif max_age and (usages[resource].updated_at - timeutils.utcnow()).seconds >= max_age:
                refresh = True

            # OK, refresh the usage
            if refresh:
                # Grab the sync routine
                sync = resources[resource].sync

                updates = sync(elevated, project_id, session)
                for res, in_use in updates.items():
                    # Make sure we have a destination for the usage!
                    if res not in usages:
                        usages[res] = _quota_usage_create(elevated,project_id,res,0, 0,until_refresh or None,session=session)

                    # Update the usage
                    usages[res].in_use = in_use
                    usages[res].until_refresh = until_refresh or None

                    work.discard(res)

        # Check for deltas that would go negative
        unders = [resource for resource, delta in deltas.items()
                  if delta < 0 and
                  delta + usages[resource].in_use < 0]

        overs = [resource for resource, delta in deltas.items()
                 if quotas[resource] >= 0 and delta >= 0 and
                 quotas[resource] < delta + usages[resource].total]

        # Create the reservations
        if not overs:
            reservations = []
            for resource, delta in deltas.items():
                reservation = reservation_create(elevated,str(uuid.uuid4()),usages[resource],project_id,resource, delta, expire,session=session)
                reservations.append(reservation.uuid)

                if delta > 0:
                    usages[resource].reserved += delta

        # Apply updates to the usages table
        for usage_ref in usages.values():
            usage_ref.save(session=session)

    if unders:
        LOG.warning(_("Change will make usage less than 0 for the following resources: %(unders)s") % locals())
    if overs:
        usages = dict((k, dict(in_use=v['in_use'], reserved=v['reserved'])) for k, v in usages.items())
        raise exception.OverQuota(overs=sorted(overs), quotas=quotas,usages=usages)

    return reservations
    这个方法中包含的内容比较多,主要完成的就是对资源进行配额检测;

    我们先来看一下传进来的参数值:

# 程序运行上下文信息;
context = <nova.context.RequestContext object at 0x4656d10>
# 资源信息;
resources = {'metadata_items': <nova.quota.AbsoluteResource object at 0x276e790>, 'injected_file_content_bytes': <nova.quota.AbsoluteResource object at 0x276e810>, 'ram': <nova.quota.ReservableResource object at 0x276e6d0>, 'floating_ips': <nova.quota.ReservableResource object at 0x276e710>, 'security_group_rules': <nova.quota.CountableResource object at 0x276e8d0>, 'instances': <nova.quota.ReservableResource object at 0x276e650>, 'key_pairs': <nova.quota.CountableResource object at 0x276e910>, 'injected_files': <nova.quota.AbsoluteResource object at 0x276e7d0>, 'cores': <nova.quota.ReservableResource object at 0x276e690>, 'fixed_ips': <nova.quota.ReservableResource object at 0x276e750>, 'injected_file_path_bytes': <nova.quota.AbsoluteResource object at 0x276e850>, 'security_groups': <nova.quota.ReservableResource object at 0x276e890>}
# 已获取的规定的限制的配额信息;
quotas = {'instances': 10, 'ram': 51200, 'cores': 20}
# 建立一个实例要求的资源信息,也就是每建立一个实例或者删除一个实例,资源配额的变化量;
deltas = {'instances': 1, 'ram': 2048L, 'cores': 1L}
# reservations的有效期;
expire = 2013-06-26 15:25:45.288831

until_refresh = 0

max_age = 0
#对象ID值;
project_id = 0e492e86f22e4d19bd523f1e7ca64566
    这里解释一下:

    until_refresh是从配置信息CONF.until_refresh赋值的,它的解释是直到usage刷新,reservations的数目,默认值为0;

    max_age是从配置信息CONF.max_age赋值的,它的解释是刷新usage之间停留的秒数,默认值为0;

    比较容易理解的语句直接就写在代码的注释中。

    下面来看语句:

usages = _get_quota_usages(context, session, project_id)
    这条语句完成了从quota_usages表中获得当前工程的各种资源的使用情况;

    来看方法_get_quota_usages:

def _get_quota_usages(context, session, project_id):
    # 获取资源配额使用信息,以字典的形式返回;
    rows = model_query(context, models.QuotaUsage,
                       read_deleted="no",
                       session=session).\
                   filter_by(project_id=project_id).\
                   with_lockmode('update').\
                   all()
    return dict((row.resource, row) for row in rows)
    类QuotaUsage定义了当前资源的使用情况;

class QuotaUsage(BASE, NovaBase):
    """
    Represents the current usage for a given resource.
    表示一个给定资源当前的使用情况;
    """

    __tablename__ = 'quota_usages'
    id = Column(Integer, primary_key=True)

    project_id = Column(String(255), index=True)
    resource = Column(String(255))

    in_use = Column(Integer)
    reserved = Column(Integer)

    @property
    def total(self):
        return self.in_use + self.reserved

    until_refresh = Column(Integer, nullable=True)
    来看下面一段代码:

if resource not in usages:
    usages[resource] = _quota_usage_create(elevated,project_id,resource,0, 0,until_refresh or None,session=session)
refresh = True
    如果当前的resource不在当前工程所使用的资源列表中,那么就把该资源添加进去,并且在数据库中增加一条相应的记录;为后续查询当前工程当前各种资源的使用情况做准备;

    具体来看一下方法_quota_usage_create:

def _quota_usage_create(context, project_id, resource, in_use, reserved,
                       until_refresh, session=None):
    quota_usage_ref = models.QuotaUsage()
    quota_usage_ref.project_id = project_id
    quota_usage_ref.resource = resource
    quota_usage_ref.in_use = in_use
    quota_usage_ref.reserved = reserved
    quota_usage_ref.until_refresh = until_refresh

    quota_usage_ref.save(session=session)

    return quota_usage_ref
    再看一下类QuotaUsage:

class QuotaUsage(BASE, NovaBase):
    """
    Represents the current usage for a given resource.
    表示一个给定资源当前的使用情况;
    """

    __tablename__ = 'quota_usages'
    id = Column(Integer, primary_key=True)

    project_id = Column(String(255), index=True)
    resource = Column(String(255))

    in_use = Column(Integer)
    reserved = Column(Integer)

    @property
    def total(self):
        return self.in_use + self.reserved

    until_refresh = Column(Integer, nullable=True)
    应该比较好理解了;

    看下一段代码:

elif usages[resource].in_use < 0:
    # Negative in_use count indicates a desync, so try to
    # heal from that...
    refresh = True

elif usages[resource].until_refresh is not None:
    usages[resource].until_refresh -= 1
    if usages[resource].until_refresh <= 0:
        refresh = True

elif max_age and (usages[resource].updated_at - timeutils.utcnow()).seconds >= max_age:
    refresh = True
    这段代码的含义是:

    如果当前的resource在当前工程的使用列表中,并且该资源的in_use小于0,说明资源数据信息不同步,则执行refresh(刷新);

    如果当前的until_refresh不为空,那么将其减1,如果减1之后小于等于0,则执行refresh(刷新);(目前还不是太明白)

    如果max_age不为空,并且该资源更新的时间减去当前的时间大于max_age,说明需要执行refresh(刷新);

    下一篇博文将会继续分析这个方法,接下来将会介绍如何执行refresh(刷新)同步操作的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值