Compare commits
62 Commits
cluster-au
...
master
Author | SHA1 | Date |
---|---|---|
|
c7a51426e2 | |
|
c1352dad7c | |
|
36804f199c | |
|
172a22c195 | |
|
4bd2e67a1d | |
|
72bf359268 | |
|
26d6b38699 | |
|
ff6e93bfc3 | |
|
1938d3971a | |
|
3d748040d9 | |
|
2eb5adda2c | |
|
0d36de3aa2 | |
|
1d5f0471bc | |
|
1fbc7a9d48 | |
|
e8941e59a0 | |
|
9a256e5c83 | |
|
f9b93ec395 | |
|
0d14eca879 | |
|
aae2a010f1 | |
|
c187e7f147 | |
|
9bc422016f | |
|
8482fd7ac1 | |
|
0fb7d53506 | |
|
637d9ad908 | |
|
0ed3da32c9 | |
|
df9718c409 | |
|
6f0f000a20 | |
|
2945e9562d | |
|
1d421cbe93 | |
|
338987711f | |
|
bd2ff7b070 | |
|
8d76026c21 | |
|
115c8168be | |
|
12e6e2e182 | |
|
8f9a24aafe | |
|
2abd557186 | |
|
cc01c8756f | |
|
88a3b42883 | |
|
055aa33780 | |
|
40b429081f | |
|
4086830636 | |
|
8e47b51d39 | |
|
f3c58dae9c | |
|
14ce6111ba | |
|
3f9526837e | |
|
b1780e6401 | |
|
65c4d6f702 | |
|
815da21233 | |
|
82178880ba | |
|
008a3b916e | |
|
77cb4c8bf8 | |
|
9424deef46 | |
|
2ae7495c3f | |
|
7912e2d0f6 | |
|
2814dcafaf | |
|
20a59a9f41 | |
|
c942ff37ad | |
|
96b13193e3 | |
|
e51dcfb60b | |
|
6eebb82f0d | |
|
9cc45e2a24 | |
|
8a954bc021 |
|
@ -7,6 +7,7 @@ updates:
|
||||||
open-pull-requests-limit: 0 # setting this to 0 means only allowing security updates, see https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#open-pull-requests-limit
|
open-pull-requests-limit: 0 # setting this to 0 means only allowing security updates, see https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#open-pull-requests-limit
|
||||||
labels:
|
labels:
|
||||||
- "area/vertical-pod-autoscaler"
|
- "area/vertical-pod-autoscaler"
|
||||||
|
- "release-note-none"
|
||||||
- package-ecosystem: docker
|
- package-ecosystem: docker
|
||||||
directory: "/vertical-pod-autoscaler/pkg/recommender"
|
directory: "/vertical-pod-autoscaler/pkg/recommender"
|
||||||
schedule:
|
schedule:
|
||||||
|
@ -17,6 +18,7 @@ updates:
|
||||||
open-pull-requests-limit: 3
|
open-pull-requests-limit: 3
|
||||||
labels:
|
labels:
|
||||||
- "area/vertical-pod-autoscaler"
|
- "area/vertical-pod-autoscaler"
|
||||||
|
- "release-note-none"
|
||||||
- package-ecosystem: docker
|
- package-ecosystem: docker
|
||||||
directory: "/vertical-pod-autoscaler/pkg/updater"
|
directory: "/vertical-pod-autoscaler/pkg/updater"
|
||||||
schedule:
|
schedule:
|
||||||
|
@ -27,6 +29,7 @@ updates:
|
||||||
open-pull-requests-limit: 3
|
open-pull-requests-limit: 3
|
||||||
labels:
|
labels:
|
||||||
- "area/vertical-pod-autoscaler"
|
- "area/vertical-pod-autoscaler"
|
||||||
|
- "release-note-none"
|
||||||
- package-ecosystem: docker
|
- package-ecosystem: docker
|
||||||
directory: "/vertical-pod-autoscaler/pkg/admission-controller"
|
directory: "/vertical-pod-autoscaler/pkg/admission-controller"
|
||||||
schedule:
|
schedule:
|
||||||
|
@ -37,9 +40,20 @@ updates:
|
||||||
open-pull-requests-limit: 3
|
open-pull-requests-limit: 3
|
||||||
labels:
|
labels:
|
||||||
- "area/vertical-pod-autoscaler"
|
- "area/vertical-pod-autoscaler"
|
||||||
|
- "release-note-none"
|
||||||
- package-ecosystem: gomod
|
- package-ecosystem: gomod
|
||||||
directory: "/addon-resizer"
|
directory: "/addon-resizer"
|
||||||
schedule:
|
schedule:
|
||||||
interval: daily
|
interval: daily
|
||||||
target-branch: "addon-resizer-release-1.8"
|
target-branch: "addon-resizer-release-1.8"
|
||||||
open-pull-requests-limit: 3
|
open-pull-requests-limit: 3
|
||||||
|
labels:
|
||||||
|
- "release-note-none"
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
open-pull-requests-limit: 3
|
||||||
|
labels:
|
||||||
|
- "area/dependency"
|
||||||
|
- "release-note-none"
|
||||||
|
|
|
@ -13,7 +13,7 @@ jobs:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.2.2
|
uses: actions/checkout@v4.2.2
|
||||||
- id: filter
|
- id: filter
|
||||||
uses: dorny/paths-filter@v2.2.0
|
uses: dorny/paths-filter@v2.11.1
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
charts:
|
charts:
|
||||||
|
@ -45,7 +45,7 @@ jobs:
|
||||||
fi
|
fi
|
||||||
- if: steps.list-changed.outputs.changed == 'true'
|
- if: steps.list-changed.outputs.changed == 'true'
|
||||||
name: Create kind cluster
|
name: Create kind cluster
|
||||||
uses: helm/kind-action@v1.10.0
|
uses: helm/kind-action@v1.12.0
|
||||||
- if: steps.list-changed.outputs.changed == 'true'
|
- if: steps.list-changed.outputs.changed == 'true'
|
||||||
name: Run chart-testing (install)
|
name: Run chart-testing (install)
|
||||||
run: ct install
|
run: ct install
|
||||||
|
|
|
@ -23,7 +23,7 @@ We'd love to accept your patches! Before we can take them, we have to jump a cou
|
||||||
|
|
||||||
All changes must be code reviewed. Coding conventions and standards are explained in the official
|
All changes must be code reviewed. Coding conventions and standards are explained in the official
|
||||||
[developer docs](https://github.com/kubernetes/community/tree/master/contributors/devel). Expect
|
[developer docs](https://github.com/kubernetes/community/tree/master/contributors/devel). Expect
|
||||||
reviewers to request that you avoid common [go style mistakes](https://github.com/golang/go/wiki/CodeReviewComments)
|
reviewers to request that you avoid common [go style mistakes](https://go.dev/wiki/CodeReviewComments)
|
||||||
in your PRs.
|
in your PRs.
|
||||||
|
|
||||||
### Merge Approval
|
### Merge Approval
|
||||||
|
|
|
@ -11,4 +11,4 @@ name: cluster-autoscaler
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler
|
- https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler
|
||||||
type: application
|
type: application
|
||||||
version: 9.47.0
|
version: 9.48.0
|
||||||
|
|
|
@ -498,6 +498,7 @@ vpa:
|
||||||
| prometheusRule.interval | string | `nil` | How often rules in the group are evaluated (falls back to `global.evaluation_interval` if not set). |
|
| prometheusRule.interval | string | `nil` | How often rules in the group are evaluated (falls back to `global.evaluation_interval` if not set). |
|
||||||
| prometheusRule.namespace | string | `"monitoring"` | Namespace which Prometheus is running in. |
|
| prometheusRule.namespace | string | `"monitoring"` | Namespace which Prometheus is running in. |
|
||||||
| prometheusRule.rules | list | `[]` | Rules spec template (see https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#rule). |
|
| prometheusRule.rules | list | `[]` | Rules spec template (see https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#rule). |
|
||||||
|
| rbac.additionalRules | list | `[]` | Additional rules for role/clusterrole |
|
||||||
| rbac.clusterScoped | bool | `true` | if set to false will only provision RBAC to alter resources in the current namespace. Most useful for Cluster-API |
|
| rbac.clusterScoped | bool | `true` | if set to false will only provision RBAC to alter resources in the current namespace. Most useful for Cluster-API |
|
||||||
| rbac.create | bool | `true` | If `true`, create and use RBAC resources. |
|
| rbac.create | bool | `true` | If `true`, create and use RBAC resources. |
|
||||||
| rbac.pspEnabled | bool | `false` | If `true`, creates and uses RBAC resources required in the cluster with [Pod Security Policies](https://kubernetes.io/docs/concepts/policy/pod-security-policy/) enabled. Must be used with `rbac.create` set to `true`. |
|
| rbac.pspEnabled | bool | `false` | If `true`, creates and uses RBAC resources required in the cluster with [Pod Security Policies](https://kubernetes.io/docs/concepts/policy/pod-security-policy/) enabled. Must be used with `rbac.create` set to `true`. |
|
||||||
|
|
|
@ -173,4 +173,7 @@ rules:
|
||||||
- patch
|
- patch
|
||||||
- update
|
- update
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.rbac.additionalRules }}
|
||||||
|
{{ toYaml .Values.rbac.additionalRules | indent 2 }}
|
||||||
|
{{- end }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
|
@ -83,5 +83,8 @@ rules:
|
||||||
verbs:
|
verbs:
|
||||||
- get
|
- get
|
||||||
- update
|
- update
|
||||||
|
{{- if .Values.rbac.additionalRules }}
|
||||||
|
{{ toYaml .Values.rbac.additionalRules | indent 2}}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
|
@ -366,6 +366,17 @@ rbac:
|
||||||
name: ""
|
name: ""
|
||||||
# rbac.serviceAccount.automountServiceAccountToken -- Automount API credentials for a Service Account.
|
# rbac.serviceAccount.automountServiceAccountToken -- Automount API credentials for a Service Account.
|
||||||
automountServiceAccountToken: true
|
automountServiceAccountToken: true
|
||||||
|
# rbac.additionalRules -- Additional rules for role/clusterrole
|
||||||
|
additionalRules: []
|
||||||
|
# - apiGroups:
|
||||||
|
# - infrastructure.cluster.x-k8s.io
|
||||||
|
# resources:
|
||||||
|
# - kubemarkmachinetemplates
|
||||||
|
# verbs:
|
||||||
|
# - get
|
||||||
|
# - list
|
||||||
|
# - watch
|
||||||
|
|
||||||
|
|
||||||
# replicaCount -- Desired number of pods
|
# replicaCount -- Desired number of pods
|
||||||
replicaCount: 1
|
replicaCount: 1
|
||||||
|
|
|
@ -107,7 +107,20 @@ build-in-docker-arch-%: clean-arch-% docker-builder
|
||||||
docker run ${RM_FLAG} -v `pwd`:/gopath/src/k8s.io/autoscaler/cluster-autoscaler/:Z autoscaling-builder:latest \
|
docker run ${RM_FLAG} -v `pwd`:/gopath/src/k8s.io/autoscaler/cluster-autoscaler/:Z autoscaling-builder:latest \
|
||||||
bash -c 'cd /gopath/src/k8s.io/autoscaler/cluster-autoscaler && BUILD_TAGS=${BUILD_TAGS} LDFLAGS="${LDFLAGS}" make build-arch-$*'
|
bash -c 'cd /gopath/src/k8s.io/autoscaler/cluster-autoscaler && BUILD_TAGS=${BUILD_TAGS} LDFLAGS="${LDFLAGS}" make build-arch-$*'
|
||||||
|
|
||||||
release: $(addprefix build-in-docker-arch-,$(ALL_ARCH)) execute-release
|
release-extract-version = $(shell cat version/version.go | grep "Version =" | cut -d '"' -f 2)
|
||||||
|
|
||||||
|
release-validate:
|
||||||
|
@if [ -z $(shell git tag --points-at HEAD | grep -e ^cluster-autoscaler-1.[1-9][0-9]*.[0-9][0-9]*$) ]; then \
|
||||||
|
echo "Can't release from this commit, there is no compatible git tag"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
@if [ -z $(shell git tag --points-at HEAD | grep -e $(call release-extract-version)) ]; then \
|
||||||
|
echo "Can't release from this commit, git tag does not match version/version.go"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
release: TAG=v$(call release-extract-version)
|
||||||
|
release: release-validate $(addprefix build-in-docker-arch-,$(ALL_ARCH)) execute-release
|
||||||
@echo "Full in-docker release ${TAG}${FOR_PROVIDER} completed"
|
@echo "Full in-docker release ${TAG}${FOR_PROVIDER} completed"
|
||||||
|
|
||||||
container: container-arch-$(GOARCH)
|
container: container-arch-$(GOARCH)
|
||||||
|
|
|
@ -10,5 +10,6 @@ reviewers:
|
||||||
- feiskyer
|
- feiskyer
|
||||||
- vadasambar
|
- vadasambar
|
||||||
- x13n
|
- x13n
|
||||||
|
- elmiko
|
||||||
labels:
|
labels:
|
||||||
- area/cluster-autoscaler
|
- area/cluster-autoscaler
|
||||||
|
|
|
@ -103,6 +103,9 @@ type Config struct {
|
||||||
|
|
||||||
// EnableFastDeleteOnFailedProvisioning defines whether to delete the experimental faster VMSS instance deletion on failed provisioning
|
// EnableFastDeleteOnFailedProvisioning defines whether to delete the experimental faster VMSS instance deletion on failed provisioning
|
||||||
EnableFastDeleteOnFailedProvisioning bool `json:"enableFastDeleteOnFailedProvisioning,omitempty" yaml:"enableFastDeleteOnFailedProvisioning,omitempty"`
|
EnableFastDeleteOnFailedProvisioning bool `json:"enableFastDeleteOnFailedProvisioning,omitempty" yaml:"enableFastDeleteOnFailedProvisioning,omitempty"`
|
||||||
|
|
||||||
|
// EnableLabelPredictionsOnTemplate defines whether to enable label predictions on the template when scaling from zero
|
||||||
|
EnableLabelPredictionsOnTemplate bool `json:"enableLabelPredictionsOnTemplate,omitempty" yaml:"enableLabelPredictionsOnTemplate,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are only here for backward compabitility. Their equivalent exists in providerazure.Config with a different name.
|
// These are only here for backward compabitility. Their equivalent exists in providerazure.Config with a different name.
|
||||||
|
@ -133,6 +136,7 @@ func BuildAzureConfig(configReader io.Reader) (*Config, error) {
|
||||||
cfg.VMType = providerazureconsts.VMTypeVMSS
|
cfg.VMType = providerazureconsts.VMTypeVMSS
|
||||||
cfg.MaxDeploymentsCount = int64(defaultMaxDeploymentsCount)
|
cfg.MaxDeploymentsCount = int64(defaultMaxDeploymentsCount)
|
||||||
cfg.StrictCacheUpdates = false
|
cfg.StrictCacheUpdates = false
|
||||||
|
cfg.EnableLabelPredictionsOnTemplate = true
|
||||||
|
|
||||||
// Config file overrides defaults
|
// Config file overrides defaults
|
||||||
if configReader != nil {
|
if configReader != nil {
|
||||||
|
@ -308,6 +312,9 @@ func BuildAzureConfig(configReader io.Reader) (*Config, error) {
|
||||||
if _, err = assignBoolFromEnvIfExists(&cfg.EnableFastDeleteOnFailedProvisioning, "AZURE_ENABLE_FAST_DELETE_ON_FAILED_PROVISIONING"); err != nil {
|
if _, err = assignBoolFromEnvIfExists(&cfg.EnableFastDeleteOnFailedProvisioning, "AZURE_ENABLE_FAST_DELETE_ON_FAILED_PROVISIONING"); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if _, err = assignBoolFromEnvIfExists(&cfg.EnableLabelPredictionsOnTemplate, "AZURE_ENABLE_LABEL_PREDICTIONS_ON_TEMPLATE"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Nonstatic defaults
|
// Nonstatic defaults
|
||||||
cfg.VMType = strings.ToLower(cfg.VMType)
|
cfg.VMType = strings.ToLower(cfg.VMType)
|
||||||
|
|
|
@ -89,6 +89,8 @@ type ScaleSet struct {
|
||||||
dedicatedHost bool
|
dedicatedHost bool
|
||||||
|
|
||||||
enableFastDeleteOnFailedProvisioning bool
|
enableFastDeleteOnFailedProvisioning bool
|
||||||
|
|
||||||
|
enableLabelPredictionsOnTemplate bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewScaleSet creates a new NewScaleSet.
|
// NewScaleSet creates a new NewScaleSet.
|
||||||
|
@ -108,10 +110,11 @@ func NewScaleSet(spec *dynamic.NodeGroupSpec, az *AzureManager, curSize int64, d
|
||||||
instancesRefreshJitter: az.config.VmssVmsCacheJitter,
|
instancesRefreshJitter: az.config.VmssVmsCacheJitter,
|
||||||
},
|
},
|
||||||
|
|
||||||
enableForceDelete: az.config.EnableForceDelete,
|
enableForceDelete: az.config.EnableForceDelete,
|
||||||
enableDynamicInstanceList: az.config.EnableDynamicInstanceList,
|
enableDynamicInstanceList: az.config.EnableDynamicInstanceList,
|
||||||
enableDetailedCSEMessage: az.config.EnableDetailedCSEMessage,
|
enableDetailedCSEMessage: az.config.EnableDetailedCSEMessage,
|
||||||
dedicatedHost: dedicatedHost,
|
enableLabelPredictionsOnTemplate: az.config.EnableLabelPredictionsOnTemplate,
|
||||||
|
dedicatedHost: dedicatedHost,
|
||||||
}
|
}
|
||||||
|
|
||||||
if az.config.VmssVirtualMachinesCacheTTLInSeconds != 0 {
|
if az.config.VmssVirtualMachinesCacheTTLInSeconds != 0 {
|
||||||
|
@ -662,7 +665,7 @@ func (scaleSet *ScaleSet) TemplateNodeInfo() (*framework.NodeInfo, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
node, err := buildNodeFromTemplate(scaleSet.Name, template, scaleSet.manager, scaleSet.enableDynamicInstanceList)
|
node, err := buildNodeFromTemplate(scaleSet.Name, template, scaleSet.manager, scaleSet.enableDynamicInstanceList, scaleSet.enableLabelPredictionsOnTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,7 +211,7 @@ func buildNodeTemplateFromVMPool(vmsPool armcontainerservice.AgentPool, location
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildNodeFromTemplate(nodeGroupName string, template NodeTemplate, manager *AzureManager, enableDynamicInstanceList bool) (*apiv1.Node, error) {
|
func buildNodeFromTemplate(nodeGroupName string, template NodeTemplate, manager *AzureManager, enableDynamicInstanceList bool, enableLabelPrediction bool) (*apiv1.Node, error) {
|
||||||
node := apiv1.Node{}
|
node := apiv1.Node{}
|
||||||
nodeName := fmt.Sprintf("%s-asg-%d", nodeGroupName, rand.Int63())
|
nodeName := fmt.Sprintf("%s-asg-%d", nodeGroupName, rand.Int63())
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ func buildNodeFromTemplate(nodeGroupName string, template NodeTemplate, manager
|
||||||
node.Status.Allocatable = node.Status.Capacity
|
node.Status.Allocatable = node.Status.Capacity
|
||||||
|
|
||||||
if template.VMSSNodeTemplate != nil {
|
if template.VMSSNodeTemplate != nil {
|
||||||
node = processVMSSTemplate(template, nodeName, node)
|
node = processVMSSTemplate(template, nodeName, node, enableLabelPrediction)
|
||||||
} else if template.VMPoolNodeTemplate != nil {
|
} else if template.VMPoolNodeTemplate != nil {
|
||||||
node = processVMPoolTemplate(template, nodeName, node)
|
node = processVMPoolTemplate(template, nodeName, node)
|
||||||
} else {
|
} else {
|
||||||
|
@ -298,7 +298,7 @@ func processVMPoolTemplate(template NodeTemplate, nodeName string, node apiv1.No
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
func processVMSSTemplate(template NodeTemplate, nodeName string, node apiv1.Node) apiv1.Node {
|
func processVMSSTemplate(template NodeTemplate, nodeName string, node apiv1.Node, enableLabelPrediction bool) apiv1.Node {
|
||||||
// NodeLabels
|
// NodeLabels
|
||||||
if template.VMSSNodeTemplate.Tags != nil {
|
if template.VMSSNodeTemplate.Tags != nil {
|
||||||
for k, v := range template.VMSSNodeTemplate.Tags {
|
for k, v := range template.VMSSNodeTemplate.Tags {
|
||||||
|
@ -324,45 +324,50 @@ func processVMSSTemplate(template NodeTemplate, nodeName string, node apiv1.Node
|
||||||
labels = extractLabelsFromTags(template.VMSSNodeTemplate.Tags)
|
labels = extractLabelsFromTags(template.VMSSNodeTemplate.Tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the agentpool label, its value should come from the VMSS poolName tag
|
// This is the best-effort to match AKS system labels,
|
||||||
// NOTE: The plan is for agentpool label to be deprecated in favor of the aks-prefixed one
|
// this prediction needs to be constantly worked on and maintained to keep up with the changes in AKS
|
||||||
// We will have to live with both labels for a while
|
if enableLabelPrediction {
|
||||||
if node.Labels[legacyPoolNameTag] != "" {
|
// Add the agentpool label, its value should come from the VMSS poolName tag
|
||||||
labels[legacyAgentPoolNodeLabelKey] = node.Labels[legacyPoolNameTag]
|
// NOTE: The plan is for agentpool label to be deprecated in favor of the aks-prefixed one
|
||||||
labels[agentPoolNodeLabelKey] = node.Labels[legacyPoolNameTag]
|
// We will have to live with both labels for a while
|
||||||
}
|
if node.Labels[legacyPoolNameTag] != "" {
|
||||||
if node.Labels[poolNameTag] != "" {
|
labels[legacyAgentPoolNodeLabelKey] = node.Labels[legacyPoolNameTag]
|
||||||
labels[legacyAgentPoolNodeLabelKey] = node.Labels[poolNameTag]
|
labels[agentPoolNodeLabelKey] = node.Labels[legacyPoolNameTag]
|
||||||
labels[agentPoolNodeLabelKey] = node.Labels[poolNameTag]
|
}
|
||||||
}
|
if node.Labels[poolNameTag] != "" {
|
||||||
|
labels[legacyAgentPoolNodeLabelKey] = node.Labels[poolNameTag]
|
||||||
|
labels[agentPoolNodeLabelKey] = node.Labels[poolNameTag]
|
||||||
|
}
|
||||||
|
|
||||||
// Add the storage profile and storage tier labels for vmss node
|
// Add the storage profile and storage tier labels for vmss node
|
||||||
if template.VMSSNodeTemplate.OSDisk != nil {
|
if template.VMSSNodeTemplate.OSDisk != nil {
|
||||||
// ephemeral
|
// ephemeral
|
||||||
if template.VMSSNodeTemplate.OSDisk.DiffDiskSettings != nil && template.VMSSNodeTemplate.OSDisk.DiffDiskSettings.Option == compute.Local {
|
if template.VMSSNodeTemplate.OSDisk.DiffDiskSettings != nil && template.VMSSNodeTemplate.OSDisk.DiffDiskSettings.Option == compute.Local {
|
||||||
labels[legacyStorageProfileNodeLabelKey] = "ephemeral"
|
labels[legacyStorageProfileNodeLabelKey] = "ephemeral"
|
||||||
labels[storageProfileNodeLabelKey] = "ephemeral"
|
labels[storageProfileNodeLabelKey] = "ephemeral"
|
||||||
} else {
|
} else {
|
||||||
labels[legacyStorageProfileNodeLabelKey] = "managed"
|
labels[legacyStorageProfileNodeLabelKey] = "managed"
|
||||||
labels[storageProfileNodeLabelKey] = "managed"
|
labels[storageProfileNodeLabelKey] = "managed"
|
||||||
|
}
|
||||||
|
if template.VMSSNodeTemplate.OSDisk.ManagedDisk != nil {
|
||||||
|
labels[legacyStorageTierNodeLabelKey] = string(template.VMSSNodeTemplate.OSDisk.ManagedDisk.StorageAccountType)
|
||||||
|
labels[storageTierNodeLabelKey] = string(template.VMSSNodeTemplate.OSDisk.ManagedDisk.StorageAccountType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if template.VMSSNodeTemplate.OSDisk.ManagedDisk != nil {
|
|
||||||
labels[legacyStorageTierNodeLabelKey] = string(template.VMSSNodeTemplate.OSDisk.ManagedDisk.StorageAccountType)
|
// If we are on GPU-enabled SKUs, append the accelerator
|
||||||
labels[storageTierNodeLabelKey] = string(template.VMSSNodeTemplate.OSDisk.ManagedDisk.StorageAccountType)
|
// label so that CA makes better decision when scaling from zero for GPU pools
|
||||||
}
|
if isNvidiaEnabledSKU(template.SkuName) {
|
||||||
// Add ephemeral-storage value
|
labels[GPULabel] = "nvidia"
|
||||||
if template.VMSSNodeTemplate.OSDisk.DiskSizeGB != nil {
|
labels[legacyGPULabel] = "nvidia"
|
||||||
node.Status.Capacity[apiv1.ResourceEphemeralStorage] = *resource.NewQuantity(int64(int(*template.VMSSNodeTemplate.OSDisk.DiskSizeGB)*1024*1024*1024), resource.DecimalSI)
|
|
||||||
klog.V(4).Infof("OS Disk Size from template is: %d", *template.VMSSNodeTemplate.OSDisk.DiskSizeGB)
|
|
||||||
klog.V(4).Infof("Setting ephemeral storage to: %v", node.Status.Capacity[apiv1.ResourceEphemeralStorage])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are on GPU-enabled SKUs, append the accelerator
|
// Add ephemeral-storage value
|
||||||
// label so that CA makes better decision when scaling from zero for GPU pools
|
if template.VMSSNodeTemplate.OSDisk != nil && template.VMSSNodeTemplate.OSDisk.DiskSizeGB != nil {
|
||||||
if isNvidiaEnabledSKU(template.SkuName) {
|
node.Status.Capacity[apiv1.ResourceEphemeralStorage] = *resource.NewQuantity(int64(int(*template.VMSSNodeTemplate.OSDisk.DiskSizeGB)*1024*1024*1024), resource.DecimalSI)
|
||||||
labels[GPULabel] = "nvidia"
|
klog.V(4).Infof("OS Disk Size from template is: %d", *template.VMSSNodeTemplate.OSDisk.DiskSizeGB)
|
||||||
labels[legacyGPULabel] = "nvidia"
|
klog.V(4).Infof("Setting ephemeral storage to: %v", node.Status.Capacity[apiv1.ResourceEphemeralStorage])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract allocatables from tags
|
// Extract allocatables from tags
|
||||||
|
|
|
@ -291,3 +291,91 @@ func makeTaintSet(taints []apiv1.Taint) map[apiv1.Taint]bool {
|
||||||
}
|
}
|
||||||
return set
|
return set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildNodeFromTemplateWithLabelPrediction(t *testing.T) {
|
||||||
|
poolName := "testpool"
|
||||||
|
testSkuName := "Standard_DS2_v2"
|
||||||
|
testNodeName := "test-node"
|
||||||
|
|
||||||
|
vmss := compute.VirtualMachineScaleSet{
|
||||||
|
Response: autorest.Response{},
|
||||||
|
Sku: &compute.Sku{Name: &testSkuName},
|
||||||
|
Plan: nil,
|
||||||
|
VirtualMachineScaleSetProperties: &compute.VirtualMachineScaleSetProperties{
|
||||||
|
VirtualMachineProfile: &compute.VirtualMachineScaleSetVMProfile{
|
||||||
|
StorageProfile: &compute.VirtualMachineScaleSetStorageProfile{
|
||||||
|
OsDisk: &compute.VirtualMachineScaleSetOSDisk{
|
||||||
|
DiffDiskSettings: nil, // This makes it managed
|
||||||
|
ManagedDisk: &compute.VirtualMachineScaleSetManagedDiskParameters{
|
||||||
|
StorageAccountType: compute.StorageAccountTypesPremiumLRS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tags: map[string]*string{
|
||||||
|
"poolName": &poolName,
|
||||||
|
},
|
||||||
|
Zones: &[]string{"1", "2"},
|
||||||
|
Location: to.StringPtr("westus"),
|
||||||
|
}
|
||||||
|
|
||||||
|
template, err := buildNodeTemplateFromVMSS(vmss, map[string]string{}, "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
manager := &AzureManager{}
|
||||||
|
node, err := buildNodeFromTemplate(testNodeName, template, manager, false, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, node)
|
||||||
|
|
||||||
|
// Verify label prediction labels are added
|
||||||
|
assert.Equal(t, poolName, node.Labels["agentpool"])
|
||||||
|
assert.Equal(t, poolName, node.Labels["kubernetes.azure.com/agentpool"])
|
||||||
|
assert.Equal(t, "managed", node.Labels["storageprofile"])
|
||||||
|
assert.Equal(t, "managed", node.Labels["kubernetes.azure.com/storageprofile"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildNodeFromTemplateWithEphemeralStorage(t *testing.T) {
|
||||||
|
poolName := "testpool"
|
||||||
|
testSkuName := "Standard_DS2_v2"
|
||||||
|
testNodeName := "test-node"
|
||||||
|
diskSizeGB := int32(128)
|
||||||
|
|
||||||
|
vmss := compute.VirtualMachineScaleSet{
|
||||||
|
Response: autorest.Response{},
|
||||||
|
Sku: &compute.Sku{Name: &testSkuName},
|
||||||
|
Plan: nil,
|
||||||
|
VirtualMachineScaleSetProperties: &compute.VirtualMachineScaleSetProperties{
|
||||||
|
VirtualMachineProfile: &compute.VirtualMachineScaleSetVMProfile{
|
||||||
|
StorageProfile: &compute.VirtualMachineScaleSetStorageProfile{
|
||||||
|
OsDisk: &compute.VirtualMachineScaleSetOSDisk{
|
||||||
|
DiskSizeGB: &diskSizeGB,
|
||||||
|
DiffDiskSettings: nil, // This makes it managed
|
||||||
|
ManagedDisk: &compute.VirtualMachineScaleSetManagedDiskParameters{
|
||||||
|
StorageAccountType: compute.StorageAccountTypesPremiumLRS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tags: map[string]*string{
|
||||||
|
"poolName": &poolName,
|
||||||
|
},
|
||||||
|
Zones: &[]string{"1", "2"},
|
||||||
|
Location: to.StringPtr("westus"),
|
||||||
|
}
|
||||||
|
|
||||||
|
template, err := buildNodeTemplateFromVMSS(vmss, map[string]string{}, "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
manager := &AzureManager{}
|
||||||
|
node, err := buildNodeFromTemplate(testNodeName, template, manager, false, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, node)
|
||||||
|
|
||||||
|
// Verify ephemeral storage is set correctly
|
||||||
|
expectedEphemeralStorage := resource.NewQuantity(int64(diskSizeGB)*1024*1024*1024, resource.DecimalSI)
|
||||||
|
ephemeralStorage, exists := node.Status.Capacity[apiv1.ResourceEphemeralStorage]
|
||||||
|
assert.True(t, exists)
|
||||||
|
assert.Equal(t, expectedEphemeralStorage.String(), ephemeralStorage.String())
|
||||||
|
}
|
||||||
|
|
|
@ -469,7 +469,7 @@ func (vmPool *VMPool) TemplateNodeInfo() (*framework.NodeInfo, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
node, err := buildNodeFromTemplate(vmPool.agentPoolName, template, vmPool.manager, vmPool.manager.config.EnableDynamicInstanceList)
|
node, err := buildNodeFromTemplate(vmPool.agentPoolName, template, vmPool.manager, vmPool.manager.config.EnableDynamicInstanceList, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ rules:
|
||||||
resources: ["statefulsets", "replicasets", "daemonsets"]
|
resources: ["statefulsets", "replicasets", "daemonsets"]
|
||||||
verbs: ["watch", "list", "get"]
|
verbs: ["watch", "list", "get"]
|
||||||
- apiGroups: ["storage.k8s.io"]
|
- apiGroups: ["storage.k8s.io"]
|
||||||
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities"]
|
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities", "volumeattachments"]
|
||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
- apiGroups: ["batch"]
|
- apiGroups: ["batch"]
|
||||||
resources: ["jobs", "cronjobs"]
|
resources: ["jobs", "cronjobs"]
|
||||||
|
@ -125,7 +125,7 @@ data:
|
||||||
ClientID: <base64-encoded-client-id>
|
ClientID: <base64-encoded-client-id>
|
||||||
ClientSecret: <base64-encoded-client-secret>
|
ClientSecret: <base64-encoded-client-secret>
|
||||||
ResourceGroup: <base64-encoded-resource-group>
|
ResourceGroup: <base64-encoded-resource-group>
|
||||||
SubscriptionID: <base64-encode-subscription-id>
|
SubscriptionID: <base64-encoded-subscription-id>
|
||||||
TenantID: <base64-encoded-tenant-id>
|
TenantID: <base64-encoded-tenant-id>
|
||||||
VMType: QUtTCg==
|
VMType: QUtTCg==
|
||||||
kind: Secret
|
kind: Secret
|
||||||
|
@ -152,17 +152,7 @@ spec:
|
||||||
spec:
|
spec:
|
||||||
serviceAccountName: cluster-autoscaler
|
serviceAccountName: cluster-autoscaler
|
||||||
containers:
|
containers:
|
||||||
- image: registry.k8s.io/autoscaling/cluster-autoscaler:{{ ca_version }}
|
- command:
|
||||||
imagePullPolicy: Always
|
|
||||||
name: cluster-autoscaler
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpu: 100m
|
|
||||||
memory: 300Mi
|
|
||||||
requests:
|
|
||||||
cpu: 100m
|
|
||||||
memory: 300Mi
|
|
||||||
command:
|
|
||||||
- ./cluster-autoscaler
|
- ./cluster-autoscaler
|
||||||
- --v=3
|
- --v=3
|
||||||
- --logtostderr=true
|
- --logtostderr=true
|
||||||
|
@ -200,4 +190,14 @@ spec:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
key: VMType
|
key: VMType
|
||||||
name: cluster-autoscaler-azure
|
name: cluster-autoscaler-azure
|
||||||
|
image: registry.k8s.io/autoscaling/cluster-autoscaler:{{ ca_version }}
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: cluster-autoscaler
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 300Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 300Mi
|
||||||
restartPolicy: Always
|
restartPolicy: Always
|
||||||
|
|
|
@ -51,7 +51,7 @@ rules:
|
||||||
resources: ["statefulsets", "replicasets", "daemonsets"]
|
resources: ["statefulsets", "replicasets", "daemonsets"]
|
||||||
verbs: ["watch", "list", "get"]
|
verbs: ["watch", "list", "get"]
|
||||||
- apiGroups: ["storage.k8s.io"]
|
- apiGroups: ["storage.k8s.io"]
|
||||||
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities"]
|
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities", "volumeattachments"]
|
||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
- apiGroups: ["batch"]
|
- apiGroups: ["batch"]
|
||||||
resources: ["jobs", "cronjobs"]
|
resources: ["jobs", "cronjobs"]
|
||||||
|
@ -123,7 +123,7 @@ subjects:
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
ResourceGroup: <base64-encoded-resource-group>
|
ResourceGroup: <base64-encoded-resource-group>
|
||||||
SubscriptionID: <base64-encode-subscription-id>
|
SubscriptionID: <base64-encoded-subscription-id>
|
||||||
Deployment: <base64-encoded-azure-initial-deploy-name>
|
Deployment: <base64-encoded-azure-initial-deploy-name>
|
||||||
VMType: c3RhbmRhcmQ=
|
VMType: c3RhbmRhcmQ=
|
||||||
kind: Secret
|
kind: Secret
|
||||||
|
|
|
@ -51,7 +51,7 @@ rules:
|
||||||
resources: ["statefulsets", "replicasets", "daemonsets"]
|
resources: ["statefulsets", "replicasets", "daemonsets"]
|
||||||
verbs: ["watch", "list", "get"]
|
verbs: ["watch", "list", "get"]
|
||||||
- apiGroups: ["storage.k8s.io"]
|
- apiGroups: ["storage.k8s.io"]
|
||||||
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities"]
|
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities", "volumeattachments"]
|
||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
- apiGroups: ["batch"]
|
- apiGroups: ["batch"]
|
||||||
resources: ["jobs", "cronjobs"]
|
resources: ["jobs", "cronjobs"]
|
||||||
|
|
|
@ -51,7 +51,7 @@ rules:
|
||||||
resources: ["statefulsets", "replicasets", "daemonsets"]
|
resources: ["statefulsets", "replicasets", "daemonsets"]
|
||||||
verbs: ["watch", "list", "get"]
|
verbs: ["watch", "list", "get"]
|
||||||
- apiGroups: ["storage.k8s.io"]
|
- apiGroups: ["storage.k8s.io"]
|
||||||
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities"]
|
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities", "volumeattachments"]
|
||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
- apiGroups: ["batch"]
|
- apiGroups: ["batch"]
|
||||||
resources: ["jobs", "cronjobs"]
|
resources: ["jobs", "cronjobs"]
|
||||||
|
@ -123,7 +123,7 @@ subjects:
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
ResourceGroup: <base64-encoded-resource-group>
|
ResourceGroup: <base64-encoded-resource-group>
|
||||||
SubscriptionID: <base64-encode-subscription-id>
|
SubscriptionID: <base64-encoded-subscription-id>
|
||||||
Deployment: <base64-encoded-azure-initial-deploy-name>
|
Deployment: <base64-encoded-azure-initial-deploy-name>
|
||||||
VMType: c3RhbmRhcmQ=
|
VMType: c3RhbmRhcmQ=
|
||||||
kind: Secret
|
kind: Secret
|
||||||
|
|
|
@ -51,7 +51,7 @@ rules:
|
||||||
resources: ["statefulsets", "replicasets", "daemonsets"]
|
resources: ["statefulsets", "replicasets", "daemonsets"]
|
||||||
verbs: ["watch", "list", "get"]
|
verbs: ["watch", "list", "get"]
|
||||||
- apiGroups: ["storage.k8s.io"]
|
- apiGroups: ["storage.k8s.io"]
|
||||||
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities"]
|
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities", "volumeattachments"]
|
||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
- apiGroups: ["batch"]
|
- apiGroups: ["batch"]
|
||||||
resources: ["jobs", "cronjobs"]
|
resources: ["jobs", "cronjobs"]
|
||||||
|
@ -125,7 +125,7 @@ data:
|
||||||
ClientID: <base64-encoded-client-id>
|
ClientID: <base64-encoded-client-id>
|
||||||
ClientSecret: <base64-encoded-client-secret>
|
ClientSecret: <base64-encoded-client-secret>
|
||||||
ResourceGroup: <base64-encoded-resource-group>
|
ResourceGroup: <base64-encoded-resource-group>
|
||||||
SubscriptionID: <base64-encode-subscription-id>
|
SubscriptionID: <base64-encoded-subscription-id>
|
||||||
TenantID: <base64-encoded-tenant-id>
|
TenantID: <base64-encoded-tenant-id>
|
||||||
Deployment: <base64-encoded-azure-initial-deploy-name>
|
Deployment: <base64-encoded-azure-initial-deploy-name>
|
||||||
VMType: c3RhbmRhcmQ=
|
VMType: c3RhbmRhcmQ=
|
||||||
|
|
|
@ -51,7 +51,7 @@ rules:
|
||||||
resources: ["statefulsets", "replicasets", "daemonsets"]
|
resources: ["statefulsets", "replicasets", "daemonsets"]
|
||||||
verbs: ["watch", "list", "get"]
|
verbs: ["watch", "list", "get"]
|
||||||
- apiGroups: ["storage.k8s.io"]
|
- apiGroups: ["storage.k8s.io"]
|
||||||
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities"]
|
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities", "volumeattachments"]
|
||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
- apiGroups: ["batch"]
|
- apiGroups: ["batch"]
|
||||||
resources: ["jobs", "cronjobs"]
|
resources: ["jobs", "cronjobs"]
|
||||||
|
@ -125,7 +125,7 @@ data:
|
||||||
ClientID: <base64-encoded-client-id>
|
ClientID: <base64-encoded-client-id>
|
||||||
ClientSecret: <base64-encoded-client-secret>
|
ClientSecret: <base64-encoded-client-secret>
|
||||||
ResourceGroup: <base64-encoded-resource-group>
|
ResourceGroup: <base64-encoded-resource-group>
|
||||||
SubscriptionID: <base64-encode-subscription-id>
|
SubscriptionID: <base64-encoded-subscription-id>
|
||||||
TenantID: <base64-encoded-tenant-id>
|
TenantID: <base64-encoded-tenant-id>
|
||||||
VMType: dm1zcw==
|
VMType: dm1zcw==
|
||||||
kind: Secret
|
kind: Secret
|
||||||
|
@ -159,10 +159,7 @@ spec:
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
kubernetes.io/role: control-plane
|
kubernetes.io/role: control-plane
|
||||||
containers:
|
containers:
|
||||||
- image: registry.k8s.io/autoscaling/cluster-autoscaler:{{ ca_version }}
|
- command:
|
||||||
imagePullPolicy: Always
|
|
||||||
name: cluster-autoscaler
|
|
||||||
command:
|
|
||||||
- ./cluster-autoscaler
|
- ./cluster-autoscaler
|
||||||
- --v=3
|
- --v=3
|
||||||
- --logtostderr=true
|
- --logtostderr=true
|
||||||
|
@ -201,6 +198,9 @@ spec:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
key: VMType
|
key: VMType
|
||||||
name: cluster-autoscaler-azure
|
name: cluster-autoscaler-azure
|
||||||
|
image: registry.k8s.io/autoscaling/cluster-autoscaler:{{ ca_version }}
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: cluster-autoscaler
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
cpu: 100m
|
cpu: 100m
|
||||||
|
|
|
@ -51,7 +51,7 @@ rules:
|
||||||
resources: ["statefulsets", "replicasets", "daemonsets"]
|
resources: ["statefulsets", "replicasets", "daemonsets"]
|
||||||
verbs: ["watch", "list", "get"]
|
verbs: ["watch", "list", "get"]
|
||||||
- apiGroups: ["storage.k8s.io"]
|
- apiGroups: ["storage.k8s.io"]
|
||||||
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities"]
|
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities", "volumeattachments"]
|
||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
- apiGroups: ["batch"]
|
- apiGroups: ["batch"]
|
||||||
resources: ["jobs", "cronjobs"]
|
resources: ["jobs", "cronjobs"]
|
||||||
|
@ -123,7 +123,7 @@ subjects:
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
ResourceGroup: <base64-encoded-resource-group>
|
ResourceGroup: <base64-encoded-resource-group>
|
||||||
SubscriptionID: <base64-encode-subscription-id>
|
SubscriptionID: <base64-encoded-subscription-id>
|
||||||
VMType: dm1zcw==
|
VMType: dm1zcw==
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
|
@ -157,10 +157,7 @@ spec:
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
kubernetes.io/role: control-plane
|
kubernetes.io/role: control-plane
|
||||||
containers:
|
containers:
|
||||||
- image: registry.k8s.io/autoscaling/cluster-autoscaler:{{ ca_version }}
|
- command:
|
||||||
imagePullPolicy: Always
|
|
||||||
name: cluster-autoscaler
|
|
||||||
command:
|
|
||||||
- ./cluster-autoscaler
|
- ./cluster-autoscaler
|
||||||
- --v=3
|
- --v=3
|
||||||
- --logtostderr=true
|
- --logtostderr=true
|
||||||
|
@ -186,6 +183,9 @@ spec:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
key: VMType
|
key: VMType
|
||||||
name: cluster-autoscaler-azure
|
name: cluster-autoscaler-azure
|
||||||
|
image: registry.k8s.io/autoscaling/cluster-autoscaler:{{ ca_version }}
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: cluster-autoscaler
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
cpu: 100m
|
cpu: 100m
|
||||||
|
|
|
@ -51,7 +51,7 @@ rules:
|
||||||
resources: ["statefulsets", "replicasets", "daemonsets"]
|
resources: ["statefulsets", "replicasets", "daemonsets"]
|
||||||
verbs: ["watch", "list", "get"]
|
verbs: ["watch", "list", "get"]
|
||||||
- apiGroups: ["storage.k8s.io"]
|
- apiGroups: ["storage.k8s.io"]
|
||||||
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities"]
|
resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities", "volumeattachments"]
|
||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
- apiGroups: ["batch"]
|
- apiGroups: ["batch"]
|
||||||
resources: ["jobs", "cronjobs"]
|
resources: ["jobs", "cronjobs"]
|
||||||
|
@ -125,7 +125,7 @@ data:
|
||||||
ClientID: <base64-encoded-client-id>
|
ClientID: <base64-encoded-client-id>
|
||||||
ClientSecret: <base64-encoded-client-secret>
|
ClientSecret: <base64-encoded-client-secret>
|
||||||
ResourceGroup: <base64-encoded-resource-group>
|
ResourceGroup: <base64-encoded-resource-group>
|
||||||
SubscriptionID: <base64-encode-subscription-id>
|
SubscriptionID: <base64-encoded-subscription-id>
|
||||||
TenantID: <base64-encoded-tenant-id>
|
TenantID: <base64-encoded-tenant-id>
|
||||||
VMType: dm1zcw==
|
VMType: dm1zcw==
|
||||||
kind: Secret
|
kind: Secret
|
||||||
|
@ -152,17 +152,7 @@ spec:
|
||||||
spec:
|
spec:
|
||||||
serviceAccountName: cluster-autoscaler
|
serviceAccountName: cluster-autoscaler
|
||||||
containers:
|
containers:
|
||||||
- image: registry.k8s.io/autoscaling/cluster-autoscaler:{{ ca_version }}
|
- command:
|
||||||
imagePullPolicy: Always
|
|
||||||
name: cluster-autoscaler
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpu: 100m
|
|
||||||
memory: 300Mi
|
|
||||||
requests:
|
|
||||||
cpu: 100m
|
|
||||||
memory: 300Mi
|
|
||||||
command:
|
|
||||||
- ./cluster-autoscaler
|
- ./cluster-autoscaler
|
||||||
- --v=3
|
- --v=3
|
||||||
- --logtostderr=true
|
- --logtostderr=true
|
||||||
|
@ -201,6 +191,16 @@ spec:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
key: VMType
|
key: VMType
|
||||||
name: cluster-autoscaler-azure
|
name: cluster-autoscaler-azure
|
||||||
|
image: registry.k8s.io/autoscaling/cluster-autoscaler:{{ ca_version }}
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: cluster-autoscaler
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 300Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 300Mi
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- mountPath: /etc/ssl/certs/ca-certificates.crt
|
- mountPath: /etc/ssl/certs/ca-certificates.crt
|
||||||
name: ssl-certs
|
name: ssl-certs
|
||||||
|
|
|
@ -1,87 +1,75 @@
|
||||||
module k8s.io/autoscaler/cluster-autoscaler/cloudprovider/azure/test
|
module k8s.io/autoscaler/cluster-autoscaler/cloudprovider/azure/test
|
||||||
|
|
||||||
go 1.23.0
|
go 1.24.0
|
||||||
|
|
||||||
toolchain go1.23.3
|
toolchain go1.24.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0
|
||||||
github.com/onsi/ginkgo/v2 v2.19.0
|
github.com/onsi/ginkgo/v2 v2.23.4
|
||||||
github.com/onsi/gomega v1.33.1
|
github.com/onsi/gomega v1.37.0
|
||||||
helm.sh/helm/v3 v3.15.2
|
helm.sh/helm/v3 v3.18.3
|
||||||
k8s.io/api v0.30.2
|
k8s.io/api v0.34.0-alpha.1
|
||||||
k8s.io/apimachinery v0.30.2
|
k8s.io/apimachinery v0.34.0-alpha.1
|
||||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
|
||||||
sigs.k8s.io/controller-runtime v0.18.4
|
sigs.k8s.io/controller-runtime v0.21.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
dario.cat/mergo v1.0.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
|
||||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
github.com/Masterminds/semver/v3 v3.3.0 // indirect
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
||||||
github.com/Masterminds/squirrel v1.5.4 // indirect
|
github.com/Masterminds/squirrel v1.5.4 // indirect
|
||||||
github.com/Microsoft/hcsshim v0.11.4 // indirect
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
|
||||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||||
github.com/containerd/containerd v1.7.12 // indirect
|
github.com/containerd/containerd v1.7.27 // indirect
|
||||||
|
github.com/containerd/errdefs v0.3.0 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
github.com/containerd/platforms v0.2.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||||
github.com/distribution/reference v0.5.0 // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/docker/cli v25.0.1+incompatible // indirect
|
|
||||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
|
||||||
github.com/docker/docker v25.0.5+incompatible // indirect
|
|
||||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
|
||||||
github.com/docker/go-connections v0.5.0 // indirect
|
|
||||||
github.com/docker/go-metrics v0.0.1 // indirect
|
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||||
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
|
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
|
||||||
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
|
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
|
||||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
|
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||||
github.com/fatih/color v1.13.0 // indirect
|
github.com/fatih/color v1.13.0 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||||
github.com/go-errors/errors v1.4.2 // indirect
|
github.com/go-errors/errors v1.4.2 // indirect
|
||||||
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.1 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
github.com/go-openapi/swag v0.22.3 // indirect
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/google/btree v1.1.3 // indirect
|
||||||
github.com/google/btree v1.0.1 // indirect
|
github.com/google/gnostic-models v0.6.9 // indirect
|
||||||
github.com/google/gnostic-models v0.6.8 // indirect
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
|
||||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
|
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/mux v1.8.0 // indirect
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
|
||||||
github.com/gosuri/uitable v0.0.4 // indirect
|
github.com/gosuri/uitable v0.0.4 // indirect
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/huandu/xstrings v1.4.0 // indirect
|
github.com/huandu/xstrings v1.5.0 // indirect
|
||||||
github.com/imdario/mergo v0.3.13 // indirect
|
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jmoiron/sqlx v1.3.5 // indirect
|
github.com/jmoiron/sqlx v1.4.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.16.0 // indirect
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||||
|
@ -91,70 +79,62 @@ require (
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
github.com/moby/locker v1.0.1 // indirect
|
github.com/moby/spdystream v0.5.0 // indirect
|
||||||
github.com/moby/spdystream v0.2.0 // indirect
|
github.com/moby/term v0.5.2 // indirect
|
||||||
github.com/moby/term v0.5.0 // indirect
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.0-rc6 // indirect
|
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus/client_golang v1.16.0 // indirect
|
github.com/rubenv/sql-migrate v1.8.0 // indirect
|
||||||
github.com/prometheus/client_model v0.4.0 // indirect
|
|
||||||
github.com/prometheus/common v0.44.0 // indirect
|
|
||||||
github.com/prometheus/procfs v0.12.0 // indirect
|
|
||||||
github.com/rubenv/sql-migrate v1.5.2 // indirect
|
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/shopspring/decimal v1.3.1 // indirect
|
github.com/shopspring/decimal v1.4.0 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/spf13/cast v1.5.0 // indirect
|
github.com/spf13/cast v1.7.0 // indirect
|
||||||
github.com/spf13/cobra v1.8.0 // indirect
|
github.com/spf13/cobra v1.9.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
github.com/xlab/treeprint v1.2.0 // indirect
|
github.com/xlab/treeprint v1.2.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
|
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.19.0 // indirect
|
golang.org/x/crypto v0.39.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.19.0 // indirect
|
golang.org/x/net v0.40.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.19.0 // indirect
|
golang.org/x/oauth2 v0.28.0 // indirect
|
||||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
golang.org/x/sync v0.15.0 // indirect
|
||||||
golang.org/x/crypto v0.24.0 // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
golang.org/x/net v0.26.0 // indirect
|
golang.org/x/term v0.32.0 // indirect
|
||||||
golang.org/x/oauth2 v0.27.0 // indirect
|
golang.org/x/text v0.26.0 // indirect
|
||||||
golang.org/x/sync v0.7.0 // indirect
|
golang.org/x/time v0.9.0 // indirect
|
||||||
golang.org/x/sys v0.21.0 // indirect
|
golang.org/x/tools v0.33.0 // indirect
|
||||||
golang.org/x/term v0.21.0 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
|
||||||
golang.org/x/text v0.16.0 // indirect
|
google.golang.org/grpc v1.68.1 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
google.golang.org/protobuf v1.36.5 // indirect
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
|
|
||||||
google.golang.org/grpc v1.58.3 // indirect
|
|
||||||
google.golang.org/protobuf v1.33.0 // indirect
|
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
k8s.io/apiextensions-apiserver v0.30.1 // indirect
|
k8s.io/apiextensions-apiserver v0.33.1 // indirect
|
||||||
k8s.io/apiserver v0.30.1 // indirect
|
k8s.io/apiserver v0.33.1 // indirect
|
||||||
k8s.io/cli-runtime v0.30.2 // indirect
|
k8s.io/cli-runtime v0.33.1 // indirect
|
||||||
k8s.io/client-go v0.30.2 // indirect
|
k8s.io/client-go v0.34.0-alpha.1 // indirect
|
||||||
k8s.io/component-base v0.30.1 // indirect
|
k8s.io/component-base v0.33.1 // indirect
|
||||||
k8s.io/klog/v2 v2.120.1 // indirect
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||||
k8s.io/kubectl v0.30.0 // indirect
|
k8s.io/kubectl v0.33.1 // indirect
|
||||||
oras.land/oras-go v1.2.5 // indirect
|
oras.land/oras-go/v2 v2.6.0 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||||
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
|
sigs.k8s.io/kustomize/api v0.19.0 // indirect
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
|
sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
|
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
||||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||||
|
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM=
|
||||||
|
@ -13,235 +16,170 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFG
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI=
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 h1:7CBQ+Ei8SP2c6ydQTGCCrS35bDxgTMfoP2miAwK++OU=
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 h1:7CBQ+Ei8SP2c6ydQTGCCrS35bDxgTMfoP2miAwK++OU=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw=
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
|
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
|
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
|
||||||
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
||||||
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||||
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
|
||||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
|
||||||
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
|
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
|
||||||
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
||||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
|
||||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
|
||||||
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
|
|
||||||
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
|
|
||||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
|
|
||||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||||
|
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||||
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
|
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
|
||||||
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
||||||
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng=
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
|
|
||||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
|
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
|
||||||
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
|
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
|
||||||
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
|
|
||||||
github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0=
|
|
||||||
github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk=
|
|
||||||
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
|
|
||||||
github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||||
|
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/docker/cli v25.0.1+incompatible h1:mFpqnrS6Hsm3v1k7Wa/BO23oz0k121MTbTO1lpcGSkU=
|
github.com/distribution/distribution/v3 v3.0.0 h1:q4R8wemdRQDClzoNNStftB2ZAfqOiN6UX90KJc4HjyM=
|
||||||
github.com/docker/cli v25.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/distribution/distribution/v3 v3.0.0/go.mod h1:tRNuFoZsUdyRVegq8xGNeds4KLjwLCRin/tTo6i1DhU=
|
||||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE=
|
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||||
github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||||
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
|
||||||
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
|
|
||||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
|
||||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
|
||||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
|
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
|
||||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
||||||
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||||
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
|
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
|
||||||
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4=
|
|
||||||
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI=
|
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
|
||||||
github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
|
||||||
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
|
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
|
||||||
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
|
||||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
|
|
||||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
|
|
||||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI=
|
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
|
||||||
github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4=
|
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
|
||||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||||
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
|
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
|
||||||
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
|
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
|
||||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
|
||||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||||
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
|
||||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU=
|
|
||||||
github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs=
|
|
||||||
github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0=
|
|
||||||
github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY=
|
|
||||||
github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY=
|
|
||||||
github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc=
|
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k=
|
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||||
github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
|
||||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
|
||||||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
|
||||||
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
|
|
||||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
|
||||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
|
||||||
github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
|
github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
|
||||||
github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
|
github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw=
|
||||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU=
|
||||||
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
|
||||||
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
|
github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
||||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
|
||||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
||||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
|
||||||
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
|
|
||||||
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
@ -255,19 +193,12 @@ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq
|
||||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
||||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
||||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
|
|
||||||
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
|
|
||||||
github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY=
|
|
||||||
github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI=
|
|
||||||
github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=
|
|
||||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
|
||||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
@ -278,119 +209,103 @@ github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPn
|
||||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
|
||||||
github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg=
|
|
||||||
github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
|
||||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
|
||||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
|
||||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
|
||||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
||||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
||||||
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
|
|
||||||
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
|
|
||||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
|
||||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
|
||||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
|
||||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
|
||||||
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
|
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||||
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
|
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.0-rc6 h1:XDqvyKsJEbRtATzkgItUqBA7QHk58yxX1Ov9HERHNqU=
|
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||||
github.com/opencontainers/image-spec v1.1.0-rc6/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
|
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
|
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
|
||||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
|
github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
|
||||||
github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
|
github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||||
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
|
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||||
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||||
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho=
|
||||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U=
|
||||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc=
|
||||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ=
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
github.com/rubenv/sql-migrate v1.8.0 h1:dXnYiJk9k3wetp7GfQbKJcPHjVJL6YK19tKj8t2Ns0o=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rubenv/sql-migrate v1.8.0/go.mod h1:F2bGFBwCU+pnmbtNYDeKvSuvL6lBVtXDXUUv5t+u1qw=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
|
||||||
github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0=
|
|
||||||
github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is=
|
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
@ -402,202 +317,171 @@ github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
|
||||||
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
|
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||||
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI=
|
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||||
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
|
go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 h1:UW0+QyeyBVhn+COBec3nGhfnFe5lwB0ic1JBVjzhk0w=
|
||||||
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE=
|
go.opentelemetry.io/contrib/bridges/prometheus v0.57.0/go.mod h1:ppciCHRLsyCio54qbzQv0E4Jyth/fLWDTJYfvWpcSVk=
|
||||||
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
|
go.opentelemetry.io/contrib/exporters/autoexport v0.57.0 h1:jmTVJ86dP60C01K3slFQa2NQ/Aoi7zA+wy7vMOKD9H4=
|
||||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY=
|
go.opentelemetry.io/contrib/exporters/autoexport v0.57.0/go.mod h1:EJBheUMttD/lABFyLXhce47Wr6DPWYReCzaZiXadH7g=
|
||||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU=
|
||||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
|
||||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg=
|
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q=
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 h1:WzNab7hOOLzdDF/EoWCt4glhrbMPVMOO5JYTmpz36Ls=
|
||||||
go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0/go.mod h1:hKvJwTzJdp90Vh7p6q/9PAOd55dI6WA6sWj62a/JvSs=
|
||||||
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 h1:S+LdBGiQXtJdowoJoQPEtI52syEP/JYBUpjO49EQhV8=
|
||||||
go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0/go.mod h1:5KXybFvPGds3QinJWQT7pmXf+TN5YIa7CNYObWRkj50=
|
||||||
go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7ZSD+5yn+lo3sGV69nW04rRR0jhYnBwjuX3r0HvnK0=
|
||||||
go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0/go.mod h1:WXbYJTUaZXAbYd8lbgGuvih0yuCfOFC5RJoYnoLcGz8=
|
||||||
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 h1:t/Qur3vKSkUCcDVaSumWF2PKHt85pc7fRvFuoVT8qFU=
|
||||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0/go.mod h1:Rl61tySSdcOJWoEgYZVtmnKdA0GeKrSqkHC1t+91CH8=
|
||||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 h1:cMyu9O88joYEaI47CnQkxO1XZdpoTF9fEnW2duIddhw=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0/go.mod h1:6Am3rn7P9TVVeXYG+wtcGE7IE1tsQ+bP3AuWcKt/gOI=
|
||||||
|
go.opentelemetry.io/otel/exporters/prometheus v0.54.0 h1:rFwzp68QMgtzu9PgP3jm9XaMICI6TsofWWPcBDKwlsU=
|
||||||
|
go.opentelemetry.io/otel/exporters/prometheus v0.54.0/go.mod h1:QyjcV9qDP6VeK5qPyKETvNjmaaEc7+gqjh4SS0ZYzDU=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0 h1:CHXNXwfKWfzS65yrlB2PVds1IBZcdsX8Vepy9of0iRU=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0/go.mod h1:zKU4zUgKiaRxrdovSS2amdM5gOc59slmo/zJwGX+YBg=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0 h1:SZmDnHcgp3zwlPBS2JX2urGYe/jBKEIT6ZedHRUyCz8=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0/go.mod h1:fdWW0HtZJ7+jNpTKUR0GpMEDP69nR8YBJQxNiVCE3jk=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0 h1:cC2yDI3IQd0Udsux7Qmq8ToKAx1XCilTQECZ0KDZyTw=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0/go.mod h1:2PD5Ex6z8CFzDbTdOlwyNIUywRr1DN0ospafJM1wJ+s=
|
||||||
|
go.opentelemetry.io/otel/log v0.8.0 h1:egZ8vV5atrUWUbnSsHn6vB8R21G2wrKqNiDt3iWertk=
|
||||||
|
go.opentelemetry.io/otel/log v0.8.0/go.mod h1:M9qvDdUTRCopJcGRKg57+JSQ9LgLBrwwfC32epk5NX8=
|
||||||
|
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
|
||||||
|
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM=
|
||||||
|
go.opentelemetry.io/otel/sdk/log v0.8.0 h1:zg7GUYXqxk1jnGF/dTdLPrK06xJdrXgqgFLnI4Crxvs=
|
||||||
|
go.opentelemetry.io/otel/sdk/log v0.8.0/go.mod h1:50iXr0UVwQrYS45KbruFrEt4LvAdCaWWgIrsN3ZQggo=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
|
||||||
|
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
|
||||||
|
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
|
||||||
|
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||||
|
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
|
||||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
|
||||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
|
||||||
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
|
||||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
|
||||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
|
||||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
|
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
|
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ=
|
|
||||||
google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
|
||||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
|
||||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
|
helm.sh/helm/v3 v3.18.3 h1:+cvyGKgs7Jt7BN3Klmb4SsG4IkVpA7GAZVGvMz6VO4I=
|
||||||
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
|
helm.sh/helm/v3 v3.18.3/go.mod h1:wUc4n3txYBocM7S9RjTeZBN9T/b5MjffpcSsWEjSIpw=
|
||||||
helm.sh/helm/v3 v3.15.2 h1:/3XINUFinJOBjQplGnjw92eLGpgXXp1L8chWPkCkDuw=
|
k8s.io/api v0.34.0-alpha.1 h1:Hye5ehH+riYQU/M/y/F8/L7hE6ZO5QZrH53zxcySa2Q=
|
||||||
helm.sh/helm/v3 v3.15.2/go.mod h1:FzSIP8jDQaa6WAVg9F+OkKz7J0ZmAga4MABtTbsb9WQ=
|
k8s.io/api v0.34.0-alpha.1/go.mod h1:Dl+4wVA5vZVlN4ckJ34aAQXRDciXazH930XZh92Lubk=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
k8s.io/apiextensions-apiserver v0.33.1 h1:N7ccbSlRN6I2QBcXevB73PixX2dQNIW0ZRuguEE91zI=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
k8s.io/apiextensions-apiserver v0.33.1/go.mod h1:uNQ52z1A1Gu75QSa+pFK5bcXc4hq7lpOXbweZgi4dqA=
|
||||||
k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI=
|
k8s.io/apimachinery v0.34.0-alpha.1 h1:pA/Biuywm6Us4cZb5FLIHi8idQZXq3/8Bw3h2dqtop4=
|
||||||
k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI=
|
k8s.io/apimachinery v0.34.0-alpha.1/go.mod h1:EZ7eIfFAwky7ktmG4Pu9XWxBxFG++4dxPDOM0GL3abw=
|
||||||
k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws=
|
k8s.io/apiserver v0.33.1 h1:yLgLUPDVC6tHbNcw5uE9mo1T6ELhJj7B0geifra3Qdo=
|
||||||
k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4=
|
k8s.io/apiserver v0.33.1/go.mod h1:VMbE4ArWYLO01omz+k8hFjAdYfc3GVAYPrhP2tTKccs=
|
||||||
k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg=
|
k8s.io/cli-runtime v0.33.1 h1:TvpjEtF71ViFmPeYMj1baZMJR4iWUEplklsUQ7D3quA=
|
||||||
k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
|
k8s.io/cli-runtime v0.33.1/go.mod h1:9dz5Q4Uh8io4OWCLiEf/217DXwqNgiTS/IOuza99VZE=
|
||||||
k8s.io/apiserver v0.30.1 h1:BEWEe8bzS12nMtDKXzCF5Q5ovp6LjjYkSp8qOPk8LZ8=
|
k8s.io/client-go v0.34.0-alpha.1 h1:u9jrtaizUQ1sdchbf5v72ZKC8rj1XI9RAMsDlN4Gcy4=
|
||||||
k8s.io/apiserver v0.30.1/go.mod h1:i87ZnQ+/PGAmSbD/iEKM68bm1D5reX8fO4Ito4B01mo=
|
k8s.io/client-go v0.34.0-alpha.1/go.mod h1:MyOhbMoeBUilHgYvjBP7U5BIBkbCUBCdZPzWZuj9i8g=
|
||||||
k8s.io/cli-runtime v0.30.2 h1:ooM40eEJusbgHNEqnHziN9ZpLN5U4WcQGsdLKVxpkKE=
|
k8s.io/component-base v0.33.1 h1:EoJ0xA+wr77T+G8p6T3l4efT2oNwbqBVKR71E0tBIaI=
|
||||||
k8s.io/cli-runtime v0.30.2/go.mod h1:Y4g/2XezFyTATQUbvV5WaChoUGhojv/jZAtdp5Zkm0A=
|
k8s.io/component-base v0.33.1/go.mod h1:guT/w/6piyPfTgq7gfvgetyXMIh10zuXA6cRRm3rDuY=
|
||||||
k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50=
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs=
|
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||||
k8s.io/component-base v0.30.1 h1:bvAtlPh1UrdaZL20D9+sWxsJljMi0QZ3Lmw+kmZAaxQ=
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
|
||||||
k8s.io/component-base v0.30.1/go.mod h1:e/X9kDiOebwlI41AvBHuWdqFriSRrX50CdwA9TFaHLI=
|
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
|
||||||
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
|
k8s.io/kubectl v0.33.1 h1:OJUXa6FV5bap6iRy345ezEjU9dTLxqv1zFTVqmeHb6A=
|
||||||
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
k8s.io/kubectl v0.33.1/go.mod h1:Z07pGqXoP4NgITlPRrnmiM3qnoo1QrK1zjw85Aiz8J0=
|
||||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
||||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
k8s.io/kubectl v0.30.0 h1:xbPvzagbJ6RNYVMVuiHArC1grrV5vSmmIcSZuCdzRyk=
|
oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc=
|
||||||
k8s.io/kubectl v0.30.0/go.mod h1:zgolRw2MQXLPwmic2l/+iHs239L49fhSeICuMhQQXTI=
|
oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o=
|
||||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
|
sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8=
|
||||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM=
|
||||||
oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo=
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
||||||
oras.land/oras-go v1.2.5/go.mod h1:PuAwRShRZCsZb7g8Ar3jKKQR/2A/qN+pkYxIOd/FAoo=
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
||||||
sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw=
|
sigs.k8s.io/kustomize/api v0.19.0 h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ=
|
||||||
sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg=
|
sigs.k8s.io/kustomize/api v0.19.0/go.mod h1:/BbwnivGVcBh1r+8m3tH1VNxJmHSk1PzP5fkP6lbL1o=
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
sigs.k8s.io/kustomize/kyaml v0.19.0 h1:RFge5qsO1uHhwJsu3ipV7RNolC7Uozc0jUBC/61XSlA=
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
sigs.k8s.io/kustomize/kyaml v0.19.0/go.mod h1:FeKD5jEOH+FbZPpqUghBP8mrLjJ3+zD3/rf9NNu1cwY=
|
||||||
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
|
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY=
|
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U=
|
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag=
|
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
|
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
|
|
||||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||||
|
|
|
@ -79,6 +79,12 @@ in the staging namespace, belonging to the purple cluster, with the label owner=
|
||||||
|
|
||||||
## Connecting cluster-autoscaler to Cluster API management and workload Clusters
|
## Connecting cluster-autoscaler to Cluster API management and workload Clusters
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> `--cloud-config` is the flag for specifying a mount volume path to the kubernetes configuration (ie KUBECONFIG) to the cluster-autoscaler for communicating with the cluster-api management cluster for the purpose of scaling machines.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> ``--kubeconfig` is the flag for specifying a mount volume path to the kubernetes configuration (ie KUBECONFIG) to the cluster-autoscaler for communicating with the cluster-api workload cluster for the purpose of watching Nodes and Pods. This flag can be affected by the desired topology for deploying the cluster-autoscaler, please see the diagrams below for more information.
|
||||||
|
|
||||||
You will also need to provide the path to the kubeconfig(s) for the management
|
You will also need to provide the path to the kubeconfig(s) for the management
|
||||||
and workload cluster you wish cluster-autoscaler to run against. To specify the
|
and workload cluster you wish cluster-autoscaler to run against. To specify the
|
||||||
kubeconfig path for the workload cluster to monitor, use the `--kubeconfig`
|
kubeconfig path for the workload cluster to monitor, use the `--kubeconfig`
|
||||||
|
|
|
@ -7,6 +7,7 @@ spec:
|
||||||
isCA: true
|
isCA: true
|
||||||
commonName: selfsigned-ca
|
commonName: selfsigned-ca
|
||||||
secretName: ca-root-secret
|
secretName: ca-root-secret
|
||||||
|
duration: 87600h
|
||||||
privateKey:
|
privateKey:
|
||||||
algorithm: ECDSA
|
algorithm: ECDSA
|
||||||
size: 256
|
size: 256
|
||||||
|
|
|
@ -78,6 +78,7 @@ var (
|
||||||
"e2": 0.021811,
|
"e2": 0.021811,
|
||||||
"h4d": 0.03224,
|
"h4d": 0.03224,
|
||||||
"m1": 0.0348,
|
"m1": 0.0348,
|
||||||
|
"m4": 0.0182784,
|
||||||
"n1": 0.031611,
|
"n1": 0.031611,
|
||||||
"n2": 0.031611,
|
"n2": 0.031611,
|
||||||
"n2d": 0.027502,
|
"n2d": 0.027502,
|
||||||
|
@ -95,6 +96,7 @@ var (
|
||||||
"e2": 0.002923,
|
"e2": 0.002923,
|
||||||
"h4d": 0.00231,
|
"h4d": 0.00231,
|
||||||
"m1": 0.0051,
|
"m1": 0.0051,
|
||||||
|
"m4": 0.00457,
|
||||||
"n1": 0.004237,
|
"n1": 0.004237,
|
||||||
"n2": 0.004237,
|
"n2": 0.004237,
|
||||||
"n2d": 0.003686,
|
"n2d": 0.003686,
|
||||||
|
@ -112,6 +114,7 @@ var (
|
||||||
"e2": 0.006543 / 0.021811,
|
"e2": 0.006543 / 0.021811,
|
||||||
"h4d": 0.019343999999999997 / 0.03224,
|
"h4d": 0.019343999999999997 / 0.03224,
|
||||||
"m1": 0.00733 / 0.0348,
|
"m1": 0.00733 / 0.0348,
|
||||||
|
"m4": 0.0073114 / 0.0182784,
|
||||||
"n1": 0.006655 / 0.031611,
|
"n1": 0.006655 / 0.031611,
|
||||||
"n2": 0.007650 / 0.031611,
|
"n2": 0.007650 / 0.031611,
|
||||||
"n2d": 0.002773 / 0.027502,
|
"n2d": 0.002773 / 0.027502,
|
||||||
|
|
|
@ -10,16 +10,16 @@ The cluster autoscaler for Hetzner Cloud scales worker nodes.
|
||||||
|
|
||||||
`HCLOUD_IMAGE` Defaults to `ubuntu-20.04`, @see https://docs.hetzner.cloud/#images. You can also use an image ID here (e.g. `15512617`), or a label selector associated with a custom snapshot (e.g. `customized_ubuntu=true`). The most recent snapshot will be used in the latter case.
|
`HCLOUD_IMAGE` Defaults to `ubuntu-20.04`, @see https://docs.hetzner.cloud/#images. You can also use an image ID here (e.g. `15512617`), or a label selector associated with a custom snapshot (e.g. `customized_ubuntu=true`). The most recent snapshot will be used in the latter case.
|
||||||
|
|
||||||
`HCLOUD_CLUSTER_CONFIG` This is the new format replacing
|
`HCLOUD_CLUSTER_CONFIG` This is the new format replacing
|
||||||
* `HCLOUD_CLOUD_INIT`
|
* `HCLOUD_CLOUD_INIT`
|
||||||
* `HCLOUD_IMAGE`
|
* `HCLOUD_IMAGE`
|
||||||
|
|
||||||
Base64 encoded JSON according to the following structure
|
Base64 encoded JSON according to the following structure
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"imagesForArch": { // These should be the same format as HCLOUD_IMAGE
|
"imagesForArch": { // These should be the same format as HCLOUD_IMAGE
|
||||||
"arm64": "",
|
"arm64": "",
|
||||||
"amd64": ""
|
"amd64": ""
|
||||||
},
|
},
|
||||||
"nodeConfigs": {
|
"nodeConfigs": {
|
||||||
|
@ -28,7 +28,7 @@ The cluster autoscaler for Hetzner Cloud scales worker nodes.
|
||||||
"labels": {
|
"labels": {
|
||||||
"node.kubernetes.io/role": "autoscaler-node"
|
"node.kubernetes.io/role": "autoscaler-node"
|
||||||
},
|
},
|
||||||
"taints":
|
"taints":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"key": "node.kubernetes.io/role",
|
"key": "node.kubernetes.io/role",
|
||||||
|
@ -47,6 +47,13 @@ Can be useful when you have many different node pools and run into issues of the
|
||||||
|
|
||||||
**NOTE**: In contrast to `HCLOUD_CLUSTER_CONFIG`, this file is not base64 encoded.
|
**NOTE**: In contrast to `HCLOUD_CLUSTER_CONFIG`, this file is not base64 encoded.
|
||||||
|
|
||||||
|
The global `imagesForArch` configuration can be overridden on a per-nodepool basis by adding an `imagesForArch` field to individual nodepool configurations.
|
||||||
|
|
||||||
|
The image selection logic works as follows:
|
||||||
|
|
||||||
|
1. If a nodepool has its own `imagesForArch` configuration, it will be used for that specific nodepool
|
||||||
|
1. If a nodepool doesn't have `imagesForArch` configured, the global `imagesForArch` configuration will be used as a fallback
|
||||||
|
1. If neither is configured, the legacy `HCLOUD_IMAGE` environment variable will be used
|
||||||
|
|
||||||
`HCLOUD_NETWORK` Default empty , The id or name of the network that is used in the cluster , @see https://docs.hetzner.cloud/#networks
|
`HCLOUD_NETWORK` Default empty , The id or name of the network that is used in the cluster , @see https://docs.hetzner.cloud/#networks
|
||||||
|
|
||||||
|
@ -105,5 +112,5 @@ git add hcloud-go/
|
||||||
|
|
||||||
## Debugging
|
## Debugging
|
||||||
|
|
||||||
To enable debug logging, set the log level of the autoscaler to at least level 5 via cli flag: `--v=5`
|
To enable debug logging, set the log level of the autoscaler to at least level 5 via cli flag: `--v=5`
|
||||||
The logs will include all requests and responses made towards the Hetzner API including headers and body.
|
The logs will include all requests and responses made towards the Hetzner API including headers and body.
|
||||||
|
|
|
@ -77,6 +77,7 @@ type NodeConfig struct {
|
||||||
PlacementGroup string
|
PlacementGroup string
|
||||||
Taints []apiv1.Taint
|
Taints []apiv1.Taint
|
||||||
Labels map[string]string
|
Labels map[string]string
|
||||||
|
ImagesForArch *ImageList
|
||||||
}
|
}
|
||||||
|
|
||||||
// LegacyConfig holds the configuration in the legacy format
|
// LegacyConfig holds the configuration in the legacy format
|
||||||
|
|
|
@ -528,12 +528,20 @@ func findImage(n *hetznerNodeGroup, serverType *hcloud.ServerType) (*hcloud.Imag
|
||||||
// Select correct image based on server type architecture
|
// Select correct image based on server type architecture
|
||||||
imageName := n.manager.clusterConfig.LegacyConfig.ImageName
|
imageName := n.manager.clusterConfig.LegacyConfig.ImageName
|
||||||
if n.manager.clusterConfig.IsUsingNewFormat {
|
if n.manager.clusterConfig.IsUsingNewFormat {
|
||||||
|
// Check for nodepool-specific images first, then fall back to global images
|
||||||
|
var imagesForArch *ImageList
|
||||||
|
if nodeConfig, exists := n.manager.clusterConfig.NodeConfigs[n.id]; exists && nodeConfig.ImagesForArch != nil {
|
||||||
|
imagesForArch = nodeConfig.ImagesForArch
|
||||||
|
} else {
|
||||||
|
imagesForArch = &n.manager.clusterConfig.ImagesForArch
|
||||||
|
}
|
||||||
|
|
||||||
if serverType.Architecture == hcloud.ArchitectureARM {
|
if serverType.Architecture == hcloud.ArchitectureARM {
|
||||||
imageName = n.manager.clusterConfig.ImagesForArch.Arm64
|
imageName = imagesForArch.Arm64
|
||||||
}
|
}
|
||||||
|
|
||||||
if serverType.Architecture == hcloud.ArchitectureX86 {
|
if serverType.Architecture == hcloud.ArchitectureX86 {
|
||||||
imageName = n.manager.clusterConfig.ImagesForArch.Amd64
|
imageName = imagesForArch.Amd64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package hetzner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFindImageWithPerNodepoolConfig(t *testing.T) {
|
||||||
|
// Test case 1: Nodepool with specific imagesForArch should use those images
|
||||||
|
t.Run("nodepool with specific imagesForArch", func(t *testing.T) {
|
||||||
|
manager := &hetznerManager{
|
||||||
|
clusterConfig: &ClusterConfig{
|
||||||
|
IsUsingNewFormat: true,
|
||||||
|
ImagesForArch: ImageList{
|
||||||
|
Arm64: "global-arm64-image",
|
||||||
|
Amd64: "global-amd64-image",
|
||||||
|
},
|
||||||
|
NodeConfigs: map[string]*NodeConfig{
|
||||||
|
"pool1": {
|
||||||
|
ImagesForArch: &ImageList{
|
||||||
|
Arm64: "pool1-arm64-image",
|
||||||
|
Amd64: "pool1-amd64-image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeGroup := &hetznerNodeGroup{
|
||||||
|
id: "pool1",
|
||||||
|
manager: manager,
|
||||||
|
}
|
||||||
|
|
||||||
|
// This would normally call the actual API, but we're just testing the logic
|
||||||
|
// The actual image selection logic is in findImage function
|
||||||
|
// For this test, we'll verify the configuration is set up correctly
|
||||||
|
nodeConfig, exists := manager.clusterConfig.NodeConfigs[nodeGroup.id]
|
||||||
|
require.True(t, exists)
|
||||||
|
require.NotNil(t, nodeConfig.ImagesForArch)
|
||||||
|
assert.Equal(t, "pool1-arm64-image", nodeConfig.ImagesForArch.Arm64)
|
||||||
|
assert.Equal(t, "pool1-amd64-image", nodeConfig.ImagesForArch.Amd64)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test case 2: Nodepool without specific imagesForArch should fall back to global
|
||||||
|
t.Run("nodepool without specific imagesForArch", func(t *testing.T) {
|
||||||
|
manager := &hetznerManager{
|
||||||
|
clusterConfig: &ClusterConfig{
|
||||||
|
IsUsingNewFormat: true,
|
||||||
|
ImagesForArch: ImageList{
|
||||||
|
Arm64: "global-arm64-image",
|
||||||
|
Amd64: "global-amd64-image",
|
||||||
|
},
|
||||||
|
NodeConfigs: map[string]*NodeConfig{
|
||||||
|
"pool2": {
|
||||||
|
// No ImagesForArch specified
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeGroup := &hetznerNodeGroup{
|
||||||
|
id: "pool2",
|
||||||
|
manager: manager,
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeConfig, exists := manager.clusterConfig.NodeConfigs[nodeGroup.id]
|
||||||
|
require.True(t, exists)
|
||||||
|
assert.Nil(t, nodeConfig.ImagesForArch)
|
||||||
|
assert.Equal(t, "global-arm64-image", manager.clusterConfig.ImagesForArch.Arm64)
|
||||||
|
assert.Equal(t, "global-amd64-image", manager.clusterConfig.ImagesForArch.Amd64)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test case 3: Nodepool with nil ImagesForArch should fall back to global
|
||||||
|
t.Run("nodepool with nil imagesForArch", func(t *testing.T) {
|
||||||
|
manager := &hetznerManager{
|
||||||
|
clusterConfig: &ClusterConfig{
|
||||||
|
IsUsingNewFormat: true,
|
||||||
|
ImagesForArch: ImageList{
|
||||||
|
Arm64: "global-arm64-image",
|
||||||
|
Amd64: "global-amd64-image",
|
||||||
|
},
|
||||||
|
NodeConfigs: map[string]*NodeConfig{
|
||||||
|
"pool3": {
|
||||||
|
ImagesForArch: nil, // Explicitly nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeGroup := &hetznerNodeGroup{
|
||||||
|
id: "pool3",
|
||||||
|
manager: manager,
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeConfig, exists := manager.clusterConfig.NodeConfigs[nodeGroup.id]
|
||||||
|
require.True(t, exists)
|
||||||
|
assert.Nil(t, nodeConfig.ImagesForArch)
|
||||||
|
assert.Equal(t, "global-arm64-image", manager.clusterConfig.ImagesForArch.Arm64)
|
||||||
|
assert.Equal(t, "global-amd64-image", manager.clusterConfig.ImagesForArch.Amd64)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImageSelectionLogic(t *testing.T) {
|
||||||
|
// Test the image selection logic that would be used in findImage function
|
||||||
|
t.Run("image selection logic", func(t *testing.T) {
|
||||||
|
manager := &hetznerManager{
|
||||||
|
clusterConfig: &ClusterConfig{
|
||||||
|
IsUsingNewFormat: true,
|
||||||
|
ImagesForArch: ImageList{
|
||||||
|
Arm64: "global-arm64-image",
|
||||||
|
Amd64: "global-amd64-image",
|
||||||
|
},
|
||||||
|
NodeConfigs: map[string]*NodeConfig{
|
||||||
|
"pool1": {
|
||||||
|
ImagesForArch: &ImageList{
|
||||||
|
Arm64: "pool1-arm64-image",
|
||||||
|
Amd64: "pool1-amd64-image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"pool2": {
|
||||||
|
// No ImagesForArch specified
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test pool1 (has specific imagesForArch)
|
||||||
|
nodeConfig, exists := manager.clusterConfig.NodeConfigs["pool1"]
|
||||||
|
require.True(t, exists)
|
||||||
|
require.NotNil(t, nodeConfig.ImagesForArch)
|
||||||
|
|
||||||
|
var imagesForArch *ImageList
|
||||||
|
if nodeConfig.ImagesForArch != nil {
|
||||||
|
imagesForArch = nodeConfig.ImagesForArch
|
||||||
|
} else {
|
||||||
|
imagesForArch = &manager.clusterConfig.ImagesForArch
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, "pool1-arm64-image", imagesForArch.Arm64)
|
||||||
|
assert.Equal(t, "pool1-amd64-image", imagesForArch.Amd64)
|
||||||
|
|
||||||
|
// Test pool2 (no specific imagesForArch, should use global)
|
||||||
|
nodeConfig, exists = manager.clusterConfig.NodeConfigs["pool2"]
|
||||||
|
require.True(t, exists)
|
||||||
|
assert.Nil(t, nodeConfig.ImagesForArch)
|
||||||
|
|
||||||
|
if nodeConfig.ImagesForArch != nil {
|
||||||
|
imagesForArch = nodeConfig.ImagesForArch
|
||||||
|
} else {
|
||||||
|
imagesForArch = &manager.clusterConfig.ImagesForArch
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, "global-arm64-image", imagesForArch.Arm64)
|
||||||
|
assert.Equal(t, "global-amd64-image", imagesForArch.Amd64)
|
||||||
|
})
|
||||||
|
}
|
|
@ -461,12 +461,6 @@ func (m *ociManagerImpl) GetExistingNodePoolSizeViaCompute(np NodePool) (int, er
|
||||||
if !strings.HasPrefix(*item.DisplayName, displayNamePrefix) {
|
if !strings.HasPrefix(*item.DisplayName, displayNamePrefix) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// A node pool can fail to scale up if there's no capacity in the region. In that case, the node pool will be
|
|
||||||
// returned by the API, but it will not actually exist or have an ID, so we don't want to tell the autoscaler about it.
|
|
||||||
if *item.Id == "" {
|
|
||||||
klog.V(4).Infof("skipping node as it doesn't have a scaled-up instance")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch item.LifecycleState {
|
switch item.LifecycleState {
|
||||||
case core.InstanceLifecycleStateStopped, core.InstanceLifecycleStateTerminated:
|
case core.InstanceLifecycleStateStopped, core.InstanceLifecycleStateTerminated:
|
||||||
klog.V(4).Infof("skipping instance is in stopped/terminated state: %q", *item.Id)
|
klog.V(4).Infof("skipping instance is in stopped/terminated state: %q", *item.Id)
|
||||||
|
@ -525,25 +519,23 @@ func (m *ociManagerImpl) GetNodePoolNodes(np NodePool) ([]cloudprovider.Instance
|
||||||
|
|
||||||
nodePool, err := m.nodePoolCache.get(np.Id())
|
nodePool, err := m.nodePoolCache.get(np.Id())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
klog.Error(err, "error while performing GetNodePoolNodes call")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var instances []cloudprovider.Instance
|
var instances []cloudprovider.Instance
|
||||||
for _, node := range nodePool.Nodes {
|
for _, node := range nodePool.Nodes {
|
||||||
|
|
||||||
// A node pool can fail to scale up if there's no capacity in the region. In that case, the node pool will be
|
|
||||||
// returned by the API, but it will not actually exist or have an ID, so we don't want to tell the autoscaler about it.
|
|
||||||
if *node.Id == "" {
|
|
||||||
klog.V(4).Infof("skipping node as it doesn't have a scaled-up instance")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.NodeError != nil {
|
if node.NodeError != nil {
|
||||||
|
|
||||||
|
// We should move away from the approach of determining a node error as a Out of host capacity
|
||||||
|
// through string comparison. An error code specifically for Out of host capacity must be set
|
||||||
|
// and returned in the API response.
|
||||||
errorClass := cloudprovider.OtherErrorClass
|
errorClass := cloudprovider.OtherErrorClass
|
||||||
if *node.NodeError.Code == "LimitExceeded" ||
|
if *node.NodeError.Code == "LimitExceeded" ||
|
||||||
(*node.NodeError.Code == "InternalServerError" &&
|
*node.NodeError.Code == "QuotaExceeded" ||
|
||||||
strings.Contains(*node.NodeError.Message, "quota")) {
|
(*node.NodeError.Code == "InternalError" &&
|
||||||
|
strings.Contains(*node.NodeError.Message, "Out of host capacity")) {
|
||||||
errorClass = cloudprovider.OutOfResourcesErrorClass
|
errorClass = cloudprovider.OutOfResourcesErrorClass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,11 @@ package nodepools
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/oci/nodepools/consts"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/oci/nodepools/consts"
|
|
||||||
|
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
|
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/oci/vendor-internal/github.com/oracle/oci-go-sdk/v65/common"
|
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/oci/vendor-internal/github.com/oracle/oci-go-sdk/v65/common"
|
||||||
|
@ -120,16 +119,10 @@ func TestGetNodePoolNodes(t *testing.T) {
|
||||||
{
|
{
|
||||||
Id: common.String("node8"),
|
Id: common.String("node8"),
|
||||||
NodeError: &oke.NodeError{
|
NodeError: &oke.NodeError{
|
||||||
Code: common.String("InternalServerError"),
|
Code: common.String("InternalError"),
|
||||||
Message: common.String("blah blah quota exceeded blah blah"),
|
Message: common.String("blah blah Out of host capacity blah blah"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
// This case happens if a node fails to scale up due to lack of capacity in the region.
|
|
||||||
// It's not a real node, so we shouldn't return it in the list of nodes.
|
|
||||||
Id: common.String(""),
|
|
||||||
LifecycleState: oke.NodeLifecycleStateCreating,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,8 +179,8 @@ func TestGetNodePoolNodes(t *testing.T) {
|
||||||
State: cloudprovider.InstanceCreating,
|
State: cloudprovider.InstanceCreating,
|
||||||
ErrorInfo: &cloudprovider.InstanceErrorInfo{
|
ErrorInfo: &cloudprovider.InstanceErrorInfo{
|
||||||
ErrorClass: cloudprovider.OutOfResourcesErrorClass,
|
ErrorClass: cloudprovider.OutOfResourcesErrorClass,
|
||||||
ErrorCode: "InternalServerError",
|
ErrorCode: "InternalError",
|
||||||
ErrorMessage: "blah blah quota exceeded blah blah",
|
ErrorMessage: "blah blah Out of host capacity blah blah",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -214,6 +214,27 @@ func (np *nodePool) DecreaseTargetSize(delta int) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
klog.V(4).Infof("DECREASE_TARGET_CHECK_VIA_COMPUTE: %v", decreaseTargetCheckViaComputeBool)
|
klog.V(4).Infof("DECREASE_TARGET_CHECK_VIA_COMPUTE: %v", decreaseTargetCheckViaComputeBool)
|
||||||
|
np.manager.InvalidateAndRefreshCache()
|
||||||
|
nodes, err := np.manager.GetNodePoolNodes(np)
|
||||||
|
if err != nil {
|
||||||
|
klog.V(4).Error(err, "error while performing GetNodePoolNodes call")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// We do not have an OCI API that allows us to delete a node with a compute instance. So we rely on
|
||||||
|
// the below approach to determine the number running instance in a nodepool from the compute API and
|
||||||
|
//update the size of the nodepool accordingly. We should move away from this approach once we have an API
|
||||||
|
// to delete a specific node without a compute instance.
|
||||||
|
if !decreaseTargetCheckViaComputeBool {
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node.Status != nil && node.Status.ErrorInfo != nil {
|
||||||
|
if node.Status.ErrorInfo.ErrorClass == cloudprovider.OutOfResourcesErrorClass {
|
||||||
|
klog.Infof("Using Compute to calculate nodepool size as nodepool may contain nodes without a compute instance.")
|
||||||
|
decreaseTargetCheckViaComputeBool = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
var nodesLen int
|
var nodesLen int
|
||||||
if decreaseTargetCheckViaComputeBool {
|
if decreaseTargetCheckViaComputeBool {
|
||||||
nodesLen, err = np.manager.GetExistingNodePoolSizeViaCompute(np)
|
nodesLen, err = np.manager.GetExistingNodePoolSizeViaCompute(np)
|
||||||
|
@ -222,12 +243,6 @@ func (np *nodePool) DecreaseTargetSize(delta int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
np.manager.InvalidateAndRefreshCache()
|
|
||||||
nodes, err := np.manager.GetNodePoolNodes(np)
|
|
||||||
if err != nil {
|
|
||||||
klog.V(4).Error(err, "error while performing GetNodePoolNodes call")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
nodesLen = len(nodes)
|
nodesLen = len(nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
kube_errors "k8s.io/apimachinery/pkg/api/errors"
|
kube_errors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/metrics"
|
"k8s.io/autoscaler/cluster-autoscaler/metrics"
|
||||||
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/fake"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/simulator/framework"
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/framework"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
kubelet_config "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
kubelet_config "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
||||||
|
@ -276,6 +277,8 @@ func podsToEvict(nodeInfo *framework.NodeInfo, evictDsByDefault bool) (dsPods, n
|
||||||
for _, podInfo := range nodeInfo.Pods() {
|
for _, podInfo := range nodeInfo.Pods() {
|
||||||
if pod_util.IsMirrorPod(podInfo.Pod) {
|
if pod_util.IsMirrorPod(podInfo.Pod) {
|
||||||
continue
|
continue
|
||||||
|
} else if fake.IsFake(podInfo.Pod) {
|
||||||
|
continue
|
||||||
} else if pod_util.IsDaemonSetPod(podInfo.Pod) {
|
} else if pod_util.IsDaemonSetPod(podInfo.Pod) {
|
||||||
dsPods = append(dsPods, podInfo.Pod)
|
dsPods = append(dsPods, podInfo.Pod)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -40,6 +40,7 @@ import (
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/core/utils"
|
"k8s.io/autoscaler/cluster-autoscaler/core/utils"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/simulator/clustersnapshot"
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/clustersnapshot"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/simulator/clustersnapshot/testsnapshot"
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/clustersnapshot/testsnapshot"
|
||||||
|
simulator_fake "k8s.io/autoscaler/cluster-autoscaler/simulator/fake"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/simulator/framework"
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/framework"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/utils/daemonset"
|
"k8s.io/autoscaler/cluster-autoscaler/utils/daemonset"
|
||||||
kube_util "k8s.io/autoscaler/cluster-autoscaler/utils/kubernetes"
|
kube_util "k8s.io/autoscaler/cluster-autoscaler/utils/kubernetes"
|
||||||
|
@ -683,6 +684,11 @@ func TestPodsToEvict(t *testing.T) {
|
||||||
wantDsPods: []*apiv1.Pod{},
|
wantDsPods: []*apiv1.Pod{},
|
||||||
wantNonDsPods: []*apiv1.Pod{},
|
wantNonDsPods: []*apiv1.Pod{},
|
||||||
},
|
},
|
||||||
|
"fake pods are never returned": {
|
||||||
|
pods: []*apiv1.Pod{fakePod("pod-1"), fakePod("pod-2")},
|
||||||
|
wantDsPods: []*apiv1.Pod{},
|
||||||
|
wantNonDsPods: []*apiv1.Pod{},
|
||||||
|
},
|
||||||
"non-DS pods are correctly returned": {
|
"non-DS pods are correctly returned": {
|
||||||
pods: []*apiv1.Pod{regularPod("pod-1"), regularPod("pod-2")},
|
pods: []*apiv1.Pod{regularPod("pod-1"), regularPod("pod-2")},
|
||||||
wantDsPods: []*apiv1.Pod{},
|
wantDsPods: []*apiv1.Pod{},
|
||||||
|
@ -766,6 +772,10 @@ func mirrorPod(name string) *apiv1.Pod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fakePod(name string) *apiv1.Pod {
|
||||||
|
return simulator_fake.WithFakePodAnnotation(regularPod(name))
|
||||||
|
}
|
||||||
|
|
||||||
func dsPod(name string, evictable bool) *apiv1.Pod {
|
func dsPod(name string, evictable bool) *apiv1.Pod {
|
||||||
pod := &apiv1.Pod{
|
pod := &apiv1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
|
|
@ -714,15 +714,7 @@ func (o *ScaleUpOrchestrator) balanceScaleUps(
|
||||||
schedulablePodGroups map[string][]estimator.PodEquivalenceGroup,
|
schedulablePodGroups map[string][]estimator.PodEquivalenceGroup,
|
||||||
) ([]nodegroupset.ScaleUpInfo, errors.AutoscalerError) {
|
) ([]nodegroupset.ScaleUpInfo, errors.AutoscalerError) {
|
||||||
// Recompute similar node groups in case they need to be updated
|
// Recompute similar node groups in case they need to be updated
|
||||||
nodeGroups := o.ComputeSimilarNodeGroups(nodeGroup, nodeInfos, schedulablePodGroups, now)
|
similarNodeGroups := o.ComputeSimilarNodeGroups(nodeGroup, nodeInfos, schedulablePodGroups, now)
|
||||||
|
|
||||||
// Similar node groups may return injected node groups as they are used for simulations
|
|
||||||
var similarNodeGroups []cloudprovider.NodeGroup
|
|
||||||
for _, ng := range nodeGroups {
|
|
||||||
if ng.Exist() || o.scaleUpExecutor.asyncNodeGroupStateChecker.IsUpcoming(ng) {
|
|
||||||
similarNodeGroups = append(similarNodeGroups, ng)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if similarNodeGroups != nil {
|
if similarNodeGroups != nil {
|
||||||
// if similar node groups are found, log about them
|
// if similar node groups are found, log about them
|
||||||
|
|
|
@ -64,7 +64,5 @@ func FilterOutExpendablePods(pods []*apiv1.Pod, expendablePodsPriorityCutoff int
|
||||||
|
|
||||||
// IsExpendablePod tests if pod is expendable for give priority cutoff
|
// IsExpendablePod tests if pod is expendable for give priority cutoff
|
||||||
func IsExpendablePod(pod *apiv1.Pod, expendablePodsPriorityCutoff int) bool {
|
func IsExpendablePod(pod *apiv1.Pod, expendablePodsPriorityCutoff int) bool {
|
||||||
preemptLowerPriority := pod.Spec.PreemptionPolicy == nil || *pod.Spec.PreemptionPolicy == apiv1.PreemptLowerPriority
|
return pod.Spec.Priority != nil && int(*pod.Spec.Priority) < expendablePodsPriorityCutoff
|
||||||
lowPriority := pod.Spec.Priority != nil && int(*pod.Spec.Priority) < expendablePodsPriorityCutoff
|
|
||||||
return preemptLowerPriority && lowPriority
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ func TestFilterOutExpendablePods(t *testing.T) {
|
||||||
assert.Equal(t, podWaitingForPreemption2, res[2])
|
assert.Equal(t, podWaitingForPreemption2, res[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsExpandablePod(t *testing.T) {
|
func TestIsExpendablePod(t *testing.T) {
|
||||||
preemptLowerPriorityPolicy := apiv1.PreemptLowerPriority
|
preemptLowerPriorityPolicy := apiv1.PreemptLowerPriority
|
||||||
neverPolicy := apiv1.PreemptNever
|
neverPolicy := apiv1.PreemptNever
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ func TestIsExpandablePod(t *testing.T) {
|
||||||
name: "pod priority set, never preemption policy, higher cutoff",
|
name: "pod priority set, never preemption policy, higher cutoff",
|
||||||
pod: withPodPriority(BuildTestPod("p", 0, 0), -1, &neverPolicy),
|
pod: withPodPriority(BuildTestPod("p", 0, 0), -1, &neverPolicy),
|
||||||
cutoff: 0,
|
cutoff: 0,
|
||||||
want: false,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pod priority set, never preemption policy, equal cutoff",
|
name: "pod priority set, never preemption policy, equal cutoff",
|
||||||
|
|
|
@ -16,12 +16,12 @@ There are a wide variety of use cases here. Some examples are as follows:
|
||||||
## Configuration options
|
## Configuration options
|
||||||
As using this expander requires communication with another service, users must specify a few options as CLI arguments.
|
As using this expander requires communication with another service, users must specify a few options as CLI arguments.
|
||||||
|
|
||||||
```yaml
|
```bash
|
||||||
--grpcExpanderUrl
|
--grpc-expander-url
|
||||||
```
|
```
|
||||||
URL of the gRPC Expander server, for CA to communicate with.
|
URL of the gRPC Expander server, for CA to communicate with.
|
||||||
```yaml
|
```bash
|
||||||
--grpcExpanderCert
|
--grpc-expander-cert
|
||||||
```
|
```
|
||||||
Location of the volume mounted certificate of the gRPC server if it is configured to communicate over TLS
|
Location of the volume mounted certificate of the gRPC server if it is configured to communicate over TLS
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ service. Note that the `protos/expander.pb.go` generated protobuf code will also
|
||||||
Communication between Cluster Autoscaler and the gRPC Server will occur over native kube-proxy. To use this, note the Service and Namespace the gRPC server is deployed in.
|
Communication between Cluster Autoscaler and the gRPC Server will occur over native kube-proxy. To use this, note the Service and Namespace the gRPC server is deployed in.
|
||||||
|
|
||||||
Deploy the gRPC Expander Server as a separate app, listening on a specifc port number.
|
Deploy the gRPC Expander Server as a separate app, listening on a specifc port number.
|
||||||
Start Cluster Autoscaler with the `--grpcExapnderURl=SERVICE_NAME.NAMESPACE_NAME.svc.cluster.local:PORT_NUMBER` flag, as well as `--grpcExpanderCert` pointed at the location of the volume mounted certificate of the gRPC server.
|
Start Cluster Autoscaler with the `--grpc-expander-url=SERVICE_NAME.NAMESPACE_NAME.svc.cluster.local:PORT_NUMBER` flag, as well as `--grpc-expander-cert` pointed at the location of the volume mounted certificate of the gRPC server.
|
||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/context"
|
"k8s.io/autoscaler/cluster-autoscaler/context"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/metrics"
|
"k8s.io/autoscaler/cluster-autoscaler/metrics"
|
||||||
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/fake"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -50,7 +51,7 @@ func (p *EnforceInjectedPodsLimitProcessor) Process(ctx *context.AutoscalingCont
|
||||||
var unschedulablePodsAfterProcessing []*apiv1.Pod
|
var unschedulablePodsAfterProcessing []*apiv1.Pod
|
||||||
|
|
||||||
for _, pod := range unschedulablePods {
|
for _, pod := range unschedulablePods {
|
||||||
if IsFake(pod) {
|
if fake.IsFake(pod) {
|
||||||
if removedFakePodsCount < numberOfFakePodsToRemove {
|
if removedFakePodsCount < numberOfFakePodsToRemove {
|
||||||
removedFakePodsCount += 1
|
removedFakePodsCount += 1
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/fake"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEnforceInjectedPodsLimitProcessor(t *testing.T) {
|
func TestEnforceInjectedPodsLimitProcessor(t *testing.T) {
|
||||||
|
@ -110,7 +111,7 @@ func TestEnforceInjectedPodsLimitProcessor(t *testing.T) {
|
||||||
func numberOfFakePods(pods []*apiv1.Pod) int {
|
func numberOfFakePods(pods []*apiv1.Pod) int {
|
||||||
numberOfFakePods := 0
|
numberOfFakePods := 0
|
||||||
for _, pod := range pods {
|
for _, pod := range pods {
|
||||||
if IsFake(pod) {
|
if fake.IsFake(pod) {
|
||||||
numberOfFakePods += 1
|
numberOfFakePods += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,17 +24,11 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/context"
|
"k8s.io/autoscaler/cluster-autoscaler/context"
|
||||||
podinjectionbackoff "k8s.io/autoscaler/cluster-autoscaler/processors/podinjection/backoff"
|
podinjectionbackoff "k8s.io/autoscaler/cluster-autoscaler/processors/podinjection/backoff"
|
||||||
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/fake"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/simulator/framework"
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/framework"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// FakePodAnnotationKey the key for pod type
|
|
||||||
FakePodAnnotationKey = "podtype"
|
|
||||||
// FakePodAnnotationValue the value for a fake pod
|
|
||||||
FakePodAnnotationValue = "fakepod"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PodInjectionPodListProcessor is a PodListProcessor used to inject fake pods to consider replica count in the respective controllers for the scale-up.
|
// PodInjectionPodListProcessor is a PodListProcessor used to inject fake pods to consider replica count in the respective controllers for the scale-up.
|
||||||
// For each controller, #fake pods injected = #replicas specified the controller - #scheduled pods - #finished pods - #unschedulable pods
|
// For each controller, #fake pods injected = #replicas specified the controller - #scheduled pods - #finished pods - #unschedulable pods
|
||||||
type PodInjectionPodListProcessor struct {
|
type PodInjectionPodListProcessor struct {
|
||||||
|
@ -90,7 +84,7 @@ func (p *PodInjectionPodListProcessor) CleanUp() {
|
||||||
func makeFakePods(ownerUid types.UID, samplePod *apiv1.Pod, podCount int) []*apiv1.Pod {
|
func makeFakePods(ownerUid types.UID, samplePod *apiv1.Pod, podCount int) []*apiv1.Pod {
|
||||||
var fakePods []*apiv1.Pod
|
var fakePods []*apiv1.Pod
|
||||||
for i := 1; i <= podCount; i++ {
|
for i := 1; i <= podCount; i++ {
|
||||||
newPod := withFakePodAnnotation(samplePod.DeepCopy())
|
newPod := fake.WithFakePodAnnotation(samplePod.DeepCopy())
|
||||||
newPod.Name = fmt.Sprintf("%s-copy-%d", samplePod.Name, i)
|
newPod.Name = fmt.Sprintf("%s-copy-%d", samplePod.Name, i)
|
||||||
newPod.UID = types.UID(fmt.Sprintf("%s-%d", string(ownerUid), i))
|
newPod.UID = types.UID(fmt.Sprintf("%s-%d", string(ownerUid), i))
|
||||||
newPod.Spec.NodeName = ""
|
newPod.Spec.NodeName = ""
|
||||||
|
@ -99,16 +93,6 @@ func makeFakePods(ownerUid types.UID, samplePod *apiv1.Pod, podCount int) []*api
|
||||||
return fakePods
|
return fakePods
|
||||||
}
|
}
|
||||||
|
|
||||||
// withFakePodAnnotation adds annotation of key `FakePodAnnotationKey` with value `FakePodAnnotationValue` to passed pod.
|
|
||||||
// withFakePodAnnotation also creates a new annotations map if original pod.Annotations is nil
|
|
||||||
func withFakePodAnnotation(pod *apiv1.Pod) *apiv1.Pod {
|
|
||||||
if pod.Annotations == nil {
|
|
||||||
pod.Annotations = make(map[string]string, 1)
|
|
||||||
}
|
|
||||||
pod.Annotations[FakePodAnnotationKey] = FakePodAnnotationValue
|
|
||||||
return pod
|
|
||||||
}
|
|
||||||
|
|
||||||
// fakePodCount calculate the fake pod count that should be injected from this podGroup
|
// fakePodCount calculate the fake pod count that should be injected from this podGroup
|
||||||
func (p *podGroup) fakePodCount() int {
|
func (p *podGroup) fakePodCount() int {
|
||||||
// Controllers with no unschedulable pods are ignored
|
// Controllers with no unschedulable pods are ignored
|
||||||
|
@ -142,14 +126,6 @@ func listControllers(ctx *context.AutoscalingContext) []controller {
|
||||||
return controllers
|
return controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsFake returns true if the a pod is marked as fake and false otherwise
|
|
||||||
func IsFake(pod *apiv1.Pod) bool {
|
|
||||||
if pod.Annotations == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return pod.Annotations[FakePodAnnotationKey] == FakePodAnnotationValue
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PodInjectionPodListProcessor) skipBackedoffControllers(controllers []controller) []controller {
|
func (p *PodInjectionPodListProcessor) skipBackedoffControllers(controllers []controller) []controller {
|
||||||
var filteredControllers []controller
|
var filteredControllers []controller
|
||||||
backoffRegistry := p.fakePodControllerBackoffRegistry
|
backoffRegistry := p.fakePodControllerBackoffRegistry
|
||||||
|
|
|
@ -32,6 +32,7 @@ import (
|
||||||
podinjectionbackoff "k8s.io/autoscaler/cluster-autoscaler/processors/podinjection/backoff"
|
podinjectionbackoff "k8s.io/autoscaler/cluster-autoscaler/processors/podinjection/backoff"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/simulator/clustersnapshot/store"
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/clustersnapshot/store"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/simulator/clustersnapshot/testsnapshot"
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/clustersnapshot/testsnapshot"
|
||||||
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/fake"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/simulator/framework"
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/framework"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/utils/kubernetes"
|
"k8s.io/autoscaler/cluster-autoscaler/utils/kubernetes"
|
||||||
. "k8s.io/autoscaler/cluster-autoscaler/utils/test"
|
. "k8s.io/autoscaler/cluster-autoscaler/utils/test"
|
||||||
|
@ -382,8 +383,7 @@ func TestMakeFakePods(t *testing.T) {
|
||||||
assert.Equal(t, fakePod.Name, fmt.Sprintf("%s-copy-%d", samplePod.Name, idx+1))
|
assert.Equal(t, fakePod.Name, fmt.Sprintf("%s-copy-%d", samplePod.Name, idx+1))
|
||||||
assert.Equal(t, fakePod.UID, types.UID(fmt.Sprintf("%s-%d", string(ownerUid), idx+1)))
|
assert.Equal(t, fakePod.UID, types.UID(fmt.Sprintf("%s-%d", string(ownerUid), idx+1)))
|
||||||
assert.Equal(t, "", fakePod.Spec.NodeName)
|
assert.Equal(t, "", fakePod.Spec.NodeName)
|
||||||
assert.NotNil(t, fakePod.Annotations)
|
assert.True(t, fake.IsFake(fakePod))
|
||||||
assert.Equal(t, fakePod.Annotations[FakePodAnnotationKey], FakePodAnnotationValue)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test case: Zero fake pod count
|
// Test case: Zero fake pod count
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
ca_context "k8s.io/autoscaler/cluster-autoscaler/context"
|
ca_context "k8s.io/autoscaler/cluster-autoscaler/context"
|
||||||
podinjectionbackoff "k8s.io/autoscaler/cluster-autoscaler/processors/podinjection/backoff"
|
podinjectionbackoff "k8s.io/autoscaler/cluster-autoscaler/processors/podinjection/backoff"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/processors/status"
|
"k8s.io/autoscaler/cluster-autoscaler/processors/status"
|
||||||
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/fake"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ func filterFakePods[T any](podsWrappers []T, getPod func(T) *apiv1.Pod, resource
|
||||||
|
|
||||||
for _, podsWrapper := range podsWrappers {
|
for _, podsWrapper := range podsWrappers {
|
||||||
currentPod := getPod(podsWrapper)
|
currentPod := getPod(podsWrapper)
|
||||||
if !IsFake(currentPod) {
|
if !fake.IsFake(currentPod) {
|
||||||
filteredPodsSouces = append(filteredPodsSouces, podsWrapper)
|
filteredPodsSouces = append(filteredPodsSouces, podsWrapper)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -86,7 +87,7 @@ func filterFakePods[T any](podsWrappers []T, getPod func(T) *apiv1.Pod, resource
|
||||||
func extractFakePodsControllersUIDs(NoScaleUpInfos []status.NoScaleUpInfo) map[types.UID]bool {
|
func extractFakePodsControllersUIDs(NoScaleUpInfos []status.NoScaleUpInfo) map[types.UID]bool {
|
||||||
uids := make(map[types.UID]bool)
|
uids := make(map[types.UID]bool)
|
||||||
for _, NoScaleUpInfo := range NoScaleUpInfos {
|
for _, NoScaleUpInfo := range NoScaleUpInfos {
|
||||||
if IsFake(NoScaleUpInfo.Pod) {
|
if fake.IsFake(NoScaleUpInfo.Pod) {
|
||||||
uids[NoScaleUpInfo.Pod.UID] = true
|
uids[NoScaleUpInfo.Pod.UID] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/context"
|
"k8s.io/autoscaler/cluster-autoscaler/context"
|
||||||
podinjectionbackoff "k8s.io/autoscaler/cluster-autoscaler/processors/podinjection/backoff"
|
podinjectionbackoff "k8s.io/autoscaler/cluster-autoscaler/processors/podinjection/backoff"
|
||||||
"k8s.io/autoscaler/cluster-autoscaler/processors/status"
|
"k8s.io/autoscaler/cluster-autoscaler/processors/status"
|
||||||
|
"k8s.io/autoscaler/cluster-autoscaler/simulator/fake"
|
||||||
. "k8s.io/autoscaler/cluster-autoscaler/utils/test"
|
. "k8s.io/autoscaler/cluster-autoscaler/utils/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -82,7 +83,7 @@ func createPod(name string, isFake bool) *apiv1.Pod {
|
||||||
if !isFake {
|
if !isFake {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
*p = *withFakePodAnnotation(p)
|
*p = *fake.WithFakePodAnnotation(p)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fake
|
||||||
|
|
||||||
|
import (
|
||||||
|
apiv1 "k8s.io/api/core/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// FakePodAnnotationKey the key for pod type.
|
||||||
|
FakePodAnnotationKey = "podtype"
|
||||||
|
// FakePodAnnotationValue the value for a fake pod,
|
||||||
|
FakePodAnnotationValue = "fakepod"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsFake returns true if the a pod is marked as fake and false otherwise,
|
||||||
|
func IsFake(pod *apiv1.Pod) bool {
|
||||||
|
if pod.Annotations == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return pod.Annotations[FakePodAnnotationKey] == FakePodAnnotationValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFakePodAnnotation adds annotation of key `FakePodAnnotationKey` with value `FakePodAnnotationValue` to passed pod.
|
||||||
|
// WithFakePodAnnotation also creates a new annotations map if original pod.Annotations is nil.
|
||||||
|
func WithFakePodAnnotation(pod *apiv1.Pod) *apiv1.Pod {
|
||||||
|
if pod.Annotations == nil {
|
||||||
|
pod.Annotations = make(map[string]string, 1)
|
||||||
|
}
|
||||||
|
pod.Annotations[FakePodAnnotationKey] = FakePodAnnotationValue
|
||||||
|
return pod
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package fake
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
apiv1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/autoscaler/cluster-autoscaler/utils/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsFake(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
pod *apiv1.Pod
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "real pod",
|
||||||
|
pod: test.BuildTestPod("real", 10, 10),
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "fake pod",
|
||||||
|
pod: WithFakePodAnnotation(test.BuildTestPod("fake", 10, 10)),
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
got := IsFake(tc.pod)
|
||||||
|
assert.Equal(t, tc.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithFakePodAnnotation(t *testing.T) {
|
||||||
|
pod := test.BuildTestPod("pod", 10, 10)
|
||||||
|
assert.Equal(t, map[string]string{}, pod.Annotations)
|
||||||
|
pod = WithFakePodAnnotation(pod)
|
||||||
|
assert.NotNil(t, pod.Annotations)
|
||||||
|
assert.Equal(t, FakePodAnnotationValue, pod.Annotations[FakePodAnnotationKey])
|
||||||
|
}
|
|
@ -43,6 +43,21 @@ spec:
|
||||||
- containerPort: 8000
|
- containerPort: 8000
|
||||||
- name: prometheus
|
- name: prometheus
|
||||||
containerPort: 8944
|
containerPort: 8944
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health-check
|
||||||
|
port: prometheus
|
||||||
|
scheme: HTTP
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health-check
|
||||||
|
port: prometheus
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
volumes:
|
volumes:
|
||||||
- name: tls-certs
|
- name: tls-certs
|
||||||
secret:
|
secret:
|
||||||
|
|
|
@ -41,3 +41,18 @@ spec:
|
||||||
ports:
|
ports:
|
||||||
- name: prometheus
|
- name: prometheus
|
||||||
containerPort: 8942
|
containerPort: 8942
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health-check
|
||||||
|
port: prometheus
|
||||||
|
scheme: HTTP
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health-check
|
||||||
|
port: prometheus
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
|
|
@ -41,3 +41,18 @@ spec:
|
||||||
ports:
|
ports:
|
||||||
- name: prometheus
|
- name: prometheus
|
||||||
containerPort: 8942
|
containerPort: 8942
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health-check
|
||||||
|
port: prometheus
|
||||||
|
scheme: HTTP
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health-check
|
||||||
|
port: prometheus
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
|
|
@ -32,3 +32,18 @@ spec:
|
||||||
ports:
|
ports:
|
||||||
- name: prometheus
|
- name: prometheus
|
||||||
containerPort: 8942
|
containerPort: 8942
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health-check
|
||||||
|
port: prometheus
|
||||||
|
scheme: HTTP
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health-check
|
||||||
|
port: prometheus
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
|
|
@ -37,3 +37,18 @@ spec:
|
||||||
ports:
|
ports:
|
||||||
- name: prometheus
|
- name: prometheus
|
||||||
containerPort: 8943
|
containerPort: 8943
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health-check
|
||||||
|
port: prometheus
|
||||||
|
scheme: HTTP
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health-check
|
||||||
|
port: prometheus
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
|
|
@ -110,9 +110,9 @@ It is possible to set the failurePolicy of the webhook to `Fail` by passing `--w
|
||||||
Please use this option with caution as it may be possible to break Pod creation if there is a failure with the VPA.
|
Please use this option with caution as it may be possible to break Pod creation if there is a failure with the VPA.
|
||||||
Using it in conjunction with `--ignored-vpa-object-namespaces=kube-system` or `--vpa-object-namespace` to reduce risk.
|
Using it in conjunction with `--ignored-vpa-object-namespaces=kube-system` or `--vpa-object-namespace` to reduce risk.
|
||||||
|
|
||||||
### Specifying global maximum allowed resources to prevent pods from being unschedulable
|
## Specifying global maximum allowed resources to prevent pods from being unschedulable
|
||||||
|
|
||||||
The [Known limitations dcoument](./known-limitations.md) outlines that VPA (vpa-recommender in particular) is not aware of the cluster's maximum allocatable and can recommend resources which will not fit even the largest node in the cluster. This issue occurs even when the cluster uses the [Cluster Autoscaler](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#basics). The vpa-recommender's resource recommendation can exceed the allocatable of the largest node in the cluster. Hence, pod's will be unschedulable (in `Pending` state) and the pod wouldn't fit the cluster even if a new node is added by the Cluster Autoscaler.
|
The [Known limitations document](./known-limitations.md) outlines that VPA (vpa-recommender in particular) is not aware of the cluster's maximum allocatable and can recommend resources which will not fit even the largest node in the cluster. This issue occurs even when the cluster uses the [Cluster Autoscaler](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#basics). The vpa-recommender's resource recommendation can exceed the allocatable of the largest node in the cluster. Hence, pod's will be unschedulable (in `Pending` state) and the pod wouldn't fit the cluster even if a new node is added by the Cluster Autoscaler.
|
||||||
It is possible to mitigate this issue by specifying the `--container-recommendation-max-allowed-cpu` and `--container-recommendation-max-allowed-memory` flags of the vpa-recommender. These flags represent the global maximum amount of cpu/memory that will be recommended **for a container**. If the VerticalPodAutoscaler already defines a max allowed (`.spec.resourcePolicy.containerPolicies.maxAllowed`) then it takes precedence over the global max allowed. The global max allowed is merged to the VerticalPodAutoscaler's max allowed if VerticalPodAutoscaler's max allowed is specified only for cpu or memory. If the VerticalPodAutoscaler does not specify a max allowed and a global max allowed is specified, then the global max allowed is being used.
|
It is possible to mitigate this issue by specifying the `--container-recommendation-max-allowed-cpu` and `--container-recommendation-max-allowed-memory` flags of the vpa-recommender. These flags represent the global maximum amount of cpu/memory that will be recommended **for a container**. If the VerticalPodAutoscaler already defines a max allowed (`.spec.resourcePolicy.containerPolicies.maxAllowed`) then it takes precedence over the global max allowed. The global max allowed is merged to the VerticalPodAutoscaler's max allowed if VerticalPodAutoscaler's max allowed is specified only for cpu or memory. If the VerticalPodAutoscaler does not specify a max allowed and a global max allowed is specified, then the global max allowed is being used.
|
||||||
|
|
||||||
The recommendation for computing the `--container-recommendation-max-allowed-cpu` and `--container-recommendation-max-allowed-memory` values for your cluster is to use the largest node's allocatable (`.status.allocatable` field of a node) minus the DaemonSet pods resource requests minus a safety margin:
|
The recommendation for computing the `--container-recommendation-max-allowed-cpu` and `--container-recommendation-max-allowed-memory` values for your cluster is to use the largest node's allocatable (`.status.allocatable` field of a node) minus the DaemonSet pods resource requests minus a safety margin:
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
- [Limits control](#limits-control)
|
- [Limits control](#limits-control)
|
||||||
- [Memory Value Humanization](#memory-value-humanization)
|
- [Memory Value Humanization](#memory-value-humanization)
|
||||||
- [CPU Recommendation Rounding](#cpu-recommendation-rounding)
|
- [CPU Recommendation Rounding](#cpu-recommendation-rounding)
|
||||||
|
- [Memory Recommendation Rounding](#memory-recommendation-rounding)
|
||||||
- [In-Place Updates](#in-place-updates-inplaceorrecreate)
|
- [In-Place Updates](#in-place-updates-inplaceorrecreate)
|
||||||
|
|
||||||
## Limits control
|
## Limits control
|
||||||
|
@ -54,6 +55,22 @@ To enable this feature, set the --round-cpu-millicores flag when running the VPA
|
||||||
--round-cpu-millicores=50
|
--round-cpu-millicores=50
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Memory Recommendation Rounding
|
||||||
|
|
||||||
|
VPA can provide Memory recommendations rounded up to user-specified values, making it easier to interpret and configure resources. This feature is controlled by the `--round-memory-bytes` flag in the recommender component.
|
||||||
|
|
||||||
|
When enabled, Memory recommendations will be:
|
||||||
|
- Rounded up to the nearest multiple of the specified bytes value
|
||||||
|
- Applied to target, lower bound, and upper bound recommendations
|
||||||
|
|
||||||
|
For example, with `--round-memory-bytes=134217728`, a memory recommendation of `200Mi` would be rounded up to `256Mi`, and a recommendation of `80Mi` would be rounded up to `128Mi`.
|
||||||
|
|
||||||
|
To enable this feature, set the `--round-memory-bytes` flag when running the VPA recommender:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
--round-memory-bytes=134217728
|
||||||
|
```
|
||||||
|
|
||||||
## In-Place Updates (`InPlaceOrRecreate`)
|
## In-Place Updates (`InPlaceOrRecreate`)
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
|
|
|
@ -118,6 +118,7 @@ This document is auto-generated from the flag definitions in the VPA recommender
|
||||||
| `recommender-interval` | | 1m0s | duration How often metrics should be fetched |
|
| `recommender-interval` | | 1m0s | duration How often metrics should be fetched |
|
||||||
| `recommender-name` | string | "default" | Set the recommender name. Recommender will generate recommendations for VPAs that configure the same recommender name. If the recommender name is left as default it will also generate recommendations that don't explicitly specify recommender. You shouldn't run two recommenders with the same name in a cluster. |
|
| `recommender-name` | string | "default" | Set the recommender name. Recommender will generate recommendations for VPAs that configure the same recommender name. If the recommender name is left as default it will also generate recommendations that don't explicitly specify recommender. You shouldn't run two recommenders with the same name in a cluster. |
|
||||||
| `round-cpu-millicores` | int | 1 | CPU recommendation rounding factor in millicores. The CPU value will always be rounded up to the nearest multiple of this factor. |
|
| `round-cpu-millicores` | int | 1 | CPU recommendation rounding factor in millicores. The CPU value will always be rounded up to the nearest multiple of this factor. |
|
||||||
|
| `round-memory-bytes` | int | 1 | Memory recommendation rounding factor in bytes. The Memory value will always be rounded up to the nearest multiple of this factor. |
|
||||||
| `skip-headers` | | | If true, avoid header prefixes in the log messages |
|
| `skip-headers` | | | If true, avoid header prefixes in the log messages |
|
||||||
| `skip-log-headers` | | | If true, avoid headers when opening log files (no effect when -logtostderr=true) |
|
| `skip-log-headers` | | | If true, avoid headers when opening log files (no effect when -logtostderr=true) |
|
||||||
| `stderrthreshold` | severity | : info | set the log level threshold for writing to standard error |
|
| `stderrthreshold` | severity | : info | set the log level threshold for writing to standard error |
|
||||||
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
# AEP-8026: Allow per-VPA component configuration parameters
|
||||||
|
|
||||||
|
<!-- toc -->
|
||||||
|
- [Summary](#summary)
|
||||||
|
- [Motivation](#motivation)
|
||||||
|
- [Goals](#goals)
|
||||||
|
- [Non-Goals](#non-goals)
|
||||||
|
- [Proposal](#proposal)
|
||||||
|
- [Parameter Descriptions](#parameter-descriptions)
|
||||||
|
- [Container Policy Parameters](#container-policy-parameters)
|
||||||
|
- [Update Policy Parameters](#update-policy-parameters)
|
||||||
|
- [Design Details](#design-details)
|
||||||
|
- [API Changes](#api-changes)
|
||||||
|
- [Phase 1 (Current Proposal)](#phase-1-current-proposal)
|
||||||
|
- [Future Extensions](#future-extensions)
|
||||||
|
- [Feature Enablement and Rollback](#feature-enablement-and-rollback)
|
||||||
|
- [How can this feature be enabled / disabled in a live cluster?](#how-can-this-feature-be-enabled--disabled-in-a-live-cluster)
|
||||||
|
- [Kubernetes version compatibility](#kubernetes-version-compatibility)
|
||||||
|
- [Validation via CEL and Testing](#validation-via-cel-and-testing)
|
||||||
|
- [Test Plan](#test-plan)
|
||||||
|
- [Implementation History](#implementation-history)
|
||||||
|
- [Future Work](#future-work)
|
||||||
|
- [Alternatives](#alternatives)
|
||||||
|
- [Multiple VPA Deployments](#multiple-vpa-deployments)
|
||||||
|
- [Environment-Specific Configuration](#environment-specific-configuration)
|
||||||
|
<!-- /toc -->
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Currently, VPA components (recommender, updater, admission controller) are configured through global flags. This makes it challenging to support different workloads with varying resource optimization needs within the same cluster. This proposal introduces the ability to specify configuration parameters at the individual VPA object level, allowing for workload-specific optimization strategies.
|
||||||
|
|
||||||
|
## Motivation
|
||||||
|
|
||||||
|
Different types of workloads in a Kubernetes cluster often have different resource optimization requirements. For example:
|
||||||
|
- Batch processing jobs might benefit from aggressive OOM handling and frequent adjustments
|
||||||
|
- User-facing services might need more conservative growth patterns for stability
|
||||||
|
- Development environments might need different settings than production
|
||||||
|
|
||||||
|
Currently, supporting these different needs requires running multiple VPA component instances with different configurations, which increases operational complexity and resource usage.
|
||||||
|
|
||||||
|
### Goals
|
||||||
|
|
||||||
|
- Allow specification of component-specific parameters in individual VPA objects
|
||||||
|
- Support different optimization strategies for different workloads in the same cluster
|
||||||
|
- Maintain backward compatibility with existing global configuration
|
||||||
|
- Initially support the following parameters:
|
||||||
|
- oomBumpUpRatio
|
||||||
|
- oomMinBumpUp
|
||||||
|
- memoryAggregationInterval
|
||||||
|
- memoryAggregationIntervalCount
|
||||||
|
- evictAfterOOMThreshold
|
||||||
|
|
||||||
|
### Non-Goals
|
||||||
|
|
||||||
|
- Converting all existing VPA flags to per-object configuration
|
||||||
|
- Changing the core VPA algorithm or its decision-making process
|
||||||
|
- Adding new optimization strategies
|
||||||
|
|
||||||
|
## Proposal
|
||||||
|
|
||||||
|
The configuration will be split into two sections: container-specific recommendations under `containerPolicies` and updater configuration under `updatePolicy`. This structure is designed to be extensible, allowing for additional parameters to be added in future iterations of this enhancement.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: autoscaling.k8s.io/v1
|
||||||
|
kind: VerticalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: oom-test-vpa
|
||||||
|
spec:
|
||||||
|
targetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: oom-test
|
||||||
|
updatePolicy:
|
||||||
|
updateMode: Auto
|
||||||
|
evictAfterOOMThreshold: "5m"
|
||||||
|
resourcePolicy:
|
||||||
|
containerPolicies:
|
||||||
|
- containerName: "*"
|
||||||
|
oomBumpUpRatio: "1.5"
|
||||||
|
oomMinBumpUp: 104857600
|
||||||
|
memoryAggregationInterval: "12h"
|
||||||
|
memoryAggregationIntervalCount: 5
|
||||||
|
```
|
||||||
|
|
||||||
|
### Parameter Descriptions
|
||||||
|
|
||||||
|
#### Container Policy Parameters
|
||||||
|
#### Container Policy Parameters
|
||||||
|
* `oomBumpUpRatio` (Quantity):
|
||||||
|
- Multiplier applied to memory recommendations after OOM events
|
||||||
|
- Represented as a Quantity (e.g., "1.5")
|
||||||
|
- Must be greater than 1
|
||||||
|
- Controls how aggressively memory is increased after container crashes
|
||||||
|
|
||||||
|
* `oomMinBumpUp` (bytes):
|
||||||
|
- Minimum absolute memory increase after OOM events
|
||||||
|
- Ensures meaningful increases even for small containers
|
||||||
|
|
||||||
|
* `memoryAggregationInterval` (duration):
|
||||||
|
- Time window for aggregating memory usage data
|
||||||
|
- Affects how quickly VPA responds to memory usage changes
|
||||||
|
|
||||||
|
* `memoryAggregationIntervalCount` (integer):
|
||||||
|
- Number of consecutive memory aggregation intervals
|
||||||
|
- Used to calculate the total memory aggregation window length
|
||||||
|
- Total window length = memoryAggregationInterval * memoryAggregationIntervalCount
|
||||||
|
|
||||||
|
#### Update Policy Parameters
|
||||||
|
* `evictAfterOOMThreshold` (duration):
|
||||||
|
- Time to wait after OOM before considering pod eviction
|
||||||
|
- Helps prevent rapid eviction cycles while maintaining stability
|
||||||
|
|
||||||
|
Each parameter can be configured independently, falling back to global defaults if not specified. Values should be chosen based on workload characteristics and stability requirements.
|
||||||
|
|
||||||
|
## Design Details
|
||||||
|
|
||||||
|
### API Changes
|
||||||
|
|
||||||
|
#### Phase 1 (Current Proposal)
|
||||||
|
|
||||||
|
Extend `ContainerResourcePolicy` with:
|
||||||
|
* `oomBumpUpRatio`
|
||||||
|
* `oomMinBumpUp`
|
||||||
|
* `memoryAggregationInterval`
|
||||||
|
* `memoryAggregationIntervalCount`
|
||||||
|
|
||||||
|
Extend `PodUpdatePolicy` with:
|
||||||
|
* `evictAfterOOMThreshold`
|
||||||
|
|
||||||
|
#### Future Extensions
|
||||||
|
|
||||||
|
This AEP will be updated as additional parameters are identified for per-object configuration. Potential candidates include:
|
||||||
|
* `confidenceIntervalCPU`
|
||||||
|
* `confidenceIntervalMemory`
|
||||||
|
* `recommendationMarginFraction`
|
||||||
|
* Other parameters that benefit from workload-specific tuning
|
||||||
|
|
||||||
|
### Feature Enablement and Rollback
|
||||||
|
|
||||||
|
#### How can this feature be enabled / disabled in a live cluster?
|
||||||
|
|
||||||
|
- Feature gate name: `PerVPAConfig`
|
||||||
|
- Default: Off (Alpha)
|
||||||
|
- Components depending on the feature gate:
|
||||||
|
- admission-controller
|
||||||
|
- recommender
|
||||||
|
- updater
|
||||||
|
|
||||||
|
The feature gate will remain in alpha (default off) until:
|
||||||
|
- All planned configuration parameters have been implemented and tested
|
||||||
|
- Performance impact has been thoroughly evaluated
|
||||||
|
- Documentation is complete for all parameters
|
||||||
|
|
||||||
|
Disabling of feature gate `PerVPAConfig` will cause the following to happen:
|
||||||
|
|
||||||
|
- Any per-VPA configuration parameters specified in VPA objects will be ignored
|
||||||
|
- Components will fall back to using their global configuration values
|
||||||
|
|
||||||
|
Enabling of feature gate `PerVPAConfig` will cause the following to happen:
|
||||||
|
|
||||||
|
- VPA components will honor the per-VPA configuration parameters specified in VPA objects
|
||||||
|
- Validation will be performed on the configuration parameters
|
||||||
|
- Configuration parameters will override global defaults for the specific VPA object
|
||||||
|
|
||||||
|
### Kubernetes version compatibility
|
||||||
|
|
||||||
|
The `PerVPAConfig` feature requires VPA version 1.5.0 or higher. The feature is being introduced as alpha and will follow the standard Kubernetes feature gate graduation process:
|
||||||
|
- Alpha: v1.5.0 (default off)
|
||||||
|
- Beta: TBD (default on)
|
||||||
|
- GA: TBD (default on)
|
||||||
|
|
||||||
|
### Validation via CEL and Testing
|
||||||
|
|
||||||
|
Initial validation rules (CEL):
|
||||||
|
* `oomMinBumpUp` > 0
|
||||||
|
* `memoryAggregationInterval` > 0
|
||||||
|
* `evictAfterOOMThreshold` > 0
|
||||||
|
* `memoryAggregationIntervalCount` > 0
|
||||||
|
|
||||||
|
Validation via Admission Controller:
|
||||||
|
Some components cann't be validated using Common Expression Language (CEL). This validation is performed within the admission controller.
|
||||||
|
|
||||||
|
* `oomBumpUpRatio` – Using Kubernetes Quantity type for validation. The value must be greater than 1.
|
||||||
|
|
||||||
|
Additional validation rules will be added as new parameters are introduced.
|
||||||
|
E2E tests will be included to verify:
|
||||||
|
* Different configurations are properly applied and respected by VPA components
|
||||||
|
* VPA behavior matches expected outcomes for different parameter combinations
|
||||||
|
* Proper fallback to global configuration when parameters are not specified
|
||||||
|
|
||||||
|
### Test Plan
|
||||||
|
|
||||||
|
- Unit tests for new API fields and validation
|
||||||
|
- Integration tests verifying different configurations are properly applied
|
||||||
|
- E2E tests comparing behavior with different configurations
|
||||||
|
- Upgrade tests ensuring backward compatibility
|
||||||
|
|
||||||
|
## Implementation History
|
||||||
|
|
||||||
|
- 2025-04-12: Initial proposal
|
||||||
|
- Future: Additional parameters will be added based on user feedback and requirements
|
||||||
|
|
||||||
|
## Future Work
|
||||||
|
|
||||||
|
This enhancement is designed to be extensible. As the VPA evolves and users provide feedback, additional parameters may be added to the per-object configuration. Each new parameter will:
|
||||||
|
1. Be documented in this AEP
|
||||||
|
2. Include appropriate validation rules
|
||||||
|
3. Maintain backward compatibility
|
||||||
|
4. Follow the same pattern of falling back to global configuration when not specified
|
||||||
|
|
||||||
|
The decision to add new parameters will be based on:
|
||||||
|
- User feedback and requirements
|
||||||
|
- Performance impact analysis
|
||||||
|
- Implementation complexity
|
||||||
|
- Maintenance considerations
|
||||||
|
|
||||||
|
## Alternatives
|
||||||
|
|
||||||
|
### Multiple VPA Deployments
|
||||||
|
|
||||||
|
Continue with current approach of running multiple VPA deployments with different configurations:
|
||||||
|
- Pros: No API changes needed
|
||||||
|
- Cons: Higher resource usage, operational complexity
|
||||||
|
|
||||||
|
### Environment-Specific Configuration
|
||||||
|
|
||||||
|
Use different VPA deployments per environment (dev/staging/prod):
|
||||||
|
- Pros: Simpler than per-workload configuration
|
||||||
|
- Cons: Less flexible, doesn't address varying needs within same environment
|
|
@ -41,6 +41,7 @@ require (
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/mailru/easyjson v0.9.0 // indirect
|
github.com/mailru/easyjson v0.9.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM golang:1.24.4 AS builder
|
FROM --platform=$BUILDPLATFORM golang:1.24.5 AS builder
|
||||||
|
|
||||||
WORKDIR /workspace
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM golang:1.24.4 AS builder
|
FROM --platform=$BUILDPLATFORM golang:1.24.5 AS builder
|
||||||
|
|
||||||
WORKDIR /workspace
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ type ClusterStateFeederFactory struct {
|
||||||
KubeClient kube_client.Interface
|
KubeClient kube_client.Interface
|
||||||
MetricsClient metrics.MetricsClient
|
MetricsClient metrics.MetricsClient
|
||||||
VpaCheckpointClient vpa_api.VerticalPodAutoscalerCheckpointsGetter
|
VpaCheckpointClient vpa_api.VerticalPodAutoscalerCheckpointsGetter
|
||||||
|
VpaCheckpointLister vpa_lister.VerticalPodAutoscalerCheckpointLister
|
||||||
VpaLister vpa_lister.VerticalPodAutoscalerLister
|
VpaLister vpa_lister.VerticalPodAutoscalerLister
|
||||||
PodLister v1lister.PodLister
|
PodLister v1lister.PodLister
|
||||||
OOMObserver oom.Observer
|
OOMObserver oom.Observer
|
||||||
|
@ -99,6 +100,7 @@ func (m ClusterStateFeederFactory) Make() *clusterStateFeeder {
|
||||||
metricsClient: m.MetricsClient,
|
metricsClient: m.MetricsClient,
|
||||||
oomChan: m.OOMObserver.GetObservedOomsChannel(),
|
oomChan: m.OOMObserver.GetObservedOomsChannel(),
|
||||||
vpaCheckpointClient: m.VpaCheckpointClient,
|
vpaCheckpointClient: m.VpaCheckpointClient,
|
||||||
|
vpaCheckpointLister: m.VpaCheckpointLister,
|
||||||
vpaLister: m.VpaLister,
|
vpaLister: m.VpaLister,
|
||||||
clusterState: m.ClusterState,
|
clusterState: m.ClusterState,
|
||||||
specClient: spec.NewSpecClient(m.PodLister),
|
specClient: spec.NewSpecClient(m.PodLister),
|
||||||
|
@ -206,6 +208,7 @@ type clusterStateFeeder struct {
|
||||||
metricsClient metrics.MetricsClient
|
metricsClient metrics.MetricsClient
|
||||||
oomChan <-chan oom.OomInfo
|
oomChan <-chan oom.OomInfo
|
||||||
vpaCheckpointClient vpa_api.VerticalPodAutoscalerCheckpointsGetter
|
vpaCheckpointClient vpa_api.VerticalPodAutoscalerCheckpointsGetter
|
||||||
|
vpaCheckpointLister vpa_lister.VerticalPodAutoscalerCheckpointLister
|
||||||
vpaLister vpa_lister.VerticalPodAutoscalerLister
|
vpaLister vpa_lister.VerticalPodAutoscalerLister
|
||||||
clusterState model.ClusterState
|
clusterState model.ClusterState
|
||||||
selectorFetcher target.VpaTargetSelectorFetcher
|
selectorFetcher target.VpaTargetSelectorFetcher
|
||||||
|
@ -267,25 +270,29 @@ func (feeder *clusterStateFeeder) InitFromCheckpoints(ctx context.Context) {
|
||||||
klog.V(3).InfoS("Initializing VPA from checkpoints")
|
klog.V(3).InfoS("Initializing VPA from checkpoints")
|
||||||
feeder.LoadVPAs(ctx)
|
feeder.LoadVPAs(ctx)
|
||||||
|
|
||||||
|
klog.V(3).InfoS("Fetching VPA checkpoints")
|
||||||
|
checkpointList, err := feeder.vpaCheckpointLister.List(labels.Everything())
|
||||||
|
if err != nil {
|
||||||
|
klog.ErrorS(err, "Cannot list VPA checkpoints")
|
||||||
|
}
|
||||||
|
|
||||||
namespaces := make(map[string]bool)
|
namespaces := make(map[string]bool)
|
||||||
for _, v := range feeder.clusterState.VPAs() {
|
for _, v := range feeder.clusterState.VPAs() {
|
||||||
namespaces[v.ID.Namespace] = true
|
namespaces[v.ID.Namespace] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
for namespace := range namespaces {
|
for namespace := range namespaces {
|
||||||
klog.V(3).InfoS("Fetching checkpoints", "namespace", namespace)
|
if feeder.shouldIgnoreNamespace(namespace) {
|
||||||
checkpointList, err := feeder.vpaCheckpointClient.VerticalPodAutoscalerCheckpoints(namespace).List(ctx, metav1.ListOptions{})
|
klog.V(3).InfoS("Skipping loading VPA Checkpoints from namespace.", "namespace", namespace, "vpaObjectNamespace", feeder.vpaObjectNamespace, "ignoredNamespaces", feeder.ignoredNamespaces)
|
||||||
if err != nil {
|
continue
|
||||||
klog.ErrorS(err, "Cannot list VPA checkpoints", "namespace", namespace)
|
|
||||||
}
|
}
|
||||||
for _, checkpoint := range checkpointList.Items {
|
|
||||||
|
|
||||||
|
for _, checkpoint := range checkpointList {
|
||||||
klog.V(3).InfoS("Loading checkpoint for VPA", "checkpoint", klog.KRef(checkpoint.Namespace, checkpoint.Spec.VPAObjectName), "container", checkpoint.Spec.ContainerName)
|
klog.V(3).InfoS("Loading checkpoint for VPA", "checkpoint", klog.KRef(checkpoint.Namespace, checkpoint.Spec.VPAObjectName), "container", checkpoint.Spec.ContainerName)
|
||||||
err = feeder.setVpaCheckpoint(&checkpoint)
|
err = feeder.setVpaCheckpoint(checkpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.ErrorS(err, "Error while loading checkpoint")
|
klog.ErrorS(err, "Error while loading checkpoint")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -345,11 +352,12 @@ func (feeder *clusterStateFeeder) shouldIgnoreNamespace(namespace string) bool {
|
||||||
|
|
||||||
func (feeder *clusterStateFeeder) cleanupCheckpointsForNamespace(ctx context.Context, namespace string, allVPAKeys map[model.VpaID]bool) error {
|
func (feeder *clusterStateFeeder) cleanupCheckpointsForNamespace(ctx context.Context, namespace string, allVPAKeys map[model.VpaID]bool) error {
|
||||||
var err error
|
var err error
|
||||||
checkpointList, err := feeder.vpaCheckpointClient.VerticalPodAutoscalerCheckpoints(namespace).List(ctx, metav1.ListOptions{})
|
checkpointList, err := feeder.vpaCheckpointLister.VerticalPodAutoscalerCheckpoints(namespace).List(labels.Everything())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, checkpoint := range checkpointList.Items {
|
for _, checkpoint := range checkpointList {
|
||||||
vpaID := model.VpaID{Namespace: checkpoint.Namespace, VpaName: checkpoint.Spec.VPAObjectName}
|
vpaID := model.VpaID{Namespace: checkpoint.Namespace, VpaName: checkpoint.Spec.VPAObjectName}
|
||||||
if !allVPAKeys[vpaID] {
|
if !allVPAKeys[vpaID] {
|
||||||
if errFeeder := feeder.vpaCheckpointClient.VerticalPodAutoscalerCheckpoints(namespace).Delete(ctx, checkpoint.Name, metav1.DeleteOptions{}); errFeeder != nil {
|
if errFeeder := feeder.vpaCheckpointClient.VerticalPodAutoscalerCheckpoints(namespace).Delete(ctx, checkpoint.Name, metav1.DeleteOptions{}); errFeeder != nil {
|
||||||
|
@ -573,6 +581,9 @@ func (feeder *clusterStateFeeder) validateTargetRef(ctx context.Context, vpa *vp
|
||||||
if vpa.Spec.TargetRef == nil {
|
if vpa.Spec.TargetRef == nil {
|
||||||
return false, condition{}
|
return false, condition{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
target := fmt.Sprintf("%s.%s/%s", vpa.Spec.TargetRef.APIVersion, vpa.Spec.TargetRef.Kind, vpa.Spec.TargetRef.Name)
|
||||||
|
|
||||||
k := controllerfetcher.ControllerKeyWithAPIVersion{
|
k := controllerfetcher.ControllerKeyWithAPIVersion{
|
||||||
ControllerKey: controllerfetcher.ControllerKey{
|
ControllerKey: controllerfetcher.ControllerKey{
|
||||||
Namespace: vpa.Namespace,
|
Namespace: vpa.Namespace,
|
||||||
|
@ -583,13 +594,13 @@ func (feeder *clusterStateFeeder) validateTargetRef(ctx context.Context, vpa *vp
|
||||||
}
|
}
|
||||||
top, err := feeder.controllerFetcher.FindTopMostWellKnownOrScalable(ctx, &k)
|
top, err := feeder.controllerFetcher.FindTopMostWellKnownOrScalable(ctx, &k)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, condition{conditionType: vpa_types.ConfigUnsupported, delete: false, message: fmt.Sprintf("Error checking if target is a topmost well-known or scalable controller: %s", err)}
|
return false, condition{conditionType: vpa_types.ConfigUnsupported, delete: false, message: fmt.Sprintf("Error checking if target %s is a topmost well-known or scalable controller: %s", target, err)}
|
||||||
}
|
}
|
||||||
if top == nil {
|
if top == nil {
|
||||||
return false, condition{conditionType: vpa_types.ConfigUnsupported, delete: false, message: fmt.Sprintf("Unknown error during checking if target is a topmost well-known or scalable controller: %s", err)}
|
return false, condition{conditionType: vpa_types.ConfigUnsupported, delete: false, message: fmt.Sprintf("Unknown error during checking if target %s is a topmost well-known or scalable controller", target)}
|
||||||
}
|
}
|
||||||
if *top != k {
|
if *top != k {
|
||||||
return false, condition{conditionType: vpa_types.ConfigUnsupported, delete: false, message: "The targetRef controller has a parent but it should point to a topmost well-known or scalable controller"}
|
return false, condition{conditionType: vpa_types.ConfigUnsupported, delete: false, message: fmt.Sprintf("The target %s has a parent controller but it should point to a topmost well-known or scalable controller", target)}
|
||||||
}
|
}
|
||||||
return true, condition{}
|
return true, condition{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,8 +65,8 @@ var (
|
||||||
unsupportedConditionTextFromFetcher = "Cannot read targetRef. Reason: targetRef not defined"
|
unsupportedConditionTextFromFetcher = "Cannot read targetRef. Reason: targetRef not defined"
|
||||||
unsupportedConditionNoExtraText = "Cannot read targetRef"
|
unsupportedConditionNoExtraText = "Cannot read targetRef"
|
||||||
unsupportedConditionNoTargetRef = "Cannot read targetRef"
|
unsupportedConditionNoTargetRef = "Cannot read targetRef"
|
||||||
unsupportedConditionMudaMudaMuda = "Error checking if target is a topmost well-known or scalable controller: muda muda muda"
|
unsupportedConditionMudaMudaMuda = "Error checking if target taxonomy.doestar/doseph-doestar is a topmost well-known or scalable controller: muda muda muda"
|
||||||
unsupportedTargetRefHasParent = "The targetRef controller has a parent but it should point to a topmost well-known or scalable controller"
|
unsupportedTargetRefHasParent = "The target stardust.dodokind/dotaro has a parent controller but it should point to a topmost well-known or scalable controller"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -859,11 +859,12 @@ func TestFilterVPAsIgnoreNamespaces(t *testing.T) {
|
||||||
func TestCanCleanupCheckpoints(t *testing.T) {
|
func TestCanCleanupCheckpoints(t *testing.T) {
|
||||||
_, tctx := ktesting.NewTestContext(t)
|
_, tctx := ktesting.NewTestContext(t)
|
||||||
client := fake.NewSimpleClientset()
|
client := fake.NewSimpleClientset()
|
||||||
|
namespace := "testNamespace"
|
||||||
|
|
||||||
_, err := client.CoreV1().Namespaces().Create(tctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "testNamespace"}}, metav1.CreateOptions{})
|
_, err := client.CoreV1().Namespaces().Create(tctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}, metav1.CreateOptions{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
vpaBuilder := test.VerticalPodAutoscaler().WithContainer("container").WithNamespace("testNamespace").WithTargetRef(&autoscalingv1.CrossVersionObjectReference{
|
vpaBuilder := test.VerticalPodAutoscaler().WithContainer("container").WithNamespace(namespace).WithTargetRef(&autoscalingv1.CrossVersionObjectReference{
|
||||||
Kind: kind,
|
Kind: kind,
|
||||||
Name: name1,
|
Name: name1,
|
||||||
APIVersion: apiVersion,
|
APIVersion: apiVersion,
|
||||||
|
@ -878,22 +879,19 @@ func TestCanCleanupCheckpoints(t *testing.T) {
|
||||||
vpaLister := &test.VerticalPodAutoscalerListerMock{}
|
vpaLister := &test.VerticalPodAutoscalerListerMock{}
|
||||||
vpaLister.On("List").Return(vpas, nil)
|
vpaLister.On("List").Return(vpas, nil)
|
||||||
|
|
||||||
checkpoints := &vpa_types.VerticalPodAutoscalerCheckpointList{
|
vpaCheckPoint := &vpa_types.VerticalPodAutoscalerCheckpoint{
|
||||||
Items: []vpa_types.VerticalPodAutoscalerCheckpoint{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
{
|
Namespace: namespace,
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
Name: "nonExistentVPA",
|
||||||
Namespace: "testNamespace",
|
},
|
||||||
Name: "nonExistentVPA",
|
Spec: vpa_types.VerticalPodAutoscalerCheckpointSpec{
|
||||||
},
|
VPAObjectName: "nonExistentVPA",
|
||||||
Spec: vpa_types.VerticalPodAutoscalerCheckpointSpec{
|
|
||||||
VPAObjectName: "nonExistentVPA",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
vpacheckpoints := []*vpa_types.VerticalPodAutoscalerCheckpoint{vpaCheckPoint}
|
||||||
|
|
||||||
for _, vpa := range vpas {
|
for _, vpa := range vpas {
|
||||||
checkpoints.Items = append(checkpoints.Items, vpa_types.VerticalPodAutoscalerCheckpoint{
|
vpacheckpoints = append(vpacheckpoints, &vpa_types.VerticalPodAutoscalerCheckpoint{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Namespace: vpa.Namespace,
|
Namespace: vpa.Namespace,
|
||||||
Name: vpa.Name,
|
Name: vpa.Name,
|
||||||
|
@ -904,23 +902,29 @@ func TestCanCleanupCheckpoints(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a mock checkpoint client to track deletions
|
||||||
checkpointClient := &fakeautoscalingv1.FakeAutoscalingV1{Fake: &core.Fake{}}
|
checkpointClient := &fakeautoscalingv1.FakeAutoscalingV1{Fake: &core.Fake{}}
|
||||||
checkpointClient.AddReactor("list", "verticalpodautoscalercheckpoints", func(action core.Action) (bool, runtime.Object, error) {
|
// Track deleted checkpoints
|
||||||
return true, checkpoints, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
deletedCheckpoints := []string{}
|
deletedCheckpoints := []string{}
|
||||||
checkpointClient.AddReactor("delete", "verticalpodautoscalercheckpoints", func(action core.Action) (bool, runtime.Object, error) {
|
checkpointClient.AddReactor("delete", "verticalpodautoscalercheckpoints", func(action core.Action) (bool, runtime.Object, error) {
|
||||||
deleteAction := action.(core.DeleteAction)
|
deleteAction := action.(core.DeleteAction)
|
||||||
deletedCheckpoints = append(deletedCheckpoints, deleteAction.GetName())
|
deletedCheckpoints = append(deletedCheckpoints, deleteAction.GetName())
|
||||||
|
|
||||||
return true, nil, nil
|
return true, nil, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Create namespace lister mock that will return the checkpoint list
|
||||||
|
checkpointNamespaceLister := &test.VerticalPodAutoscalerCheckPointListerMock{}
|
||||||
|
checkpointNamespaceLister.On("List").Return(vpacheckpoints, nil)
|
||||||
|
|
||||||
|
// Create main checkpoint mock that will return the namespace lister
|
||||||
|
checkpointLister := &test.VerticalPodAutoscalerCheckPointListerMock{}
|
||||||
|
checkpointLister.On("VerticalPodAutoscalerCheckpoints", namespace).Return(checkpointNamespaceLister)
|
||||||
|
|
||||||
feeder := clusterStateFeeder{
|
feeder := clusterStateFeeder{
|
||||||
coreClient: client.CoreV1(),
|
coreClient: client.CoreV1(),
|
||||||
vpaLister: vpaLister,
|
vpaLister: vpaLister,
|
||||||
vpaCheckpointClient: checkpointClient,
|
vpaCheckpointClient: checkpointClient,
|
||||||
|
vpaCheckpointLister: checkpointLister,
|
||||||
clusterState: model.NewClusterState(testGcPeriod),
|
clusterState: model.NewClusterState(testGcPeriod),
|
||||||
recommenderName: "default",
|
recommenderName: "default",
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ var (
|
||||||
confidenceIntervalMemory = flag.Duration("confidence-interval-memory", time.Hour*24, "The time interval used for computing the confidence multiplier for the memory lower and upper bound. Default: 24h")
|
confidenceIntervalMemory = flag.Duration("confidence-interval-memory", time.Hour*24, "The time interval used for computing the confidence multiplier for the memory lower and upper bound. Default: 24h")
|
||||||
humanizeMemory = flag.Bool("humanize-memory", false, "Convert memory values in recommendations to the highest appropriate SI unit with up to 2 decimal places for better readability.")
|
humanizeMemory = flag.Bool("humanize-memory", false, "Convert memory values in recommendations to the highest appropriate SI unit with up to 2 decimal places for better readability.")
|
||||||
roundCPUMillicores = flag.Int("round-cpu-millicores", 1, `CPU recommendation rounding factor in millicores. The CPU value will always be rounded up to the nearest multiple of this factor.`)
|
roundCPUMillicores = flag.Int("round-cpu-millicores", 1, `CPU recommendation rounding factor in millicores. The CPU value will always be rounded up to the nearest multiple of this factor.`)
|
||||||
|
roundMemoryBytes = flag.Int("round-memory-bytes", 1, `Memory recommendation rounding factor in bytes. The Memory value will always be rounded up to the nearest multiple of this factor.`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// PodResourceRecommender computes resource recommendation for a Vpa object.
|
// PodResourceRecommender computes resource recommendation for a Vpa object.
|
||||||
|
@ -193,10 +194,10 @@ func MapToListOfRecommendedContainerResources(resources RecommendedPodResources)
|
||||||
for _, name := range containerNames {
|
for _, name := range containerNames {
|
||||||
containerResources = append(containerResources, vpa_types.RecommendedContainerResources{
|
containerResources = append(containerResources, vpa_types.RecommendedContainerResources{
|
||||||
ContainerName: name,
|
ContainerName: name,
|
||||||
Target: model.ResourcesAsResourceList(resources[name].Target, *humanizeMemory, *roundCPUMillicores),
|
Target: model.ResourcesAsResourceList(resources[name].Target, *humanizeMemory, *roundCPUMillicores, *roundMemoryBytes),
|
||||||
LowerBound: model.ResourcesAsResourceList(resources[name].LowerBound, *humanizeMemory, *roundCPUMillicores),
|
LowerBound: model.ResourcesAsResourceList(resources[name].LowerBound, *humanizeMemory, *roundCPUMillicores, *roundMemoryBytes),
|
||||||
UpperBound: model.ResourcesAsResourceList(resources[name].UpperBound, *humanizeMemory, *roundCPUMillicores),
|
UpperBound: model.ResourcesAsResourceList(resources[name].UpperBound, *humanizeMemory, *roundCPUMillicores, *roundMemoryBytes),
|
||||||
UncappedTarget: model.ResourcesAsResourceList(resources[name].Target, *humanizeMemory, *roundCPUMillicores),
|
UncappedTarget: model.ResourcesAsResourceList(resources[name].Target, *humanizeMemory, *roundCPUMillicores, *roundMemoryBytes),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
recommendation := &vpa_types.RecommendedPodResources{
|
recommendation := &vpa_types.RecommendedPodResources{
|
||||||
|
|
|
@ -297,6 +297,7 @@ func run(ctx context.Context, healthCheck *metrics.HealthCheck, commonFlag *comm
|
||||||
MetricsClient: input_metrics.NewMetricsClient(source, commonFlag.VpaObjectNamespace, "default-metrics-client"),
|
MetricsClient: input_metrics.NewMetricsClient(source, commonFlag.VpaObjectNamespace, "default-metrics-client"),
|
||||||
VpaCheckpointClient: vpa_clientset.NewForConfigOrDie(config).AutoscalingV1(),
|
VpaCheckpointClient: vpa_clientset.NewForConfigOrDie(config).AutoscalingV1(),
|
||||||
VpaLister: vpa_api_util.NewVpasLister(vpa_clientset.NewForConfigOrDie(config), make(chan struct{}), commonFlag.VpaObjectNamespace),
|
VpaLister: vpa_api_util.NewVpasLister(vpa_clientset.NewForConfigOrDie(config), make(chan struct{}), commonFlag.VpaObjectNamespace),
|
||||||
|
VpaCheckpointLister: vpa_api_util.NewVpaCheckpointLister(vpa_clientset.NewForConfigOrDie(config), make(chan struct{}), commonFlag.VpaObjectNamespace),
|
||||||
ClusterState: clusterState,
|
ClusterState: clusterState,
|
||||||
SelectorFetcher: target.NewVpaTargetSelectorFetcher(config, kubeClient, factory),
|
SelectorFetcher: target.NewVpaTargetSelectorFetcher(config, kubeClient, factory),
|
||||||
MemorySaveMode: *memorySaver,
|
MemorySaveMode: *memorySaver,
|
||||||
|
|
|
@ -73,7 +73,7 @@ func BytesFromMemoryAmount(memoryAmount ResourceAmount) float64 {
|
||||||
|
|
||||||
// QuantityFromMemoryAmount converts memory ResourceAmount to a resource.Quantity.
|
// QuantityFromMemoryAmount converts memory ResourceAmount to a resource.Quantity.
|
||||||
func QuantityFromMemoryAmount(memoryAmount ResourceAmount) resource.Quantity {
|
func QuantityFromMemoryAmount(memoryAmount ResourceAmount) resource.Quantity {
|
||||||
return *resource.NewScaledQuantity(int64(memoryAmount), 0)
|
return *resource.NewQuantity(int64(memoryAmount), resource.BinarySI)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScaleResource returns the resource amount multiplied by a given factor.
|
// ScaleResource returns the resource amount multiplied by a given factor.
|
||||||
|
@ -82,7 +82,7 @@ func ScaleResource(amount ResourceAmount, factor float64) ResourceAmount {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourcesAsResourceList converts internal Resources representation to ResourcesList.
|
// ResourcesAsResourceList converts internal Resources representation to ResourcesList.
|
||||||
func ResourcesAsResourceList(resources Resources, humanizeMemory bool, roundCPUMillicores int) apiv1.ResourceList {
|
func ResourcesAsResourceList(resources Resources, humanizeMemory bool, roundCPUMillicores, roundMemoryBytes int) apiv1.ResourceList {
|
||||||
result := make(apiv1.ResourceList)
|
result := make(apiv1.ResourceList)
|
||||||
for key, resourceAmount := range resources {
|
for key, resourceAmount := range resources {
|
||||||
var newKey apiv1.ResourceName
|
var newKey apiv1.ResourceName
|
||||||
|
@ -103,6 +103,15 @@ func ResourcesAsResourceList(resources Resources, humanizeMemory bool, roundCPUM
|
||||||
case ResourceMemory:
|
case ResourceMemory:
|
||||||
newKey = apiv1.ResourceMemory
|
newKey = apiv1.ResourceMemory
|
||||||
quantity = QuantityFromMemoryAmount(resourceAmount)
|
quantity = QuantityFromMemoryAmount(resourceAmount)
|
||||||
|
if roundMemoryBytes != 1 && !quantity.IsZero() {
|
||||||
|
roundedValues, err := RoundUpToScale(resourceAmount, roundMemoryBytes)
|
||||||
|
if err != nil {
|
||||||
|
klog.V(4).InfoS("Error rounding memory value; leaving unchanged", "rawValue", resourceAmount, "scale", roundMemoryBytes, "error", err)
|
||||||
|
} else {
|
||||||
|
klog.V(4).InfoS("Successfully rounded memory value", "rawValue", resourceAmount, "roundedValue", roundedValues)
|
||||||
|
}
|
||||||
|
quantity = QuantityFromMemoryAmount(roundedValues)
|
||||||
|
}
|
||||||
if humanizeMemory && !quantity.IsZero() {
|
if humanizeMemory && !quantity.IsZero() {
|
||||||
rawValues := quantity.Value()
|
rawValues := quantity.Value()
|
||||||
humanizedValue := HumanizeMemoryQuantity(rawValues)
|
humanizedValue := HumanizeMemoryQuantity(rawValues)
|
||||||
|
|
|
@ -29,22 +29,24 @@ type ResourcesAsResourceListTestCase struct {
|
||||||
resources Resources
|
resources Resources
|
||||||
humanize bool
|
humanize bool
|
||||||
roundCPU int
|
roundCPU int
|
||||||
|
roundMemory int
|
||||||
resourceList apiv1.ResourceList
|
resourceList apiv1.ResourceList
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResourcesAsResourceList(t *testing.T) {
|
func TestResourcesAsResourceList(t *testing.T) {
|
||||||
testCases := []ResourcesAsResourceListTestCase{
|
testCases := []ResourcesAsResourceListTestCase{
|
||||||
{
|
{
|
||||||
name: "basic resources without humanize and no cpu rounding",
|
name: "basic resources without humanize and no rounding",
|
||||||
resources: Resources{
|
resources: Resources{
|
||||||
ResourceCPU: 1000,
|
ResourceCPU: 1000,
|
||||||
ResourceMemory: 1000,
|
ResourceMemory: 1024,
|
||||||
},
|
},
|
||||||
humanize: false,
|
humanize: false,
|
||||||
roundCPU: 1,
|
roundCPU: 1,
|
||||||
|
roundMemory: 1,
|
||||||
resourceList: apiv1.ResourceList{
|
resourceList: apiv1.ResourceList{
|
||||||
apiv1.ResourceCPU: *resource.NewMilliQuantity(1000, resource.DecimalSI),
|
apiv1.ResourceCPU: *resource.NewMilliQuantity(1000, resource.DecimalSI),
|
||||||
apiv1.ResourceMemory: *resource.NewQuantity(1000, resource.DecimalSI),
|
apiv1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -53,21 +55,37 @@ func TestResourcesAsResourceList(t *testing.T) {
|
||||||
ResourceCPU: 1000,
|
ResourceCPU: 1000,
|
||||||
ResourceMemory: 262144000, // 250Mi
|
ResourceMemory: 262144000, // 250Mi
|
||||||
},
|
},
|
||||||
humanize: true,
|
humanize: true,
|
||||||
roundCPU: 1,
|
roundCPU: 1,
|
||||||
|
roundMemory: 1,
|
||||||
resourceList: apiv1.ResourceList{
|
resourceList: apiv1.ResourceList{
|
||||||
apiv1.ResourceCPU: *resource.NewMilliQuantity(1000, resource.DecimalSI),
|
apiv1.ResourceCPU: *resource.NewMilliQuantity(1000, resource.DecimalSI),
|
||||||
apiv1.ResourceMemory: resource.MustParse("250.00Mi"),
|
apiv1.ResourceMemory: resource.MustParse("250.00Mi"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "basic resources with humanize and memory rounding to 256Mi",
|
||||||
|
resources: Resources{
|
||||||
|
ResourceCPU: 1000,
|
||||||
|
ResourceMemory: 262144000, // 250Mi
|
||||||
|
},
|
||||||
|
humanize: true,
|
||||||
|
roundCPU: 1,
|
||||||
|
roundMemory: 268435456,
|
||||||
|
resourceList: apiv1.ResourceList{
|
||||||
|
apiv1.ResourceCPU: *resource.NewMilliQuantity(1000, resource.DecimalSI),
|
||||||
|
apiv1.ResourceMemory: resource.MustParse("256.00Mi"),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "large memory value with humanize and cpu rounding to 3",
|
name: "large memory value with humanize and cpu rounding to 3",
|
||||||
resources: Resources{
|
resources: Resources{
|
||||||
ResourceCPU: 1000,
|
ResourceCPU: 1000,
|
||||||
ResourceMemory: 839500000, // 800.61Mi
|
ResourceMemory: 839500000, // 800.61Mi
|
||||||
},
|
},
|
||||||
humanize: true,
|
humanize: true,
|
||||||
roundCPU: 3,
|
roundCPU: 3,
|
||||||
|
roundMemory: 1,
|
||||||
resourceList: apiv1.ResourceList{
|
resourceList: apiv1.ResourceList{
|
||||||
apiv1.ResourceCPU: *resource.NewMilliQuantity(1002, resource.DecimalSI),
|
apiv1.ResourceCPU: *resource.NewMilliQuantity(1002, resource.DecimalSI),
|
||||||
apiv1.ResourceMemory: resource.MustParse("800.61Mi"),
|
apiv1.ResourceMemory: resource.MustParse("800.61Mi"),
|
||||||
|
@ -79,11 +97,12 @@ func TestResourcesAsResourceList(t *testing.T) {
|
||||||
ResourceCPU: 0,
|
ResourceCPU: 0,
|
||||||
ResourceMemory: 0,
|
ResourceMemory: 0,
|
||||||
},
|
},
|
||||||
humanize: false,
|
humanize: false,
|
||||||
roundCPU: 2,
|
roundCPU: 2,
|
||||||
|
roundMemory: 1,
|
||||||
resourceList: apiv1.ResourceList{
|
resourceList: apiv1.ResourceList{
|
||||||
apiv1.ResourceCPU: *resource.NewMilliQuantity(0, resource.DecimalSI),
|
apiv1.ResourceCPU: *resource.NewMilliQuantity(0, resource.DecimalSI),
|
||||||
apiv1.ResourceMemory: *resource.NewQuantity(0, resource.DecimalSI),
|
apiv1.ResourceMemory: *resource.NewQuantity(0, resource.BinarySI),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -92,17 +111,32 @@ func TestResourcesAsResourceList(t *testing.T) {
|
||||||
ResourceCPU: 1231241,
|
ResourceCPU: 1231241,
|
||||||
ResourceMemory: 839500000,
|
ResourceMemory: 839500000,
|
||||||
},
|
},
|
||||||
humanize: false,
|
humanize: false,
|
||||||
roundCPU: 13,
|
roundCPU: 13,
|
||||||
|
roundMemory: 1,
|
||||||
resourceList: apiv1.ResourceList{
|
resourceList: apiv1.ResourceList{
|
||||||
apiv1.ResourceCPU: *resource.NewMilliQuantity(1231243, resource.DecimalSI),
|
apiv1.ResourceCPU: *resource.NewMilliQuantity(1231243, resource.DecimalSI),
|
||||||
apiv1.ResourceMemory: *resource.NewQuantity(839500000, resource.DecimalSI),
|
apiv1.ResourceMemory: *resource.NewQuantity(839500000, resource.BinarySI),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "large memory value without humanize and with memory rounding to 128Mi",
|
||||||
|
resources: Resources{
|
||||||
|
ResourceCPU: 1231241,
|
||||||
|
ResourceMemory: 839500000,
|
||||||
|
},
|
||||||
|
humanize: false,
|
||||||
|
roundCPU: 13,
|
||||||
|
roundMemory: 134217728,
|
||||||
|
resourceList: apiv1.ResourceList{
|
||||||
|
apiv1.ResourceCPU: *resource.NewMilliQuantity(1231243, resource.DecimalSI),
|
||||||
|
apiv1.ResourceMemory: resource.MustParse("896Mi"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
result := ResourcesAsResourceList(tc.resources, tc.humanize, tc.roundCPU)
|
result := ResourcesAsResourceList(tc.resources, tc.humanize, tc.roundCPU, tc.roundMemory)
|
||||||
if !result[apiv1.ResourceCPU].Equal(tc.resourceList[apiv1.ResourceCPU]) {
|
if !result[apiv1.ResourceCPU].Equal(tc.resourceList[apiv1.ResourceCPU]) {
|
||||||
t.Errorf("expected %v, got %v", tc.resourceList[apiv1.ResourceCPU], result[apiv1.ResourceCPU])
|
t.Errorf("expected %v, got %v", tc.resourceList[apiv1.ResourceCPU], result[apiv1.ResourceCPU])
|
||||||
}
|
}
|
||||||
|
@ -503,42 +537,42 @@ func TestQuantityFromMemoryAmount(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "should get 69",
|
name: "should get 69",
|
||||||
memoryAmount: 69,
|
memoryAmount: 69,
|
||||||
want: *resource.NewQuantity(69, resource.DecimalSI),
|
want: *resource.NewQuantity(69, resource.BinarySI),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "should get 12",
|
name: "should get 12",
|
||||||
memoryAmount: 12,
|
memoryAmount: 12,
|
||||||
want: *resource.NewQuantity(12, resource.DecimalSI),
|
want: *resource.NewQuantity(12, resource.BinarySI),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "should get 17",
|
name: "should get 17",
|
||||||
memoryAmount: 17,
|
memoryAmount: 17,
|
||||||
want: *resource.NewQuantity(17, resource.DecimalSI),
|
want: *resource.NewQuantity(17, resource.BinarySI),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "should get 4",
|
name: "should get 4",
|
||||||
memoryAmount: 4,
|
memoryAmount: 4,
|
||||||
want: *resource.NewQuantity(4, resource.DecimalSI),
|
want: *resource.NewQuantity(4, resource.BinarySI),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "should get 12",
|
name: "should get 12",
|
||||||
memoryAmount: 12,
|
memoryAmount: 12,
|
||||||
want: *resource.NewQuantity(12, resource.DecimalSI),
|
want: *resource.NewQuantity(12, resource.BinarySI),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "should get 1",
|
name: "should get 1",
|
||||||
memoryAmount: 1,
|
memoryAmount: 1,
|
||||||
want: *resource.NewQuantity(1, resource.DecimalSI),
|
want: *resource.NewQuantity(1, resource.BinarySI),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "should get 0",
|
name: "should get 0",
|
||||||
memoryAmount: 0,
|
memoryAmount: 0,
|
||||||
want: *resource.NewQuantity(0, resource.DecimalSI),
|
want: *resource.NewQuantity(0, resource.BinarySI),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "should get 123456789",
|
name: "should get 123456789",
|
||||||
memoryAmount: 123456789,
|
memoryAmount: 123456789,
|
||||||
want: *resource.NewQuantity(123456789, resource.DecimalSI),
|
want: *resource.NewQuantity(123456789, resource.BinarySI),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range tc {
|
for _, tc := range tc {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM golang:1.24.4 AS builder
|
FROM --platform=$BUILDPLATFORM golang:1.24.5 AS builder
|
||||||
|
|
||||||
WORKDIR /workspace
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
|
|
@ -230,7 +230,8 @@ func (u *updater) RunOnce(ctx context.Context) {
|
||||||
// to contain only Pods controlled by a VPA in auto, recreate, or inPlaceOrRecreate mode
|
// to contain only Pods controlled by a VPA in auto, recreate, or inPlaceOrRecreate mode
|
||||||
for vpa, livePods := range controlledPods {
|
for vpa, livePods := range controlledPods {
|
||||||
vpaSize := len(livePods)
|
vpaSize := len(livePods)
|
||||||
controlledPodsCounter.Add(vpaSize, vpaSize)
|
updateMode := vpa_api_util.GetUpdateMode(vpa)
|
||||||
|
controlledPodsCounter.Add(vpaSize, updateMode, vpaSize)
|
||||||
creatorToSingleGroupStatsMap, podToReplicaCreatorMap, err := u.restrictionFactory.GetCreatorMaps(livePods, vpa)
|
creatorToSingleGroupStatsMap, podToReplicaCreatorMap, err := u.restrictionFactory.GetCreatorMaps(livePods, vpa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.ErrorS(err, "Failed to get creator maps")
|
klog.ErrorS(err, "Failed to get creator maps")
|
||||||
|
@ -242,7 +243,6 @@ func (u *updater) RunOnce(ctx context.Context) {
|
||||||
|
|
||||||
podsForInPlace := make([]*apiv1.Pod, 0)
|
podsForInPlace := make([]*apiv1.Pod, 0)
|
||||||
podsForEviction := make([]*apiv1.Pod, 0)
|
podsForEviction := make([]*apiv1.Pod, 0)
|
||||||
updateMode := vpa_api_util.GetUpdateMode(vpa)
|
|
||||||
|
|
||||||
if updateMode == vpa_types.UpdateModeInPlaceOrRecreate && features.Enabled(features.InPlaceOrRecreate) {
|
if updateMode == vpa_types.UpdateModeInPlaceOrRecreate && features.Enabled(features.InPlaceOrRecreate) {
|
||||||
podsForInPlace = u.getPodsUpdateOrder(filterNonInPlaceUpdatablePods(livePods, inPlaceLimiter), vpa)
|
podsForInPlace = u.getPodsUpdateOrder(filterNonInPlaceUpdatablePods(livePods, inPlaceLimiter), vpa)
|
||||||
|
@ -253,7 +253,7 @@ func (u *updater) RunOnce(ctx context.Context) {
|
||||||
klog.InfoS("Warning: feature gate is not enabled for this updateMode", "featuregate", features.InPlaceOrRecreate, "updateMode", vpa_types.UpdateModeInPlaceOrRecreate)
|
klog.InfoS("Warning: feature gate is not enabled for this updateMode", "featuregate", features.InPlaceOrRecreate, "updateMode", vpa_types.UpdateModeInPlaceOrRecreate)
|
||||||
}
|
}
|
||||||
podsForEviction = u.getPodsUpdateOrder(filterNonEvictablePods(livePods, evictionLimiter), vpa)
|
podsForEviction = u.getPodsUpdateOrder(filterNonEvictablePods(livePods, evictionLimiter), vpa)
|
||||||
evictablePodsCounter.Add(vpaSize, len(podsForEviction))
|
evictablePodsCounter.Add(vpaSize, updateMode, len(podsForEviction))
|
||||||
}
|
}
|
||||||
|
|
||||||
withInPlaceUpdatable := false
|
withInPlaceUpdatable := false
|
||||||
|
@ -279,8 +279,9 @@ func (u *updater) RunOnce(ctx context.Context) {
|
||||||
}
|
}
|
||||||
err := inPlaceLimiter.InPlaceUpdate(pod, vpa, u.eventRecorder)
|
err := inPlaceLimiter.InPlaceUpdate(pod, vpa, u.eventRecorder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(0).InfoS("In-place update failed", "error", err, "pod", klog.KObj(pod))
|
klog.V(0).InfoS("In-place resize failed, falling back to eviction", "error", err, "pod", klog.KObj(pod))
|
||||||
metrics_updater.RecordFailedInPlaceUpdate(vpaSize, "InPlaceUpdateError")
|
metrics_updater.RecordFailedInPlaceUpdate(vpaSize, "InPlaceUpdateError")
|
||||||
|
podsForEviction = append(podsForEviction, pod)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
withInPlaceUpdated = true
|
withInPlaceUpdated = true
|
||||||
|
@ -303,7 +304,7 @@ func (u *updater) RunOnce(ctx context.Context) {
|
||||||
klog.V(0).InfoS("Eviction failed", "error", evictErr, "pod", klog.KObj(pod))
|
klog.V(0).InfoS("Eviction failed", "error", evictErr, "pod", klog.KObj(pod))
|
||||||
} else {
|
} else {
|
||||||
withEvicted = true
|
withEvicted = true
|
||||||
metrics_updater.AddEvictedPod(vpaSize)
|
metrics_updater.AddEvictedPod(vpaSize, updateMode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,10 +315,10 @@ func (u *updater) RunOnce(ctx context.Context) {
|
||||||
vpasWithInPlaceUpdatedPodsCounter.Add(vpaSize, 1)
|
vpasWithInPlaceUpdatedPodsCounter.Add(vpaSize, 1)
|
||||||
}
|
}
|
||||||
if withEvictable {
|
if withEvictable {
|
||||||
vpasWithEvictablePodsCounter.Add(vpaSize, 1)
|
vpasWithEvictablePodsCounter.Add(vpaSize, updateMode, 1)
|
||||||
}
|
}
|
||||||
if withEvicted {
|
if withEvicted {
|
||||||
vpasWithEvictedPodsCounter.Add(vpaSize, 1)
|
vpasWithEvictedPodsCounter.Add(vpaSize, updateMode, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timer.ObserveStep("EvictPods")
|
timer.ObserveStep("EvictPods")
|
||||||
|
|
|
@ -18,6 +18,7 @@ package logic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -55,6 +56,7 @@ func TestRunOnce_Mode(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
updateMode vpa_types.UpdateMode
|
updateMode vpa_types.UpdateMode
|
||||||
|
shouldInPlaceFail bool
|
||||||
expectFetchCalls bool
|
expectFetchCalls bool
|
||||||
expectedEvictionCount int
|
expectedEvictionCount int
|
||||||
expectedInPlacedCount int
|
expectedInPlacedCount int
|
||||||
|
@ -64,6 +66,7 @@ func TestRunOnce_Mode(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "with Auto mode",
|
name: "with Auto mode",
|
||||||
updateMode: vpa_types.UpdateModeAuto,
|
updateMode: vpa_types.UpdateModeAuto,
|
||||||
|
shouldInPlaceFail: false,
|
||||||
expectFetchCalls: true,
|
expectFetchCalls: true,
|
||||||
expectedEvictionCount: 5,
|
expectedEvictionCount: 5,
|
||||||
expectedInPlacedCount: 0,
|
expectedInPlacedCount: 0,
|
||||||
|
@ -73,6 +76,7 @@ func TestRunOnce_Mode(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "with Initial mode",
|
name: "with Initial mode",
|
||||||
updateMode: vpa_types.UpdateModeInitial,
|
updateMode: vpa_types.UpdateModeInitial,
|
||||||
|
shouldInPlaceFail: false,
|
||||||
expectFetchCalls: false,
|
expectFetchCalls: false,
|
||||||
expectedEvictionCount: 0,
|
expectedEvictionCount: 0,
|
||||||
expectedInPlacedCount: 0,
|
expectedInPlacedCount: 0,
|
||||||
|
@ -82,6 +86,7 @@ func TestRunOnce_Mode(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "with Off mode",
|
name: "with Off mode",
|
||||||
updateMode: vpa_types.UpdateModeOff,
|
updateMode: vpa_types.UpdateModeOff,
|
||||||
|
shouldInPlaceFail: false,
|
||||||
expectFetchCalls: false,
|
expectFetchCalls: false,
|
||||||
expectedEvictionCount: 0,
|
expectedEvictionCount: 0,
|
||||||
expectedInPlacedCount: 0,
|
expectedInPlacedCount: 0,
|
||||||
|
@ -91,6 +96,7 @@ func TestRunOnce_Mode(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "with InPlaceOrRecreate mode expecting in-place updates",
|
name: "with InPlaceOrRecreate mode expecting in-place updates",
|
||||||
updateMode: vpa_types.UpdateModeInPlaceOrRecreate,
|
updateMode: vpa_types.UpdateModeInPlaceOrRecreate,
|
||||||
|
shouldInPlaceFail: false,
|
||||||
expectFetchCalls: true,
|
expectFetchCalls: true,
|
||||||
expectedEvictionCount: 0,
|
expectedEvictionCount: 0,
|
||||||
expectedInPlacedCount: 5,
|
expectedInPlacedCount: 5,
|
||||||
|
@ -100,6 +106,7 @@ func TestRunOnce_Mode(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "with InPlaceOrRecreate mode expecting fallback to evictions",
|
name: "with InPlaceOrRecreate mode expecting fallback to evictions",
|
||||||
updateMode: vpa_types.UpdateModeInPlaceOrRecreate,
|
updateMode: vpa_types.UpdateModeInPlaceOrRecreate,
|
||||||
|
shouldInPlaceFail: false,
|
||||||
expectFetchCalls: true,
|
expectFetchCalls: true,
|
||||||
expectedEvictionCount: 5,
|
expectedEvictionCount: 5,
|
||||||
expectedInPlacedCount: 0,
|
expectedInPlacedCount: 0,
|
||||||
|
@ -109,18 +116,30 @@ func TestRunOnce_Mode(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "with InPlaceOrRecreate mode expecting no evictions or in-place",
|
name: "with InPlaceOrRecreate mode expecting no evictions or in-place",
|
||||||
updateMode: vpa_types.UpdateModeInPlaceOrRecreate,
|
updateMode: vpa_types.UpdateModeInPlaceOrRecreate,
|
||||||
|
shouldInPlaceFail: false,
|
||||||
expectFetchCalls: true,
|
expectFetchCalls: true,
|
||||||
expectedEvictionCount: 0,
|
expectedEvictionCount: 0,
|
||||||
expectedInPlacedCount: 0,
|
expectedInPlacedCount: 0,
|
||||||
canEvict: false,
|
canEvict: false,
|
||||||
canInPlaceUpdate: utils.InPlaceDeferred,
|
canInPlaceUpdate: utils.InPlaceDeferred,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "with InPlaceOrRecreate mode and failed in-place update",
|
||||||
|
updateMode: vpa_types.UpdateModeInPlaceOrRecreate,
|
||||||
|
shouldInPlaceFail: true,
|
||||||
|
expectFetchCalls: true,
|
||||||
|
expectedEvictionCount: 5, // All pods should be evicted after in-place update fails
|
||||||
|
expectedInPlacedCount: 5, // All pods attempt in-place update first
|
||||||
|
canEvict: true,
|
||||||
|
canInPlaceUpdate: utils.InPlaceApproved,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
testRunOnceBase(
|
testRunOnceBase(
|
||||||
t,
|
t,
|
||||||
tc.updateMode,
|
tc.updateMode,
|
||||||
|
tc.shouldInPlaceFail,
|
||||||
newFakeValidator(true),
|
newFakeValidator(true),
|
||||||
tc.expectFetchCalls,
|
tc.expectFetchCalls,
|
||||||
tc.expectedEvictionCount,
|
tc.expectedEvictionCount,
|
||||||
|
@ -159,6 +178,7 @@ func TestRunOnce_Status(t *testing.T) {
|
||||||
testRunOnceBase(
|
testRunOnceBase(
|
||||||
t,
|
t,
|
||||||
vpa_types.UpdateModeAuto,
|
vpa_types.UpdateModeAuto,
|
||||||
|
false,
|
||||||
tc.statusValidator,
|
tc.statusValidator,
|
||||||
tc.expectFetchCalls,
|
tc.expectFetchCalls,
|
||||||
tc.expectedEvictionCount,
|
tc.expectedEvictionCount,
|
||||||
|
@ -172,6 +192,7 @@ func TestRunOnce_Status(t *testing.T) {
|
||||||
func testRunOnceBase(
|
func testRunOnceBase(
|
||||||
t *testing.T,
|
t *testing.T,
|
||||||
updateMode vpa_types.UpdateMode,
|
updateMode vpa_types.UpdateMode,
|
||||||
|
shouldInPlaceFail bool,
|
||||||
statusValidator status.Validator,
|
statusValidator status.Validator,
|
||||||
expectFetchCalls bool,
|
expectFetchCalls bool,
|
||||||
expectedEvictionCount int,
|
expectedEvictionCount int,
|
||||||
|
@ -213,7 +234,11 @@ func testRunOnceBase(
|
||||||
pods[i].Labels = labels
|
pods[i].Labels = labels
|
||||||
|
|
||||||
inplace.On("CanInPlaceUpdate", pods[i]).Return(canInPlaceUpdate)
|
inplace.On("CanInPlaceUpdate", pods[i]).Return(canInPlaceUpdate)
|
||||||
inplace.On("InPlaceUpdate", pods[i], nil).Return(nil)
|
if shouldInPlaceFail {
|
||||||
|
inplace.On("InPlaceUpdate", pods[i], nil).Return(fmt.Errorf("in-place update failed"))
|
||||||
|
} else {
|
||||||
|
inplace.On("InPlaceUpdate", pods[i], nil).Return(nil)
|
||||||
|
}
|
||||||
|
|
||||||
eviction.On("CanEvict", pods[i]).Return(true)
|
eviction.On("CanEvict", pods[i]).Return(true)
|
||||||
eviction.On("Evict", pods[i], nil).Return(nil)
|
eviction.On("Evict", pods[i], nil).Return(nil)
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1"
|
||||||
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/metrics"
|
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,13 +36,20 @@ type SizeBasedGauge struct {
|
||||||
gauge *prometheus.GaugeVec
|
gauge *prometheus.GaugeVec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateModeAndSizeBasedGauge is a wrapper for incrementally recording values
|
||||||
|
// indexed by log2(VPA size) and update mode
|
||||||
|
type UpdateModeAndSizeBasedGauge struct {
|
||||||
|
values [metrics.MaxVpaSizeLog]map[vpa_types.UpdateMode]int
|
||||||
|
gauge *prometheus.GaugeVec
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
controlledCount = prometheus.NewGaugeVec(
|
controlledCount = prometheus.NewGaugeVec(
|
||||||
prometheus.GaugeOpts{
|
prometheus.GaugeOpts{
|
||||||
Namespace: metricsNamespace,
|
Namespace: metricsNamespace,
|
||||||
Name: "controlled_pods_total",
|
Name: "controlled_pods_total",
|
||||||
Help: "Number of Pods controlled by VPA updater.",
|
Help: "Number of Pods controlled by VPA updater.",
|
||||||
}, []string{"vpa_size_log2"},
|
}, []string{"vpa_size_log2", "update_mode"},
|
||||||
)
|
)
|
||||||
|
|
||||||
evictableCount = prometheus.NewGaugeVec(
|
evictableCount = prometheus.NewGaugeVec(
|
||||||
|
@ -49,7 +57,7 @@ var (
|
||||||
Namespace: metricsNamespace,
|
Namespace: metricsNamespace,
|
||||||
Name: "evictable_pods_total",
|
Name: "evictable_pods_total",
|
||||||
Help: "Number of Pods matching evicition criteria.",
|
Help: "Number of Pods matching evicition criteria.",
|
||||||
}, []string{"vpa_size_log2"},
|
}, []string{"vpa_size_log2", "update_mode"},
|
||||||
)
|
)
|
||||||
|
|
||||||
evictedCount = prometheus.NewCounterVec(
|
evictedCount = prometheus.NewCounterVec(
|
||||||
|
@ -57,7 +65,7 @@ var (
|
||||||
Namespace: metricsNamespace,
|
Namespace: metricsNamespace,
|
||||||
Name: "evicted_pods_total",
|
Name: "evicted_pods_total",
|
||||||
Help: "Number of Pods evicted by Updater to apply a new recommendation.",
|
Help: "Number of Pods evicted by Updater to apply a new recommendation.",
|
||||||
}, []string{"vpa_size_log2"},
|
}, []string{"vpa_size_log2", "update_mode"},
|
||||||
)
|
)
|
||||||
|
|
||||||
vpasWithEvictablePodsCount = prometheus.NewGaugeVec(
|
vpasWithEvictablePodsCount = prometheus.NewGaugeVec(
|
||||||
|
@ -65,7 +73,7 @@ var (
|
||||||
Namespace: metricsNamespace,
|
Namespace: metricsNamespace,
|
||||||
Name: "vpas_with_evictable_pods_total",
|
Name: "vpas_with_evictable_pods_total",
|
||||||
Help: "Number of VPA objects with at least one Pod matching evicition criteria.",
|
Help: "Number of VPA objects with at least one Pod matching evicition criteria.",
|
||||||
}, []string{"vpa_size_log2"},
|
}, []string{"vpa_size_log2", "update_mode"},
|
||||||
)
|
)
|
||||||
|
|
||||||
vpasWithEvictedPodsCount = prometheus.NewGaugeVec(
|
vpasWithEvictedPodsCount = prometheus.NewGaugeVec(
|
||||||
|
@ -73,7 +81,7 @@ var (
|
||||||
Namespace: metricsNamespace,
|
Namespace: metricsNamespace,
|
||||||
Name: "vpas_with_evicted_pods_total",
|
Name: "vpas_with_evicted_pods_total",
|
||||||
Help: "Number of VPA objects with at least one evicted Pod.",
|
Help: "Number of VPA objects with at least one evicted Pod.",
|
||||||
}, []string{"vpa_size_log2"},
|
}, []string{"vpa_size_log2", "update_mode"},
|
||||||
)
|
)
|
||||||
|
|
||||||
inPlaceUpdatableCount = prometheus.NewGaugeVec(
|
inPlaceUpdatableCount = prometheus.NewGaugeVec(
|
||||||
|
@ -138,30 +146,41 @@ func newSizeBasedGauge(gauge *prometheus.GaugeVec) *SizeBasedGauge {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newModeAndSizeBasedGauge provides a wrapper for counting items in a loop
|
||||||
|
func newModeAndSizeBasedGauge(gauge *prometheus.GaugeVec) *UpdateModeAndSizeBasedGauge {
|
||||||
|
g := &UpdateModeAndSizeBasedGauge{
|
||||||
|
gauge: gauge,
|
||||||
|
}
|
||||||
|
for i := range g.values {
|
||||||
|
g.values[i] = make(map[vpa_types.UpdateMode]int)
|
||||||
|
}
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
// NewControlledPodsCounter returns a wrapper for counting Pods controlled by Updater
|
// NewControlledPodsCounter returns a wrapper for counting Pods controlled by Updater
|
||||||
func NewControlledPodsCounter() *SizeBasedGauge {
|
func NewControlledPodsCounter() *UpdateModeAndSizeBasedGauge {
|
||||||
return newSizeBasedGauge(controlledCount)
|
return newModeAndSizeBasedGauge(controlledCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEvictablePodsCounter returns a wrapper for counting Pods which are matching eviction criteria
|
// NewEvictablePodsCounter returns a wrapper for counting Pods which are matching eviction criteria
|
||||||
func NewEvictablePodsCounter() *SizeBasedGauge {
|
func NewEvictablePodsCounter() *UpdateModeAndSizeBasedGauge {
|
||||||
return newSizeBasedGauge(evictableCount)
|
return newModeAndSizeBasedGauge(evictableCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVpasWithEvictablePodsCounter returns a wrapper for counting VPA objects with Pods matching eviction criteria
|
// NewVpasWithEvictablePodsCounter returns a wrapper for counting VPA objects with Pods matching eviction criteria
|
||||||
func NewVpasWithEvictablePodsCounter() *SizeBasedGauge {
|
func NewVpasWithEvictablePodsCounter() *UpdateModeAndSizeBasedGauge {
|
||||||
return newSizeBasedGauge(vpasWithEvictablePodsCount)
|
return newModeAndSizeBasedGauge(vpasWithEvictablePodsCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVpasWithEvictedPodsCounter returns a wrapper for counting VPA objects with evicted Pods
|
// NewVpasWithEvictedPodsCounter returns a wrapper for counting VPA objects with evicted Pods
|
||||||
func NewVpasWithEvictedPodsCounter() *SizeBasedGauge {
|
func NewVpasWithEvictedPodsCounter() *UpdateModeAndSizeBasedGauge {
|
||||||
return newSizeBasedGauge(vpasWithEvictedPodsCount)
|
return newModeAndSizeBasedGauge(vpasWithEvictedPodsCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddEvictedPod increases the counter of pods evicted by Updater, by given VPA size
|
// AddEvictedPod increases the counter of pods evicted by Updater, by given VPA size
|
||||||
func AddEvictedPod(vpaSize int) {
|
func AddEvictedPod(vpaSize int, mode vpa_types.UpdateMode) {
|
||||||
log2 := metrics.GetVpaSizeLog2(vpaSize)
|
log2 := metrics.GetVpaSizeLog2(vpaSize)
|
||||||
evictedCount.WithLabelValues(strconv.Itoa(log2)).Inc()
|
evictedCount.WithLabelValues(strconv.Itoa(log2), string(mode)).Inc()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInPlaceUpdatablePodsCounter returns a wrapper for counting Pods which are matching in-place update criteria
|
// NewInPlaceUpdatablePodsCounter returns a wrapper for counting Pods which are matching in-place update criteria
|
||||||
|
@ -203,3 +222,19 @@ func (g *SizeBasedGauge) Observe() {
|
||||||
g.gauge.WithLabelValues(strconv.Itoa(log2)).Set(float64(value))
|
g.gauge.WithLabelValues(strconv.Itoa(log2)).Set(float64(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add increases the counter for the given VPA size and VPA update mode.
|
||||||
|
func (g *UpdateModeAndSizeBasedGauge) Add(vpaSize int, vpaUpdateMode vpa_types.UpdateMode, value int) {
|
||||||
|
log2 := metrics.GetVpaSizeLog2(vpaSize)
|
||||||
|
g.values[log2][vpaUpdateMode] += value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observe stores the recorded values into metrics object associated with the
|
||||||
|
// wrapper
|
||||||
|
func (g *UpdateModeAndSizeBasedGauge) Observe() {
|
||||||
|
for log2, valueMap := range g.values {
|
||||||
|
for vpaMode, value := range valueMap {
|
||||||
|
g.gauge.WithLabelValues(strconv.Itoa(log2), string(vpaMode)).Set(float64(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,297 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package updater
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/testutil"
|
||||||
|
|
||||||
|
vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddEvictedPod(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
vpaSize int
|
||||||
|
mode vpa_types.UpdateMode
|
||||||
|
log2 string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "VPA size 5, mode Auto",
|
||||||
|
vpaSize: 5,
|
||||||
|
mode: vpa_types.UpdateModeAuto,
|
||||||
|
log2: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "VPA size 10, mode Off",
|
||||||
|
vpaSize: 10,
|
||||||
|
mode: vpa_types.UpdateModeOff,
|
||||||
|
log2: "3",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
t.Cleanup(evictedCount.Reset)
|
||||||
|
AddEvictedPod(tc.vpaSize, tc.mode)
|
||||||
|
val := testutil.ToFloat64(evictedCount.WithLabelValues(tc.log2, string(tc.mode)))
|
||||||
|
if val != 1 {
|
||||||
|
t.Errorf("Unexpected value for evictedCount metric with labels (%s, %s): got %v, want 1", tc.log2, string(tc.mode), val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddInPlaceUpdatedPod(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
vpaSize int
|
||||||
|
log2 string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "VPA size 10",
|
||||||
|
vpaSize: 10,
|
||||||
|
log2: "3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "VPA size 1",
|
||||||
|
vpaSize: 1,
|
||||||
|
log2: "0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
t.Cleanup(inPlaceUpdatedCount.Reset)
|
||||||
|
AddInPlaceUpdatedPod(tc.vpaSize)
|
||||||
|
val := testutil.ToFloat64(inPlaceUpdatedCount.WithLabelValues(tc.log2))
|
||||||
|
if val != 1 {
|
||||||
|
t.Errorf("Unexpected value for InPlaceUpdatedPod metric with labels (%s): got %v, want 1", tc.log2, val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRecordFailedInPlaceUpdate(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
vpaSize int
|
||||||
|
reason string
|
||||||
|
log2 string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "VPA size 2, some reason",
|
||||||
|
vpaSize: 2,
|
||||||
|
reason: "some_reason",
|
||||||
|
log2: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "VPA size 20, another reason",
|
||||||
|
vpaSize: 20,
|
||||||
|
reason: "another_reason",
|
||||||
|
log2: "4",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
t.Cleanup(failedInPlaceUpdateAttempts.Reset)
|
||||||
|
RecordFailedInPlaceUpdate(tc.vpaSize, tc.reason)
|
||||||
|
val := testutil.ToFloat64(failedInPlaceUpdateAttempts.WithLabelValues(tc.log2, tc.reason))
|
||||||
|
if val != 1 {
|
||||||
|
t.Errorf("Unexpected value for FailedInPlaceUpdate metric with labels (%s, %s): got %v, want 1", tc.log2, tc.reason, val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateModeAndSizeBasedGauge(t *testing.T) {
|
||||||
|
type addition struct {
|
||||||
|
vpaSize int
|
||||||
|
mode vpa_types.UpdateMode
|
||||||
|
value int
|
||||||
|
}
|
||||||
|
type expectation struct {
|
||||||
|
labels []string
|
||||||
|
value float64
|
||||||
|
}
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
newCounter func() *UpdateModeAndSizeBasedGauge
|
||||||
|
metric *prometheus.GaugeVec
|
||||||
|
metricName string
|
||||||
|
additions []addition
|
||||||
|
expectedMetrics []expectation
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "ControlledPodsCounter",
|
||||||
|
newCounter: NewControlledPodsCounter,
|
||||||
|
metric: controlledCount,
|
||||||
|
metricName: "vpa_updater_controlled_pods_total",
|
||||||
|
additions: []addition{
|
||||||
|
{1, vpa_types.UpdateModeAuto, 5},
|
||||||
|
{2, vpa_types.UpdateModeOff, 10},
|
||||||
|
{2, vpa_types.UpdateModeAuto, 2},
|
||||||
|
{2, vpa_types.UpdateModeAuto, 7},
|
||||||
|
},
|
||||||
|
expectedMetrics: []expectation{
|
||||||
|
{[]string{"0" /* log2(1) */, "Auto"}, 5},
|
||||||
|
{[]string{"1" /* log2(2) */, "Auto"}, 9},
|
||||||
|
{[]string{"1" /* log2(2) */, "Off"}, 10},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "EvictablePodsCounter",
|
||||||
|
newCounter: NewEvictablePodsCounter,
|
||||||
|
metric: evictableCount,
|
||||||
|
metricName: "vpa_updater_evictable_pods_total",
|
||||||
|
additions: []addition{
|
||||||
|
{4, vpa_types.UpdateModeAuto, 3},
|
||||||
|
{1, vpa_types.UpdateModeRecreate, 8},
|
||||||
|
},
|
||||||
|
expectedMetrics: []expectation{
|
||||||
|
{[]string{"2" /* log2(4) */, "Auto"}, 3},
|
||||||
|
{[]string{"0" /* log2(1) */, "Recreate"}, 8},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "VpasWithEvictablePodsCounter",
|
||||||
|
newCounter: NewVpasWithEvictablePodsCounter,
|
||||||
|
metric: vpasWithEvictablePodsCount,
|
||||||
|
metricName: "vpa_updater_vpas_with_evictable_pods_total",
|
||||||
|
additions: []addition{
|
||||||
|
{1, vpa_types.UpdateModeOff, 1},
|
||||||
|
{2, vpa_types.UpdateModeAuto, 1},
|
||||||
|
},
|
||||||
|
expectedMetrics: []expectation{
|
||||||
|
{[]string{"0" /* log2(1) */, "Off"}, 1},
|
||||||
|
{[]string{"1" /* log2(2) */, "Auto"}, 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "VpasWithEvictedPodsCounter",
|
||||||
|
newCounter: NewVpasWithEvictedPodsCounter,
|
||||||
|
metric: vpasWithEvictedPodsCount,
|
||||||
|
metricName: "vpa_updater_vpas_with_evicted_pods_total",
|
||||||
|
additions: []addition{
|
||||||
|
{1, vpa_types.UpdateModeAuto, 2},
|
||||||
|
{1, vpa_types.UpdateModeAuto, 3},
|
||||||
|
},
|
||||||
|
expectedMetrics: []expectation{
|
||||||
|
{[]string{"0" /* log2(1) */, "Auto"}, 5},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
t.Cleanup(tc.metric.Reset)
|
||||||
|
counter := tc.newCounter()
|
||||||
|
for _, add := range tc.additions {
|
||||||
|
counter.Add(add.vpaSize, add.mode, add.value)
|
||||||
|
}
|
||||||
|
counter.Observe()
|
||||||
|
for _, expected := range tc.expectedMetrics {
|
||||||
|
val := testutil.ToFloat64(tc.metric.WithLabelValues(expected.labels...))
|
||||||
|
if val != expected.value {
|
||||||
|
t.Errorf("Unexpected value for metric %s with labels %v: got %v, want %v", tc.metricName, expected.labels, val, expected.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSizeBasedGauge(t *testing.T) {
|
||||||
|
type addition struct {
|
||||||
|
vpaSize int
|
||||||
|
value int
|
||||||
|
}
|
||||||
|
type expectation struct {
|
||||||
|
labels []string
|
||||||
|
value float64
|
||||||
|
}
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
newCounter func() *SizeBasedGauge
|
||||||
|
metric *prometheus.GaugeVec
|
||||||
|
metricName string
|
||||||
|
additions []addition
|
||||||
|
expectedMetrics []expectation
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "InPlaceUpdatablePodsCounter",
|
||||||
|
newCounter: NewInPlaceUpdatablePodsCounter,
|
||||||
|
metric: inPlaceUpdatableCount,
|
||||||
|
metricName: "vpa_updater_in_place_updatable_pods_total",
|
||||||
|
additions: []addition{
|
||||||
|
{1, 5},
|
||||||
|
{2, 10},
|
||||||
|
},
|
||||||
|
expectedMetrics: []expectation{
|
||||||
|
{[]string{"0" /* log2(1) */}, 5},
|
||||||
|
{[]string{"1" /* log2(2) */}, 10},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "VpasWithInPlaceUpdatablePodsCounter",
|
||||||
|
newCounter: NewVpasWithInPlaceUpdatablePodsCounter,
|
||||||
|
metric: vpasWithInPlaceUpdatablePodsCount,
|
||||||
|
metricName: "vpa_updater_vpas_with_in_place_updatable_pods_total",
|
||||||
|
additions: []addition{
|
||||||
|
{10, 1},
|
||||||
|
{20, 1},
|
||||||
|
},
|
||||||
|
expectedMetrics: []expectation{
|
||||||
|
{[]string{"3" /* log2(10) */}, 1},
|
||||||
|
{[]string{"4" /* log2(20) */}, 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "VpasWithInPlaceUpdatedPodsCounter",
|
||||||
|
newCounter: NewVpasWithInPlaceUpdatedPodsCounter,
|
||||||
|
metric: vpasWithInPlaceUpdatedPodsCount,
|
||||||
|
metricName: "vpa_updater_vpas_with_in_place_updated_pods_total",
|
||||||
|
additions: []addition{
|
||||||
|
{2, 4},
|
||||||
|
{4, 5},
|
||||||
|
},
|
||||||
|
expectedMetrics: []expectation{
|
||||||
|
{[]string{"1" /* log2(2) */}, 4},
|
||||||
|
{[]string{"2" /* log2(4) */}, 5},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
t.Cleanup(tc.metric.Reset)
|
||||||
|
counter := tc.newCounter()
|
||||||
|
for _, add := range tc.additions {
|
||||||
|
counter.Add(add.vpaSize, add.value)
|
||||||
|
}
|
||||||
|
counter.Observe()
|
||||||
|
for _, expected := range tc.expectedMetrics {
|
||||||
|
val := testutil.ToFloat64(tc.metric.WithLabelValues(expected.labels...))
|
||||||
|
if val != expected.value {
|
||||||
|
t.Errorf("Unexpected value for metric %s with labels %v: got %v, want %v", tc.metricName, expected.labels, val, expected.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -200,6 +200,36 @@ func (m *VerticalPodAutoscalerListerMock) Get(name string) (*vpa_types.VerticalP
|
||||||
return nil, fmt.Errorf("unimplemented")
|
return nil, fmt.Errorf("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerticalPodAutoscalerCheckPointListerMock is a mock of VerticalPodAutoscalerCheckPointLister
|
||||||
|
type VerticalPodAutoscalerCheckPointListerMock struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// List is a mock implementation of VerticalPodAutoscalerLister.List
|
||||||
|
func (m *VerticalPodAutoscalerCheckPointListerMock) List(selector labels.Selector) (ret []*vpa_types.VerticalPodAutoscalerCheckpoint, err error) {
|
||||||
|
args := m.Called()
|
||||||
|
var returnArg []*vpa_types.VerticalPodAutoscalerCheckpoint
|
||||||
|
if args.Get(0) != nil {
|
||||||
|
returnArg = args.Get(0).([]*vpa_types.VerticalPodAutoscalerCheckpoint)
|
||||||
|
}
|
||||||
|
return returnArg, args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerticalPodAutoscalerCheckpoints is a mock implementation of returning a lister for namespace.
|
||||||
|
func (m *VerticalPodAutoscalerCheckPointListerMock) VerticalPodAutoscalerCheckpoints(namespace string) vpa_lister.VerticalPodAutoscalerCheckpointNamespaceLister {
|
||||||
|
args := m.Called(namespace)
|
||||||
|
var returnArg vpa_lister.VerticalPodAutoscalerCheckpointNamespaceLister
|
||||||
|
if args.Get(0) != nil {
|
||||||
|
returnArg = args.Get(0).(vpa_lister.VerticalPodAutoscalerCheckpointNamespaceLister)
|
||||||
|
}
|
||||||
|
return returnArg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get is not implemented for this mock
|
||||||
|
func (m *VerticalPodAutoscalerCheckPointListerMock) Get(name string) (*vpa_types.VerticalPodAutoscalerCheckpoint, error) {
|
||||||
|
return nil, fmt.Errorf("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
// VerticalPodAutoscalerV1Beta1ListerMock is a mock of VerticalPodAutoscalerLister or
|
// VerticalPodAutoscalerV1Beta1ListerMock is a mock of VerticalPodAutoscalerLister or
|
||||||
// VerticalPodAutoscalerNamespaceLister - the crucial List method is the same.
|
// VerticalPodAutoscalerNamespaceLister - the crucial List method is the same.
|
||||||
type VerticalPodAutoscalerV1Beta1ListerMock struct {
|
type VerticalPodAutoscalerV1Beta1ListerMock struct {
|
||||||
|
|
|
@ -107,6 +107,36 @@ func NewVpasLister(vpaClient *vpa_clientset.Clientset, stopChannel <-chan struct
|
||||||
return vpaLister
|
return vpaLister
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewVpaCheckpointLister returns VerticalPodAutoscalerCheckpointLister configured to fetch all VPACheckpoint objects from namespace,
|
||||||
|
// set namespace to k8sapiv1.NamespaceAll to select all namespaces.
|
||||||
|
// The method blocks until vpaCheckpointLister is initially populated.
|
||||||
|
func NewVpaCheckpointLister(vpaClient *vpa_clientset.Clientset, stopChannel <-chan struct{}, namespace string) vpa_lister.VerticalPodAutoscalerCheckpointLister {
|
||||||
|
vpaListWatch := cache.NewListWatchFromClient(vpaClient.AutoscalingV1().RESTClient(), "verticalpodautoscalercheckpoints", namespace, fields.Everything())
|
||||||
|
informerOptions := cache.InformerOptions{
|
||||||
|
ObjectType: &vpa_types.VerticalPodAutoscalerCheckpoint{},
|
||||||
|
ListerWatcher: vpaListWatch,
|
||||||
|
Handler: &cache.ResourceEventHandlerFuncs{},
|
||||||
|
ResyncPeriod: 1 * time.Hour,
|
||||||
|
Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
|
||||||
|
}
|
||||||
|
|
||||||
|
store, controller := cache.NewInformerWithOptions(informerOptions)
|
||||||
|
indexer, ok := store.(cache.Indexer)
|
||||||
|
if !ok {
|
||||||
|
klog.ErrorS(nil, "Expected Indexer, but got a Store that does not implement Indexer")
|
||||||
|
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||||
|
}
|
||||||
|
vpaCheckpointLister := vpa_lister.NewVerticalPodAutoscalerCheckpointLister(indexer)
|
||||||
|
go controller.Run(stopChannel)
|
||||||
|
if !cache.WaitForCacheSync(stopChannel, controller.HasSynced) {
|
||||||
|
klog.ErrorS(nil, "Failed to sync VPA checkpoint cache during initialization")
|
||||||
|
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||||
|
} else {
|
||||||
|
klog.InfoS("Initial VPA checkpoint synced successfully")
|
||||||
|
}
|
||||||
|
return vpaCheckpointLister
|
||||||
|
}
|
||||||
|
|
||||||
// PodMatchesVPA returns true iff the vpaWithSelector matches the Pod.
|
// PodMatchesVPA returns true iff the vpaWithSelector matches the Pod.
|
||||||
func PodMatchesVPA(pod *core.Pod, vpaWithSelector *VpaWithSelector) bool {
|
func PodMatchesVPA(pod *core.Pod, vpaWithSelector *VpaWithSelector) bool {
|
||||||
return PodLabelsMatchVPA(pod.Namespace, labels.Set(pod.GetLabels()), vpaWithSelector.Vpa.Namespace, vpaWithSelector.Selector)
|
return PodLabelsMatchVPA(pod.Namespace, labels.Set(pod.GetLabels()), vpaWithSelector.Vpa.Namespace, vpaWithSelector.Selector)
|
||||||
|
|
Loading…
Reference in New Issue