예제 #1
0
def _resource_classes_sync(ctx):
    # Create a set of all resource class in the os_resource_classes library.
    sel = sa.select([_RC_TBL.c.name])
    res = ctx.session.execute(sel).fetchall()
    db_classes = [r[0] for r in res if not orc.is_custom(r[0])]
    LOG.debug("Found existing resource classes in db: %s", db_classes)
    # Determine those resource clases which are in os_resource_classes but not
    # currently in the database, and insert them.
    batch_args = [{
        'name': six.text_type(name),
        'id': index
    } for index, name in enumerate(orc.STANDARDS) if name not in db_classes]
    ins = _RC_TBL.insert()
    if batch_args:
        conn = ctx.session.connection()
        if conn.engine.dialect.name == 'mysql':
            # We need to do a literal insert of 0 to preserve the order
            # of the resource class ids from the previous style of
            # managing them. In some mysql settings a 0 is the same as
            # "give me a default key".
            conn.execute("SET SESSION SQL_MODE='NO_AUTO_VALUE_ON_ZERO'")
        try:
            ctx.session.execute(ins, batch_args)
            LOG.debug("Synced resource_classes from os_resource_classes: %s",
                      batch_args)
        except db_exc.DBDuplicateEntry:
            pass  # some other process sync'd, just ignore
예제 #2
0
def _resource_classes_sync(context):
    # Create a set of all resource class in the os_resource_classes library.

    query = """
            MATCH (rc:RESOURCE_CLASS)
            RETURN rc.name AS name
    """
    result = context.tx.run(query).data()
    db_std_classes = []
    if result:
        db_std_classes = [
            res["name"] for res in result if not orc.is_custom(res["name"])
        ]
    LOG.debug("Found existing resource classes in db: %s", db_std_classes)
    # Determine those resource clases which are in os_resource_classes but not
    # currently in the database, and insert them.
    missing_rc_names = [
        name for name in orc.STANDARDS if name not in db_std_classes
    ]
    for rc_name in missing_rc_names:
        query = """
                MERGE (rc:RESOURCE_CLASS {name: '%s', created_at: timestamp(),
                    updated_at: timestamp()})
        """ % rc_name
        try:
            result = context.tx.run(query).data()
        except db.ClientError:
            pass  # some other process sync'd, just ignore
        except db.TransientError as e:
            LOG.error("Transient errror creating Resource Class '%s': %s" %
                      (rc_name, e))
    def _validate_rc(provider):
        # Check that resource classes are custom
        additional_inventories = provider.get("inventories",
                                              {}).get("additional", [])
        all_inventory_conflicts = []
        for inventory in additional_inventories:
            inventory_conflicts = [
                rc for rc in inventory if not os_resource_classes.is_custom(rc)
            ]
            all_inventory_conflicts += inventory_conflicts

        if all_inventory_conflicts:
            # sort for more predictable message for testing
            message = _("Invalid resource class, only custom resource classes "
                        "are allowed: %s") % ', '.join(
                            sorted(all_inventory_conflicts))
            raise nova_exc.ProviderConfigException(error=message)
        return additional_inventories
예제 #4
0
def _get_usage(
    context: 'nova.context.RequestContext',
    project_id: str,
    resource_names: ty.List[str],
) -> ty.Dict[str, int]:
    """Called by oslo_limit's enforcer"""
    if not limit_utils.use_unified_limits():
        raise NotImplementedError("Unified limits support is disabled")

    count_servers = False
    resource_classes = []

    for resource in resource_names:
        if resource == "servers":
            count_servers = True
            continue

        if not resource.startswith("class:"):
            raise ValueError("Unknown resource type: %s" % resource)

        # Temporarily strip resource class prefix as placement does not use it.
        # Example: limit resource 'class:VCPU' will be returned as 'VCPU' from
        # placement.
        r_class = resource.lstrip("class:")
        if r_class in orc.STANDARDS or orc.is_custom(r_class):
            resource_classes.append(r_class)
        else:
            raise ValueError("Unknown resource class: %s" % r_class)

    if not count_servers and len(resource_classes) == 0:
        raise ValueError("no resources to check")

    resource_counts = {}
    if count_servers:
        # TODO(melwitt): Change this to count servers from placement once nova
        # is using placement consumer types and is able to differentiate
        # between "instance" allocations vs "migration" allocations.
        if not quota.is_qfd_populated(context):
            LOG.error('Must migrate all instance mappings before using '
                      'unified limits')
            raise ValueError("must first migrate instance mappings")
        mappings = objects.InstanceMappingList.get_counts(context, project_id)
        resource_counts['servers'] = mappings['project']['instances']

    try:
        usages = _get_placement_usages(context, project_id)
    except exception.UsagesRetrievalFailed as e:
        msg = ("Failed to retrieve usages from placement while enforcing "
               "%s quota limits." % ", ".join(resource_names))
        LOG.error(msg + " Error: " + str(e))
        raise exception.UsagesRetrievalFailed(msg)

    # Use legacy behavior VCPU = VCPU + PCPU if configured.
    if CONF.workarounds.unified_limits_count_pcpu_as_vcpu:
        # If PCPU is in resource_classes, that means it was specified in the
        # flavor explicitly. In that case, we expect it to have its own limit
        # registered and we should not fold it into VCPU.
        if orc.PCPU in usages and orc.PCPU not in resource_classes:
            usages[orc.VCPU] = (usages.get(orc.VCPU, 0) +
                                usages.get(orc.PCPU, 0))

    for resource_class in resource_classes:
        # Need to add back resource class prefix that was stripped earlier
        resource_name = 'class:' + resource_class
        # Placement doesn't know about classes with zero usage
        # so default to zero to tell oslo.limit usage is zero
        resource_counts[resource_name] = usages.get(resource_class, 0)

    return resource_counts