diff --git a/go.mod b/go.mod index b82e8cec..7f012365 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/prometheus/client_golang v1.20.5 github.com/prometheus/common v0.60.1 github.com/rs/cors v1.11.1 - github.com/sapcc/go-api-declarations v1.12.9 + github.com/sapcc/go-api-declarations v1.13.0 github.com/sapcc/go-bits v0.0.0-20241113133958-a93c0408d3e5 go.uber.org/automaxprocs v1.6.0 gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum index e21582e6..237be2e2 100644 --- a/go.sum +++ b/go.sum @@ -157,8 +157,8 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/sapcc/go-api-declarations v1.12.9 h1:4CWkt333oQxGnbka1TH4qApC0bxZe+WIBduygEcxiNw= -github.com/sapcc/go-api-declarations v1.12.9/go.mod h1:83R3hTANhuRXt/pXDby37IJetw8l7DG41s33Tp9NXxI= +github.com/sapcc/go-api-declarations v1.13.0 h1:4ufQUF7rwhLz7kPDVFCkw6CpQ8VeO2clJg4pjwTTpTU= +github.com/sapcc/go-api-declarations v1.13.0/go.mod h1:83R3hTANhuRXt/pXDby37IJetw8l7DG41s33Tp9NXxI= github.com/sapcc/go-bits v0.0.0-20241113133958-a93c0408d3e5 h1:YFcDGuLjl2vyRoFJhEEDHwY8df7Kz+oWspcldITq7pI= github.com/sapcc/go-bits v0.0.0-20241113133958-a93c0408d3e5/go.mod h1:P4F8aMHla5I0gRW+eOEYrhM89h3heEg0nypTZZcKoBQ= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= diff --git a/vendor/github.com/sapcc/go-api-declarations/liquid/doc.go b/vendor/github.com/sapcc/go-api-declarations/liquid/doc.go index 1dd6c863..014b8def 100644 --- a/vendor/github.com/sapcc/go-api-declarations/liquid/doc.go +++ b/vendor/github.com/sapcc/go-api-declarations/liquid/doc.go @@ -62,7 +62,7 @@ // In this case, quota and usage values are in terms of effective capacity, even though the capacity value is in terms of raw capacity. // // Capacity and usage may be AZ-aware, in which case one value will be reported per availability zone (AZ). -// Quota is not modelled as AZ-aware since there are no OpenStack services that support AZ-aware quota at this time. +// Quota is only optionally modelled as AZ-aware since there are no OpenStack services that support AZ-aware quota at this time. // // # Inside a rate: Usage // diff --git a/vendor/github.com/sapcc/go-api-declarations/liquid/info.go b/vendor/github.com/sapcc/go-api-declarations/liquid/info.go index 00bece66..ea414fe9 100644 --- a/vendor/github.com/sapcc/go-api-declarations/liquid/info.go +++ b/vendor/github.com/sapcc/go-api-declarations/liquid/info.go @@ -63,6 +63,13 @@ type ResourceInfo struct { // For example, the compute resource "cores" is countable, but the compute resource "ram" is measured, usually in MiB. Unit Unit `json:"unit,omitempty"` + // How the resource reports usage (and capacity, if any). + // + // For backwards compatibility, it is currently acceptable to not provide this field. + // In this case, the fallback behavior is for Limes to decide between FlatResourceTopology and AZAwareResourceTopology based on actual reports. + // In the future, Limes will eventually reject ResourceInfo that do not specify a known ResourceTopology. + Topology ResourceTopology `json:"topology"` + // Whether the liquid reports capacity for this resource on the cluster level. HasCapacity bool `json:"hasCapacity"` @@ -82,6 +89,46 @@ type ResourceInfo struct { Attributes json.RawMessage `json:"attributes,omitempty"` } +// ResourceTopology describes how capacity and usage reported by a certain resource is structured. +// Type type appears in type ResourceInfo. +type ResourceTopology string + +const ( + // FlatResourceTopology is a topology for resources that are not AZ-aware at all. + // In reports for this resource, PerAZ must contain exactly one key: AvailabilityZoneAny. + // Any other entry, as well as the absence of AvailabilityZoneAny, will be considered an error by Limes. + // + // If the resource sets HasQuota = true, only a flat number will be given, and PerAZ will be null. + FlatResourceTopology ResourceTopology = "flat" + + // AZAwareResourceTopology is a topology for resources that can measure capacity and usage by AZ. + // In reports for this resource, PerAZ shall contain an entry for each AZ mentioned in the AllAZs key of the request. + // PerAZ may also include an entry for AvailabilityZoneUnknown as needed. + // Any other entry (including AvailabilityZoneAny) will be considered an error by Limes. + // + // If the resource sets "HasQuota = true", only a flat number will be given, and PerAZ will be null. + // This behavior matches the AZ-unawareness of quota in most OpenStack services. + AZAwareResourceTopology ResourceTopology = "az-aware" + + // AZSeparatedResourceTopology is like AZAwareResourceTopology, but quota is also AZ-aware. + // For resources with HasQuota = false, this behaves the same as AZAwareResourceTopology. + // + // If the resource sets "HasQuota = true", quota requests will include the PerAZ breakdown. + // PerAZ will only contain quotas for actual AZs, not for AvailabilityZoneAny or AvailabilityZoneUnknown. + AZSeparatedResourceTopology ResourceTopology = "az-separated" +) + +// IsValid returns whether the given value is a part of the enum. +// This can be used to check unmarshalled values. +func (t ResourceTopology) IsValid() bool { + switch t { + case FlatResourceTopology, AZAwareResourceTopology, AZSeparatedResourceTopology: + return true + default: + return false + } +} + // RateInfo describes a rate that a liquid's service provides. // This type appears in type ServiceInfo. type RateInfo struct { diff --git a/vendor/github.com/sapcc/go-api-declarations/liquid/quota.go b/vendor/github.com/sapcc/go-api-declarations/liquid/quota.go index 0f7e1fd8..0665d92f 100644 --- a/vendor/github.com/sapcc/go-api-declarations/liquid/quota.go +++ b/vendor/github.com/sapcc/go-api-declarations/liquid/quota.go @@ -28,12 +28,23 @@ type ServiceQuotaRequest struct { ProjectMetadata *ProjectMetadata `json:"projectMetadata,omitempty"` } -// ResourceQuotaRequest contains the new quota value for a single resource. +// ResourceQuotaRequest contains new quotas for a single resource. // It appears in type ServiceQuotaRequest. type ResourceQuotaRequest struct { + // For FlatResourceTopology and AZAwareResourceTopology, this is the only field that is filled, and PerAZ will be nil. + // For AZSeparatedResourceTopology, this contains the sum of the quotas across all AZs (for compatibility purposes). + Quota uint64 `json:"quota"` + + // PerAZ will only be filled for AZSeparatedResourceTopology. + PerAZ map[AvailabilityZone]AZResourceQuotaRequest `json:"perAZ,omitempty"` +} + +// AZResourceQuotaRequest contains the new quota value for a single resource and AZ. +// It appears in type ResourceQuotaRequest. +type AZResourceQuotaRequest struct { Quota uint64 `json:"quota"` // This struct looks superfluous (why not just have a bare uint64?), but in - // the unlikely event that AZ-aware quota may be added in the future, having - // this struct allows for that to be a backwards-compatible change. + // the event that more data needs to be added in the future, having this + // struct allows for that to be a backwards-compatible change. } diff --git a/vendor/github.com/sapcc/go-api-declarations/liquid/report_capacity.go b/vendor/github.com/sapcc/go-api-declarations/liquid/report_capacity.go index eafef113..ca093d6b 100644 --- a/vendor/github.com/sapcc/go-api-declarations/liquid/report_capacity.go +++ b/vendor/github.com/sapcc/go-api-declarations/liquid/report_capacity.go @@ -41,7 +41,7 @@ type ResourceDemand struct { OvercommitFactor OvercommitFactor `json:"overcommitFactor,omitempty"` // The actual demand values are AZ-aware. - // For non-AZ-aware resources, the only entry will be for AvailabilityZoneAny. + // The keys that can be expected in this map depend on the chosen ResourceTopology. PerAZ map[AvailabilityZone]ResourceDemandInAZ `json:"perAZ"` } @@ -77,17 +77,28 @@ type ServiceCapacityReport struct { // ResourceCapacityReport contains capacity data for a resource. // It appears in type ServiceCapacityReport. type ResourceCapacityReport struct { - // For non-AZ-aware resources, the only entry shall be for AvailabilityZoneAny. - // Use func InAnyAZ to quickly construct a suitable structure. - // - // For AZ-aware resources, there shall be an entry for each AZ mentioned in ServiceCapacityRequest.AllAZs. - // Reports for AZ-aware resources may also include an entry for AvailabilityZoneUnknown as needed. + // The keys that are allowed in this map depend on the chosen ResourceTopology. + // See documentation on ResourceTopology enum variants for details. PerAZ map[AvailabilityZone]*AZResourceCapacityReport `json:"perAZ"` } // AZResourceCapacityReport contains capacity data for a resource in a single AZ. // It appears in type ResourceCapacityReport. type AZResourceCapacityReport struct { + // How much capacity is available to Limes in this resource and AZ. + // + // Caution: In some cases, underlying capacity can be used by multiple + // resources. For example, the storage capacity in Manila pools can be used + // by both the `share_capacity` and `snapshot_capacity` resources. In this case, + // it is *incorrect* to just report the entire storage capacity in both resources. + // Limes assumes that whatever number you provide here is free to be + // allocated exclusively for the respective resource. If physical capacity + // can be used by multiple resources, you need to split the capacity and + // report only a chunk of the real capacity in each resource. + // + // If you need to split physical capacity between multiple resources like + // this, the recommended way is to set "NeedsResourceDemand = true" and + // then split capacity based on the demand reported by Limes. Capacity uint64 `json:"capacity"` // How much of the Capacity is used, or null if no usage data is available. diff --git a/vendor/github.com/sapcc/go-api-declarations/liquid/report_usage.go b/vendor/github.com/sapcc/go-api-declarations/liquid/report_usage.go index d542b944..3e8bc89b 100644 --- a/vendor/github.com/sapcc/go-api-declarations/liquid/report_usage.go +++ b/vendor/github.com/sapcc/go-api-declarations/liquid/report_usage.go @@ -73,20 +73,18 @@ type ServiceUsageReport struct { type ResourceUsageReport struct { // If true, this project is forbidden from accessing this resource. // This has two consequences: - // - If the resource has quota, Limes will never try to assign quota for this resource to this project. + // - If the resource has quota, Limes will never try to assign quota for this resource to this project except to cover existing usage. // - If the project has no usage in this resource, Limes will hide this resource from project reports. Forbidden bool `json:"forbidden"` - // This shall be null if and only if the resource is declared with "HasQuota = false". + // This shall be null if and only if the resource is declared with "HasQuota = false" or with AZSeparatedResourceTopology. // A negative value, usually -1, indicates "infinite quota" (i.e., the absence of a quota). Quota *int64 `json:"quota,omitempty"` - // For non-AZ-aware resources, the only entry shall be for AvailabilityZoneAny. - // Use func InAnyAZ to quickly construct a suitable structure. + // The keys that are allowed in this map depend on the chosen ResourceTopology. + // See documentation on ResourceTopology enum variants for details. // - // For AZ-aware resources, there shall be an entry for each AZ mentioned in ServiceUsageRequest.AllAZs. - // Reports for AZ-aware resources may also include an entry for AvailabilityZoneUnknown as needed. - // When starting from a non-AZ-aware usage number that is later broken down with AZ-aware data, use func PrepareForBreakdownInto. + // Tip: When filling this by starting from a non-AZ-aware usage number that is later broken down with AZ-aware data, use func PrepareForBreakdownInto. PerAZ map[AvailabilityZone]*AZResourceUsageReport `json:"perAZ"` } @@ -104,6 +102,10 @@ type AZResourceUsageReport struct { // It is not allowed to report 5 GiB as Usage in this situation, since the 50 GiB value is used when judging whether the Quota fits. PhysicalUsage *uint64 `json:"physicalUsage,omitempty"` + // This shall be non-null if and only if the resource is declared with AZSeparatedResourceTopology. + // A negative value, usually -1, indicates "infinite quota" (i.e., the absence of a quota). + Quota *int64 `json:"quota,omitempty"` + // Only filled if the resource is able to report subresources for this usage in a useful way. Subresources []Subresource `json:"subresources,omitempty"` } @@ -148,11 +150,8 @@ func (r *ResourceUsageReport) AddLocalizedUsage(az AvailabilityZone, usage uint6 // RateUsageReport contains usage data for a rate in a single project. // It appears in type ServiceUsageReport. type RateUsageReport struct { - // For non-AZ-aware rates, the only entry shall be for AvailabilityZoneAny. - // Use func InAnyAZ to quickly construct a suitable structure. - // - // For AZ-aware rates, there shall be an entry for each AZ mentioned in ServiceUsageRequest.AllAZs. - // Reports for AZ-aware rates may also include an entry for AvailabilityZoneUnknown as needed. + // The keys that are allowed in this map depend on the chosen ResourceTopology. + // See documentation on ResourceTopology enum variants for details. PerAZ map[AvailabilityZone]*AZRateUsageReport `json:"perAZ"` } diff --git a/vendor/modules.txt b/vendor/modules.txt index 614b4fea..8bca39a0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -141,7 +141,7 @@ github.com/rabbitmq/amqp091-go ## explicit; go 1.13 github.com/rs/cors github.com/rs/cors/internal -# github.com/sapcc/go-api-declarations v1.12.9 +# github.com/sapcc/go-api-declarations v1.13.0 ## explicit; go 1.21 github.com/sapcc/go-api-declarations/bininfo github.com/sapcc/go-api-declarations/cadf