fix(go): add golangci-lint (#525)

This commit is contained in:
Antoine Lecompte
2026-08-21 13:55:25 +00:00
committed by GitHub
parent 359a227645
commit 55488d6818
36 changed files with 162 additions and 264 deletions
+27
View File
@@ -0,0 +1,27 @@
version: '2'
issues:
max-issues-per-linter: 0
max-same-issues: 0
linters:
settings:
errcheck:
# Best-effort writes and teardown where the error carries no signal:
# CLI/tabwriter output, and Close on response bodies, files, listeners.
exclude-functions:
- fmt.Fprint
- fmt.Fprintf
- fmt.Fprintln
- (io.Closer).Close
- (*os.File).Close
- (net.Listener).Close
- (*net/http.Server).Close
- (*text/tabwriter.Writer).Flush
exclusions:
rules:
# SA4023 sees only the !embedagent stub of embeddedAgent (the embedagent
# variant needs the gitignored bench-agent artifact) and wrongly concludes
# its error is always non-nil.
- path: resticbench/orchestrator\.go
text: 'SA4023'
+3 -2
View File
@@ -1,7 +1,8 @@
[tools] [tools]
node = "25.9.0" node = "25.9.0"
pnpm = "10.28.1" pnpm = "10.28.1"
go = "1.26.5" go = "1.27.0"
golangci-lint = "2.13.1"
restic = "0.19.1" restic = "0.19.1"
gh = "2.25.0" gh = "2.25.0"
@@ -66,7 +67,7 @@ run = [{ task = "install:frozen" }, { task = "build" }]
[tasks."check"] [tasks."check"]
description = "Run checks & unit tests" description = "Run checks & unit tests"
run = [{ tasks = ["lint", "*:check"] }, { task = "format" }, { task = "test" }] run = [{ tasks = ["lint", "lint:go", "*:check"] }, { task = "format" }, { task = "test" }]
[tasks.fix] [tasks.fix]
description = "Run all possible code fixes" description = "Run all possible code fixes"
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
#MISE description="Lint Go packages with golangci-lint"
set -e
status=0
for pkg in michael yuctl; do
(cd "packages/$pkg" && golangci-lint run ./... "$@") || status=1
done
exit $status
+2 -2
View File
@@ -5,7 +5,7 @@ ARG ALPINE_VERSION=3.23
# be appended to the node/golang base tags (which reuse ${ALPINE_VERSION}). # be appended to the node/golang base tags (which reuse ${ALPINE_VERSION}).
ARG ALPINE_IMAGE=alpine:3.23@sha256:fd791d74b68913cbb027c6546007b3f0d3bc45125f797758156952bc2d6daf40 ARG ALPINE_IMAGE=alpine:3.23@sha256:fd791d74b68913cbb027c6546007b3f0d3bc45125f797758156952bc2d6daf40
FROM golang:1.25-alpine${ALPINE_VERSION} AS dev FROM golang:1.27-alpine${ALPINE_VERSION} AS dev
WORKDIR /src WORKDIR /src
# air is pinned: @latest broke the build when v1.67.2 started requiring a newer # air is pinned: @latest broke the build when v1.67.2 started requiring a newer
# Go than this base image ships (bump air and the golang tag together). # Go than this base image ships (bump air and the golang tag together).
@@ -17,7 +17,7 @@ COPY packages/michael/ ./
EXPOSE 3010 EXPOSE 3010
CMD ["air", "-c", ".air.toml"] CMD ["air", "-c", ".air.toml"]
FROM golang:1.25-alpine${ALPINE_VERSION} AS builder FROM golang:1.27-alpine${ALPINE_VERSION} AS builder
WORKDIR /app WORKDIR /app
COPY packages/michael/go.mod packages/michael/go.sum ./ COPY packages/michael/go.mod packages/michael/go.sum ./
+1 -1
View File
@@ -1,6 +1,6 @@
module michael module michael
go 1.25.0 go 1.27.0
require ( require (
github.com/aws/aws-sdk-go-v2 v1.43.3 github.com/aws/aws-sdk-go-v2 v1.43.3
+6 -80
View File
@@ -1,60 +1,33 @@
github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY=
github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
github.com/aws/aws-sdk-go-v2 v1.43.3 h1:XJIcfv8uDs2ukdQsoAC8/Ebu1ejxwzlayl2ZsiFns2A= github.com/aws/aws-sdk-go-v2 v1.43.3 h1:XJIcfv8uDs2ukdQsoAC8/Ebu1ejxwzlayl2ZsiFns2A=
github.com/aws/aws-sdk-go-v2 v1.43.3/go.mod h1:70vwSy16txshwG+g55WkpgPKDIByzHI8ccBsOteo3bQ= github.com/aws/aws-sdk-go-v2 v1.43.3/go.mod h1:70vwSy16txshwG+g55WkpgPKDIByzHI8ccBsOteo3bQ=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 h1:eBMB84YGghSocM7PsjmmPffTa+1FBUeNvGvFou6V/4o=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16 h1:aiuaKlDweRC5qExJondpWjOgyzMHpofpwspGXUtwn4c= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16 h1:aiuaKlDweRC5qExJondpWjOgyzMHpofpwspGXUtwn4c=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16/go.mod h1:nG/LOlmox9BDe9HvQnXWzgcK8uKbgBMZ/Hp5pVt/21I= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16/go.mod h1:nG/LOlmox9BDe9HvQnXWzgcK8uKbgBMZ/Hp5pVt/21I=
github.com/aws/aws-sdk-go-v2/credentials v1.19.10 h1:EEhmEUFCE1Yhl7vDhNOI5OCL/iKMdkkYFTRpZXNw7m8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.10/go.mod h1:RnnlFCAlxQCkN2Q379B67USkBMu1PipEEiibzYN5UTE=
github.com/aws/aws-sdk-go-v2/credentials v1.19.33 h1:/e5V3EWfeDiW6cuRxHsC8gbwko4/vvVYPJR2afBKFFY= github.com/aws/aws-sdk-go-v2/credentials v1.19.33 h1:/e5V3EWfeDiW6cuRxHsC8gbwko4/vvVYPJR2afBKFFY=
github.com/aws/aws-sdk-go-v2/credentials v1.19.33/go.mod h1:ZxAmkcyOM9beY/WO9oxp2oVPXiP3rq5N1/p4NbenJdE= github.com/aws/aws-sdk-go-v2/credentials v1.19.33/go.mod h1:ZxAmkcyOM9beY/WO9oxp2oVPXiP3rq5N1/p4NbenJdE=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34 h1:vuIfjzoeqhQMGJyOBU3t0ZEjn2jrN8Bbg1N4CgjzM5Q= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34 h1:vuIfjzoeqhQMGJyOBU3t0ZEjn2jrN8Bbg1N4CgjzM5Q=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34/go.mod h1:hP28cN4CPJLZHirdQPrZR50JcLN4ApRJP2tzG8cRlhY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34/go.mod h1:hP28cN4CPJLZHirdQPrZR50JcLN4ApRJP2tzG8cRlhY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34 h1:9faHsnqxJ1vDvB4wMZy/ajIDyz5QhllQjjc72RJpXAw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34 h1:9faHsnqxJ1vDvB4wMZy/ajIDyz5QhllQjjc72RJpXAw=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34/go.mod h1:Yp6nIyejpa23nzlB/LhT63KTla9Jdi06nv/HH/OkAH8= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34/go.mod h1:Yp6nIyejpa23nzlB/LhT63KTla9Jdi06nv/HH/OkAH8=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22 h1:rWyie/PxDRIdhNf4DzRk0lvjVOqFJuNnO8WwaIRVxzQ=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22/go.mod h1:zd/JsJ4P7oGfUhXn1VyLqaRZwPmZwg44Jf2dS84Dm3Y=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35 h1:Oe8gMKJLO5awqpa5EhAGKVnBv1s+brdWVuxM2mDa7zA= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35 h1:Oe8gMKJLO5awqpa5EhAGKVnBv1s+brdWVuxM2mDa7zA=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35/go.mod h1:FZevcG9cOST/FWAAUhHIchjR9fXFXFRCWodOhx+PDLA= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35/go.mod h1:FZevcG9cOST/FWAAUhHIchjR9fXFXFRCWodOhx+PDLA=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 h1:JJLBQxwY+AFwuPAi5ivGc1ChnTdUt4cXMv7e76m2c/Y= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 h1:JJLBQxwY+AFwuPAi5ivGc1ChnTdUt4cXMv7e76m2c/Y=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15/go.mod h1:lQknBIe78MVL0cQOQDlag8KGflMbMEVFx9mB6O8ENvk= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15/go.mod h1:lQknBIe78MVL0cQOQDlag8KGflMbMEVFx9mB6O8ENvk=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13 h1:JRaIgADQS/U6uXDqlPiefP32yXTda7Kqfx+LgspooZM=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13/go.mod h1:CEuVn5WqOMilYl+tbccq8+N2ieCy0gVn3OtRb0vBNNM=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27 h1:zwB6ltUc0UiyOsRQaMQ8jNLjKECbjhadCyl4hqV0y/c= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27 h1:zwB6ltUc0UiyOsRQaMQ8jNLjKECbjhadCyl4hqV0y/c=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27/go.mod h1:ce9y+Y+hGLUyPKJZZJGoFLuFJNfCNuWZTujUJAsckQA= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27/go.mod h1:ce9y+Y+hGLUyPKJZZJGoFLuFJNfCNuWZTujUJAsckQA=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 h1:c31//R3xgIJMSC8S6hEVq+38DcvUlgFY0FM6mSI5oto=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34 h1:sYg4qHWLqsjp15PzX7XCOHSOgKEGoZ5vQY43VvZ1pas= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34 h1:sYg4qHWLqsjp15PzX7XCOHSOgKEGoZ5vQY43VvZ1pas=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34/go.mod h1:N58SSz3roKf1HzW5qRaOiyk6MbDLTKgLPvlTfJ90iyI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34/go.mod h1:N58SSz3roKf1HzW5qRaOiyk6MbDLTKgLPvlTfJ90iyI=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21 h1:ZlvrNcHSFFWURB8avufQq9gFsheUgjVD9536obIknfM=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21/go.mod h1:cv3TNhVrssKR0O/xxLJVRfd2oazSnZnkUeTf6ctUwfQ=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35 h1:ohfdSAm4TA6nryIY7mLqe4mnSIAnAreoAPBM81ZVoIM= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35 h1:ohfdSAm4TA6nryIY7mLqe4mnSIAnAreoAPBM81ZVoIM=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35/go.mod h1:uUjphnxMb3HH3vIiOHl4dH0fGNKL+csjqRQEabbfw5k= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35/go.mod h1:uUjphnxMb3HH3vIiOHl4dH0fGNKL+csjqRQEabbfw5k=
github.com/aws/aws-sdk-go-v2/service/s3 v1.97.3 h1:HwxWTbTrIHm5qY+CAEur0s/figc3qwvLWsNkF4RPToo=
github.com/aws/aws-sdk-go-v2/service/s3 v1.97.3/go.mod h1:uoA43SdFwacedBfSgfFSjjCvYe8aYBS7EnU5GZ/YKMM=
github.com/aws/aws-sdk-go-v2/service/s3 v1.106.3 h1:oSfubHEP3a0nTRAtm99IDaws0f15qwf+fOwS1Esh5jI= github.com/aws/aws-sdk-go-v2/service/s3 v1.106.3 h1:oSfubHEP3a0nTRAtm99IDaws0f15qwf+fOwS1Esh5jI=
github.com/aws/aws-sdk-go-v2/service/s3 v1.106.3/go.mod h1:lWk6L5Q3YkaC7so1bQUJkvF7hj2KUFzdZ4w15wc2GHY= github.com/aws/aws-sdk-go-v2/service/s3 v1.106.3/go.mod h1:lWk6L5Q3YkaC7so1bQUJkvF7hj2KUFzdZ4w15wc2GHY=
github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng=
github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/aws/smithy-go v1.27.6 h1:0zjT8jgK3jbrTT7JJ3EE6JsMhX8JTrZ+f1sEndYDXrA= github.com/aws/smithy-go v1.27.6 h1:0zjT8jgK3jbrTT7JJ3EE6JsMhX8JTrZ+f1sEndYDXrA=
github.com/aws/smithy-go v1.27.6/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/aws/smithy-go v1.27.6/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-chi/chi/v5 v5.3.1 h1:3j4HZLGZQ3JpMCrPJF/Jl3mYJfWLKBfNJ6quurUGCf8= github.com/go-chi/chi/v5 v5.3.1 h1:3j4HZLGZQ3JpMCrPJF/Jl3mYJfWLKBfNJ6quurUGCf8=
github.com/go-chi/chi/v5 v5.3.1/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto= github.com/go-chi/chi/v5 v5.3.1/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -62,7 +35,6 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3/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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -73,105 +45,59 @@ 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/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
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.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/oschwald/maxminddb-golang/v2 v2.4.1 h1:OffzqSABE3Sw354GdBThqDsKfpA4GWBqOY2P91V8tjI= github.com/oschwald/maxminddb-golang/v2 v2.4.1 h1:OffzqSABE3Sw354GdBThqDsKfpA4GWBqOY2P91V8tjI=
github.com/oschwald/maxminddb-golang/v2 v2.4.1/go.mod h1:CZK8iQQMKfy6mKOifoyUmrj4vTHnMiGVaS7hDaZZxQ0= github.com/oschwald/maxminddb-golang/v2 v2.4.1/go.mod h1:CZK8iQQMKfy6mKOifoyUmrj4vTHnMiGVaS7hDaZZxQ0=
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 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/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI= github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI=
github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0 h1:icqq3Z34UrEFk2u+HMhTtRsvo7Ues+eiJVjaJt62njs=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0/go.mod h1:W2m8P+d5Wn5kipj4/xmbt9uMqezEKfBjzVJadfABSBE=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 h1:HIBTQ3VO5aupLKjC90JgMqpezVXwFuq6Ryjn0/izoag= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 h1:HIBTQ3VO5aupLKjC90JgMqpezVXwFuq6Ryjn0/izoag=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0/go.mod h1:ji9vId85hMxqfvICA0Jt8JqEdrXaAkcpkI9HPXya0ro= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0/go.mod h1:ji9vId85hMxqfvICA0Jt8JqEdrXaAkcpkI9HPXya0ro=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0 h1:MMrOAN8H1FrvDyq9UJ4lu5/+ss49Qgfgb7Zpm0m8ABo= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0 h1:MMrOAN8H1FrvDyq9UJ4lu5/+ss49Qgfgb7Zpm0m8ABo=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0/go.mod h1:Na+2NNASJtF+uT4NxDe0G+NQb+bUgdPDfwxY/6JmS/c= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0/go.mod h1:Na+2NNASJtF+uT4NxDe0G+NQb+bUgdPDfwxY/6JmS/c=
go.opentelemetry.io/otel/log v0.18.0 h1:XgeQIIBjZZrliksMEbcwMZefoOSMI1hdjiLEiiB0bAg=
go.opentelemetry.io/otel/log v0.18.0/go.mod h1:KEV1kad0NofR3ycsiDH4Yjcoj0+8206I6Ox2QYFSNgI=
go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4= go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4=
go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk= go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk=
go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=
go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= go.opentelemetry.io/otel/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA=
go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk=
go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
go.opentelemetry.io/otel/sdk/log v0.18.0 h1:n8OyZr7t7otkeTnPTbDNom6rW16TBYGtvyy2Gk6buQw=
go.opentelemetry.io/otel/sdk/log v0.18.0/go.mod h1:C0+wxkTwKpOCZLrlJ3pewPiiQwpzycPI/u6W0Z9fuYk=
go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko= go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko=
go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg= go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg=
go.opentelemetry.io/otel/sdk/log/logtest v0.18.0 h1:l3mYuPsuBx6UKE47BVcPrZoZ0q/KER57vbj2qkgDLXA= go.opentelemetry.io/otel/sdk/log/logtest v0.19.0 h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk=
go.opentelemetry.io/otel/sdk/log/logtest v0.18.0/go.mod h1:7cHtiVJpZebB3wybTa4NG+FUo5NPe3PROz1FqB0+qdw= go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk=
go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA=
go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=
go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=
go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0=
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY=
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA=
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
+6 -6
View File
@@ -36,13 +36,13 @@ const (
func integrationConfig() config.Config { func integrationConfig() config.Config {
return config.Config{ return config.Config{
Port: 3010, Port: 3010,
JWTPublicKey: testPublicKey, JWTPublicKey: testPublicKey,
S3AccessKeyID: envOrDefault("S3_ACCESS_KEY_ID", "minio"), S3AccessKeyID: envOrDefault("S3_ACCESS_KEY_ID", "minio"),
S3SecretAccessKey: envOrDefault("S3_SECRET_ACCESS_KEY", "miniominio"), S3SecretAccessKey: envOrDefault("S3_SECRET_ACCESS_KEY", "miniominio"),
S3Region: envOrDefault("S3_REGION", "minio"), S3Region: envOrDefault("S3_REGION", "minio"),
S3Endpoint: envOrDefault("S3_ENDPOINT", "http://localhost:9000"), S3Endpoint: envOrDefault("S3_ENDPOINT", "http://localhost:9000"),
S3ForcePathStyle: true, S3ForcePathStyle: true,
} }
} }
+5 -4
View File
@@ -10,6 +10,7 @@ import (
"net" "net"
"net/http" "net/http"
"net/netip" "net/netip"
"slices"
"strconv" "strconv"
"strings" "strings"
@@ -140,10 +141,10 @@ func isPrivate(addr netip.Addr) bool {
func ClientAddr(r *http.Request, header string) netip.Addr { func ClientAddr(r *http.Request, header string) netip.Addr {
if header != "" { if header != "" {
values := r.Header.Values(header) values := r.Header.Values(header)
for i := len(values) - 1; i >= 0; i-- { for _, value := range slices.Backward(values) {
entries := strings.Split(values[i], ",") entries := strings.Split(value, ",")
for j := len(entries) - 1; j >= 0; j-- { for _, entrie := range slices.Backward(entries) {
if addr, ok := parseAddr(entries[j]); ok { if addr, ok := parseAddr(entrie); ok {
return addr return addr
} }
} }
@@ -174,7 +174,7 @@ func TestResolve(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Open: %v", err) t.Fatalf("Open: %v", err)
} }
defer db.Close() defer func() { _ = db.Close() }()
r := httptest.NewRequest(http.MethodGet, "/repo/data/abc", nil) r := httptest.NewRequest(http.MethodGet, "/repo/data/abc", nil)
r.RemoteAddr = "10.0.0.1:1234" r.RemoteAddr = "10.0.0.1:1234"
@@ -137,7 +137,7 @@ func TestClusterRoutingUnknownClusterRejected(t *testing.T) {
t.Errorf("a known cluster served a request for an unknown one (default=%d spice=%d)", def.hits, spice.hits) t.Errorf("a known cluster served a request for an unknown one (default=%d spice=%d)", def.hits, spice.hits)
} }
warn := findLog(parseLogLines(t, buf), map[string]interface{}{"level": "warn", "cluster": "sietch"}) warn := findLog(parseLogLines(t, buf), map[string]any{"level": "warn", "cluster": "sietch"})
if warn == nil { if warn == nil {
t.Fatalf("no warn log for the unknown cluster:\n%s", buf.String()) t.Fatalf("no warn log for the unknown cluster:\n%s", buf.String())
} }
@@ -177,14 +177,14 @@ func wormAuth() auth.Auth {
} }
// parseLogLines parses JSON log output into a slice of maps. // parseLogLines parses JSON log output into a slice of maps.
func parseLogLines(t *testing.T, buf *bytes.Buffer) []map[string]interface{} { func parseLogLines(t *testing.T, buf *bytes.Buffer) []map[string]any {
t.Helper() t.Helper()
var entries []map[string]interface{} var entries []map[string]any
for _, line := range bytes.Split(bytes.TrimSpace(buf.Bytes()), []byte("\n")) { for line := range bytes.SplitSeq(bytes.TrimSpace(buf.Bytes()), []byte("\n")) {
if len(line) == 0 { if len(line) == 0 {
continue continue
} }
var entry map[string]interface{} var entry map[string]any
if err := json.Unmarshal(line, &entry); err != nil { if err := json.Unmarshal(line, &entry); err != nil {
t.Fatalf("log line is not valid JSON: %s", line) t.Fatalf("log line is not valid JSON: %s", line)
} }
@@ -194,7 +194,7 @@ func parseLogLines(t *testing.T, buf *bytes.Buffer) []map[string]interface{} {
} }
// findLog returns the first log entry matching all given field values. // findLog returns the first log entry matching all given field values.
func findLog(entries []map[string]interface{}, match map[string]interface{}) map[string]interface{} { func findLog(entries []map[string]any, match map[string]any) map[string]any {
for _, e := range entries { for _, e := range entries {
hit := true hit := true
for k, v := range match { for k, v := range match {
@@ -238,7 +238,7 @@ func TestAccessLogOutput(t *testing.T) {
} }
entries := parseLogLines(t, buf) entries := parseLogLines(t, buf)
accessLog := findLog(entries, map[string]interface{}{"status": float64(http.StatusOK)}) accessLog := findLog(entries, map[string]any{"status": float64(http.StatusOK)})
if accessLog == nil { if accessLog == nil {
t.Fatalf("no access log entry found in output:\n%s", buf.String()) t.Fatalf("no access log entry found in output:\n%s", buf.String())
} }
@@ -277,7 +277,7 @@ func TestErrorLogOutput(t *testing.T) {
entries := parseLogLines(t, buf) entries := parseLogLines(t, buf)
// Should have an error-level log with the error message and request context // Should have an error-level log with the error message and request context
errLog := findLog(entries, map[string]interface{}{"level": "error"}) errLog := findLog(entries, map[string]any{"level": "error"})
if errLog == nil { if errLog == nil {
t.Fatalf("no error log entry found in output:\n%s", buf.String()) t.Fatalf("no error log entry found in output:\n%s", buf.String())
} }
@@ -297,7 +297,7 @@ func TestErrorLogOutput(t *testing.T) {
// Should also have an access log for this failed request, carrying the // Should also have an access log for this failed request, carrying the
// authenticated identity (authLogContext mutates the shared request logger). // authenticated identity (authLogContext mutates the shared request logger).
accessLog := findLog(entries, map[string]interface{}{"status": float64(http.StatusInternalServerError)}) accessLog := findLog(entries, map[string]any{"status": float64(http.StatusInternalServerError)})
if accessLog == nil { if accessLog == nil {
t.Fatalf("no access log entry for the 500 response:\n%s", buf.String()) t.Fatalf("no access log entry for the 500 response:\n%s", buf.String())
} }
@@ -327,7 +327,7 @@ func TestAuthFailureLogOutput(t *testing.T) {
entries := parseLogLines(t, buf) entries := parseLogLines(t, buf)
// Should still get an access log even for auth failures // Should still get an access log even for auth failures
accessLog := findLog(entries, map[string]interface{}{"status": float64(http.StatusUnauthorized)}) accessLog := findLog(entries, map[string]any{"status": float64(http.StatusUnauthorized)})
if accessLog == nil { if accessLog == nil {
t.Fatalf("no access log entry for 401 response:\n%s", buf.String()) t.Fatalf("no access log entry for 401 response:\n%s", buf.String())
} }
@@ -395,7 +395,7 @@ func TestClientNetworkLogOutput(t *testing.T) {
t.Fatalf("expected 401, got %d", rec.Code) t.Fatalf("expected 401, got %d", rec.Code)
} }
accessLog := findLog(parseLogLines(t, buf), map[string]interface{}{"status": float64(http.StatusUnauthorized)}) accessLog := findLog(parseLogLines(t, buf), map[string]any{"status": float64(http.StatusUnauthorized)})
if accessLog == nil { if accessLog == nil {
t.Fatalf("no access log entry for 401 response:\n%s", buf.String()) t.Fatalf("no access log entry for 401 response:\n%s", buf.String())
} }
@@ -258,9 +258,7 @@ func TestClientTrackerEvictionKeepsRequestsAttached(t *testing.T) {
var collectors, requests sync.WaitGroup var collectors, requests sync.WaitGroup
// Collect for as long as requests are arriving, so the two actually overlap. // Collect for as long as requests are arriving, so the two actually overlap.
collectors.Add(1) collectors.Go(func() {
go func() {
defer collectors.Done()
obs := &recordingObserver{} obs := &recordingObserver{}
for { for {
select { select {
@@ -271,20 +269,18 @@ func TestClientTrackerEvictionKeepsRequestsAttached(t *testing.T) {
obs.got = obs.got[:0] obs.got = obs.got[:0]
} }
} }
}() })
for i := 0; i < 4; i++ { for range 4 {
requests.Add(1) requests.Go(func() {
go func() { for range 20000 {
defer requests.Done()
for n := 0; n < 20000; n++ {
state := tr.enter(key) state := tr.enter(key)
if v, ok := tr.states.Load(key); !ok || v.(*clientConcurrency) != state { if v, ok := tr.states.Load(key); !ok || v.(*clientConcurrency) != state {
orphaned.Add(1) orphaned.Add(1)
} }
state.exit(time.Now()) state.exit(time.Now())
} }
}() })
} }
requests.Wait() requests.Wait()
@@ -331,12 +327,10 @@ func TestClientTrackerConcurrentEnterExit(t *testing.T) {
key := clientAttrKey{"u1", "r1", "restic"} key := clientAttrKey{"u1", "r1", "restic"}
var wg sync.WaitGroup var wg sync.WaitGroup
for i := 0; i < 200; i++ { for range 200 {
wg.Add(1) wg.Go(func() {
go func() {
defer wg.Done()
tr.enter(key).exit(time.Now()) tr.enter(key).exit(time.Now())
}() })
} }
wg.Wait() wg.Wait()
@@ -397,12 +397,10 @@ func TestCachedRoutePattern(t *testing.T) {
func TestBlobMetricOptionConcurrency(t *testing.T) { func TestBlobMetricOptionConcurrency(t *testing.T) {
var wg sync.WaitGroup var wg sync.WaitGroup
for i := 0; i < 100; i++ { for range 100 {
wg.Add(1) wg.Go(func() {
go func() {
defer wg.Done()
BlobMetricOption(auth.Auth{User: "u1", Repository: "r1"}, "data") BlobMetricOption(auth.Auth{User: "u1", Repository: "r1"}, "data")
}() })
} }
wg.Wait() wg.Wait()
} }
+1 -1
View File
@@ -63,7 +63,7 @@ func NewOTLPLogWriter(provider *sdklog.LoggerProvider) *OTLPLogWriter {
// Write parses a zerolog JSON line and emits it as an OTEL log record. // Write parses a zerolog JSON line and emits it as an OTEL log record.
func (w *OTLPLogWriter) Write(p []byte) (int, error) { func (w *OTLPLogWriter) Write(p []byte) (int, error) {
var entry map[string]interface{} var entry map[string]any
if err := json.Unmarshal(p, &entry); err != nil { if err := json.Unmarshal(p, &entry); err != nil {
// Not JSON — pass through length but skip OTEL export. // Not JSON — pass through length but skip OTEL export.
return len(p), nil return len(p), nil
+1 -1
View File
@@ -124,7 +124,7 @@ func (p *Pool) Run(ctx context.Context) {
case <-ctx.Done(): case <-ctx.Done():
return return
case <-ticker.C: case <-ticker.C:
p.Reconcile(ctx) _ = p.Reconcile(ctx)
} }
} }
} }
+13 -13
View File
@@ -85,7 +85,7 @@ func (f *fakeStore) GetObject(_ context.Context, _, _, _ string) (*S3Object, err
if f.opFail.Load() { if f.opFail.Load() {
return nil, f.transportErr() return nil, f.transportErr()
} }
var rc io.ReadCloser = io.NopCloser(strings.NewReader(f.getBody)) rc := io.NopCloser(strings.NewReader(f.getBody))
if f.getErr != nil { if f.getErr != nil {
rc = &errReadCloser{data: f.getBody, err: f.getErr} rc = &errReadCloser{data: f.getBody, err: f.getErr}
} }
@@ -226,13 +226,13 @@ func TestPool_EjectAfterThresholdThenReinstate(t *testing.T) {
// Two failures: still healthy (no immediate ejection). // Two failures: still healthy (no immediate ejection).
reg["a"].opFail.Store(true) reg["a"].opFail.Store(true)
p.HeadObject(context.Background(), "bucket", "k") _, _ = p.HeadObject(context.Background(), "bucket", "k")
p.HeadObject(context.Background(), "bucket", "k") _, _ = p.HeadObject(context.Background(), "bucket", "k")
if !b.healthy.Load() { if !b.healthy.Load() {
t.Error("ejected before reaching threshold") t.Error("ejected before reaching threshold")
} }
// Third consecutive failure: ejected. // Third consecutive failure: ejected.
p.HeadObject(context.Background(), "bucket", "k") _, _ = p.HeadObject(context.Background(), "bucket", "k")
if b.healthy.Load() { if b.healthy.Load() {
t.Error("expected ejection after threshold failures") t.Error("expected ejection after threshold failures")
} }
@@ -242,7 +242,7 @@ func TestPool_EjectAfterThresholdThenReinstate(t *testing.T) {
// Active probe reinstates once the backend recovers. // Active probe reinstates once the backend recovers.
reg["a"].opFail.Store(false) reg["a"].opFail.Store(false)
p.Reconcile(context.Background()) _ = p.Reconcile(context.Background())
if !b.healthy.Load() { if !b.healthy.Load() {
t.Error("expected reinstatement after healthy probe") t.Error("expected reinstatement after healthy probe")
} }
@@ -324,7 +324,7 @@ func TestPool_ReconcileAddsAndRemoves(t *testing.T) {
// Remove b, add c. // Remove b, add c.
res.set([]string{"a", "c"}, nil) res.set([]string{"a", "c"}, nil)
p.Reconcile(context.Background()) _ = p.Reconcile(context.Background())
eps := map[string]bool{} eps := map[string]bool{}
for _, b := range p.snapshot() { for _, b := range p.snapshot() {
@@ -346,7 +346,7 @@ func TestPool_ReconcileAddsAndRemoves(t *testing.T) {
func TestPool_ReconcileEjectsViaProbe(t *testing.T) { func TestPool_ReconcileEjectsViaProbe(t *testing.T) {
p, _, reg := newTestPool(t, []string{"a", "b"}, 3) p, _, reg := newTestPool(t, []string{"a", "b"}, 3)
reg["a"].probeFail.Store(true) reg["a"].probeFail.Store(true)
p.Reconcile(context.Background()) _ = p.Reconcile(context.Background())
if backendByEndpoint(p, "a").healthy.Load() { if backendByEndpoint(p, "a").healthy.Load() {
t.Error("'a' should be ejected after failing probe") t.Error("'a' should be ejected after failing probe")
@@ -357,7 +357,7 @@ func TestPool_ReconcileEjectsViaProbe(t *testing.T) {
// Recovery: probe passes again, backend reinstated. // Recovery: probe passes again, backend reinstated.
reg["a"].probeFail.Store(false) reg["a"].probeFail.Store(false)
p.Reconcile(context.Background()) _ = p.Reconcile(context.Background())
if !backendByEndpoint(p, "a").healthy.Load() { if !backendByEndpoint(p, "a").healthy.Load() {
t.Error("'a' should be reinstated after probe recovers") t.Error("'a' should be reinstated after probe recovers")
} }
@@ -366,7 +366,7 @@ func TestPool_ReconcileEjectsViaProbe(t *testing.T) {
func TestPool_ReconcileKeepsSetOnResolverError(t *testing.T) { func TestPool_ReconcileKeepsSetOnResolverError(t *testing.T) {
p, res, _ := newTestPool(t, []string{"a", "b"}, 3) p, res, _ := newTestPool(t, []string{"a", "b"}, 3)
res.set(nil, errors.New("dns down")) res.set(nil, errors.New("dns down"))
p.Reconcile(context.Background()) _ = p.Reconcile(context.Background())
if len(p.snapshot()) != 2 { if len(p.snapshot()) != 2 {
t.Errorf("resolver error should not drain pool; got %d backends", len(p.snapshot())) t.Errorf("resolver error should not drain pool; got %d backends", len(p.snapshot()))
} }
@@ -375,7 +375,7 @@ func TestPool_ReconcileKeepsSetOnResolverError(t *testing.T) {
func TestPool_ReconcileKeepsSetOnEmptyResolve(t *testing.T) { func TestPool_ReconcileKeepsSetOnEmptyResolve(t *testing.T) {
p, res, _ := newTestPool(t, []string{"a", "b"}, 3) p, res, _ := newTestPool(t, []string{"a", "b"}, 3)
res.set([]string{}, nil) res.set([]string{}, nil)
p.Reconcile(context.Background()) _ = p.Reconcile(context.Background())
if len(p.snapshot()) != 2 { if len(p.snapshot()) != 2 {
t.Errorf("empty resolve should not drain pool; got %d backends", len(p.snapshot())) t.Errorf("empty resolve should not drain pool; got %d backends", len(p.snapshot()))
} }
@@ -396,7 +396,7 @@ func TestPool_ConcurrentRequestsDuringReconcile(t *testing.T) {
return return
default: default:
} }
p.HeadObject(context.Background(), "bucket", "k") _, _ = p.HeadObject(context.Background(), "bucket", "k")
if obj, err := p.GetObject(context.Background(), "bucket", "k", ""); err == nil { if obj, err := p.GetObject(context.Background(), "bucket", "k", ""); err == nil {
_, _ = io.ReadAll(obj.Body) _, _ = io.ReadAll(obj.Body)
obj.Body.Close() obj.Body.Close()
@@ -415,7 +415,7 @@ func TestPool_ConcurrentRequestsDuringReconcile(t *testing.T) {
default: default:
} }
res.set(sets[i%len(sets)], nil) res.set(sets[i%len(sets)], nil)
p.Reconcile(context.Background()) _ = p.Reconcile(context.Background())
} }
}) })
@@ -429,7 +429,7 @@ func TestPool_StatsReflectActivity(t *testing.T) {
p, _, _ := newTestPool(t, []string{"a", "b"}, 3) p, _, _ := newTestPool(t, []string{"a", "b"}, 3)
// Drive some successful ops. // Drive some successful ops.
for range 4 { for range 4 {
p.HeadObject(context.Background(), "bucket", "k") _, _ = p.HeadObject(context.Background(), "bucket", "k")
} }
var totalReq int64 var totalReq int64
stats := p.Stats() stats := p.Stats()
+16 -20
View File
@@ -108,8 +108,8 @@ func NewS3StorageForCluster(cc config.ClusterConfig, opts S3Options) *S3Storage
), ),
BaseEndpoint: aws.String(opts.Endpoint), BaseEndpoint: aws.String(opts.Endpoint),
UsePathStyle: cc.S3ForcePathStyle, UsePathStyle: cc.S3ForcePathStyle,
}
s3opts.HTTPClient = buildHTTPClient(opts) HTTPClient: buildHTTPClient(opts)}
return &S3Storage{client: s3.New(s3opts)} return &S3Storage{client: s3.New(s3opts)}
} }
@@ -179,13 +179,11 @@ func (s *S3Storage) CheckBucket(ctx context.Context, bucket string) (bool, error
Bucket: aws.String(bucket), Bucket: aws.String(bucket),
}) })
if err != nil { if err != nil {
var notFound *types.NotFound if _, ok := errors.AsType[*types.NotFound](err); ok {
if errors.As(err, &notFound) {
return false, nil return false, nil
} }
// Also check for 404 in the operation error // Also check for 404 in the operation error
var noSuchBucket *types.NoSuchBucket if _, ok := errors.AsType[*types.NoSuchBucket](err); ok {
if errors.As(err, &noSuchBucket) {
return false, nil return false, nil
} }
return false, fmt.Errorf("check bucket: %w", err) return false, fmt.Errorf("check bucket: %w", err)
@@ -250,7 +248,7 @@ func (s *S3Storage) GetObject(ctx context.Context, bucket, key, rangeHeader stri
} }
func (s *S3Storage) PutObject(ctx context.Context, bucket, key string, body io.Reader, contentLength int64, writeOnce bool, sha256Hex string) error { func (s *S3Storage) PutObject(ctx context.Context, bucket, key string, body io.Reader, contentLength int64, writeOnce bool, sha256Hex string) error {
var uploadBody io.Reader = body uploadBody := body
var hasher *sha256Writer var hasher *sha256Writer
if sha256Hex != "" { if sha256Hex != "" {
@@ -354,18 +352,16 @@ func (s *S3Storage) DeleteObject(ctx context.Context, bucket, key string) error
// IsNotFound reports whether err is an S3 404 — the object (or bucket) does // IsNotFound reports whether err is an S3 404 — the object (or bucket) does
// not exist, as opposed to a storage failure. // not exist, as opposed to a storage failure.
func IsNotFound(err error) bool { func IsNotFound(err error) bool {
var notFound *types.NotFound if _, ok := errors.AsType[*types.NotFound](err); ok {
if errors.As(err, &notFound) {
return true return true
} }
var noSuchKey *types.NoSuchKey if _, ok := errors.AsType[*types.NoSuchKey](err); ok {
if errors.As(err, &noSuchKey) {
return true return true
} }
var apiErr interface { if apiErr, ok := errors.AsType[interface {
error
HTTPStatusCode() int HTTPStatusCode() int
} }](err); ok {
if errors.As(err, &apiErr) {
return apiErr.HTTPStatusCode() == 404 return apiErr.HTTPStatusCode() == 404
} }
return false return false
@@ -374,10 +370,10 @@ func IsNotFound(err error) bool {
// isPreconditionFailed checks if an S3 error is a 412 Precondition Failed. // isPreconditionFailed checks if an S3 error is a 412 Precondition Failed.
func isPreconditionFailed(err error) bool { func isPreconditionFailed(err error) bool {
// aws-sdk-go-v2 wraps HTTP status in the operation error // aws-sdk-go-v2 wraps HTTP status in the operation error
var apiErr interface { if apiErr, ok := errors.AsType[interface {
error
HTTPStatusCode() int HTTPStatusCode() int
} }](err); ok {
if errors.As(err, &apiErr) {
return apiErr.HTTPStatusCode() == 412 return apiErr.HTTPStatusCode() == 412
} }
return false return false
@@ -399,10 +395,10 @@ func isBackendFailure(err error) bool {
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
return false return false
} }
var apiErr interface { if apiErr, ok := errors.AsType[interface {
error
HTTPStatusCode() int HTTPStatusCode() int
} }](err); ok {
if errors.As(err, &apiErr) {
code := apiErr.HTTPStatusCode() code := apiErr.HTTPStatusCode()
// A transport failure (dial refused, timeout, reset) is surfaced by the // A transport failure (dial refused, timeout, reset) is surfaced by the
// SDK as a ResponseError with StatusCode 0 — no response ever reached // SDK as a ResponseError with StatusCode 0 — no response ever reached
+3 -3
View File
@@ -190,10 +190,10 @@ func TestListObjects_EmptyListing(t *testing.T) {
// which restic retries at the pack level (its own body IS seekable). RED before // which restic retries at the pack level (its own body IS seekable). RED before
// the s3.go RetryMaxAttempts=1 fix, GREEN after. // the s3.go RetryMaxAttempts=1 fix, GREEN after.
func TestPutObject_NonSeekableBodyOn503_NoRewindRetry(t *testing.T) { func TestPutObject_NonSeekableBodyOn503_NoRewindRetry(t *testing.T) {
var puts int32 var puts atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPut { if r.Method == http.MethodPut {
atomic.AddInt32(&puts, 1) puts.Add(1)
_, _ = io.Copy(io.Discard, r.Body) // let the client finish sending _, _ = io.Copy(io.Discard, r.Body) // let the client finish sending
w.WriteHeader(http.StatusServiceUnavailable) w.WriteHeader(http.StatusServiceUnavailable)
return return
@@ -215,7 +215,7 @@ func TestPutObject_NonSeekableBodyOn503_NoRewindRetry(t *testing.T) {
t.Fatalf("PutObject attempted a rewind-for-retry on a non-seekable body: %v", err) t.Fatalf("PutObject attempted a rewind-for-retry on a non-seekable body: %v", err)
} }
// And with retries off, the gateway must see exactly one upload attempt. // And with retries off, the gateway must see exactly one upload attempt.
if n := atomic.LoadInt32(&puts); n != 1 { if n := puts.Load(); n != 1 {
t.Fatalf("expected exactly 1 upload attempt (no retry on a non-seekable body), got %d", n) t.Fatalf("expected exactly 1 upload attempt (no retry on a non-seekable body), got %d", n)
} }
} }
+1 -1
View File
@@ -268,7 +268,7 @@ func (o *options) buildConfig(defaultPhases []string) (resticbench.Config, error
} }
if o.connections != "" { if o.connections != "" {
for _, s := range strings.Split(o.connections, ",") { for s := range strings.SplitSeq(o.connections, ",") {
n, err := strconv.Atoi(strings.TrimSpace(s)) n, err := strconv.Atoi(strings.TrimSpace(s))
if err != nil || n < 1 { if err != nil || n < 1 {
return cfg, fmt.Errorf("invalid --connections value %q", s) return cfg, fmt.Errorf("invalid --connections value %q", s)
+7 -7
View File
@@ -32,10 +32,10 @@ func (v *view) render(r *fbfleet.StatusReport, sampledAt time.Time, sampleSec in
if r.Run != nil { if r.Run != nil {
since := time.Since(r.Run.StartedAt).Round(time.Second).String() + " ago" since := time.Since(r.Run.StartedAt).Round(time.Second).String() + " ago"
p := r.Run.Params p := r.Run.Params
b.WriteString(fmt.Sprintf("%s %s · %s objects · %s/cycle · %s clients/host · %s\n", fmt.Fprintf(&b, "%s %s · %s objects · %s/cycle · %s clients/host · %s\n",
ui.OK.Render("● "+r.Run.Label), ui.OK.Render("● "+r.Run.Label),
ui.Muted.Render("started "+since), ui.Muted.Render("started "+since),
p["obj_size_mib"]+"MiB", p["cycle_size"], p["clients_per_host"], p["duration"])) p["obj_size_mib"]+"MiB", p["cycle_size"], p["clients_per_host"], p["duration"])
b.WriteString(ui.Muted.Render("cap "+p["cap_per_host"]+" per host") + "\n") b.WriteString(ui.Muted.Render("cap "+p["cap_per_host"]+" per host") + "\n")
} else { } else {
b.WriteString(ui.Warn.Render("○ no active run recorded") + b.WriteString(ui.Warn.Render("○ no active run recorded") +
@@ -89,10 +89,10 @@ func (v *view) render(r *fbfleet.StatusReport, sampledAt time.Time, sampleSec in
wire += used wire += used
capTotal += capBytes capTotal += capBytes
} }
b.WriteString(fmt.Sprintf("%s %s %s · %s\n", fmt.Fprintf(&b, "%s %s %s · %s\n",
ui.Muted.Render(fmt.Sprintf("%-*s", nameW+6, "aggregate")), ui.Muted.Render(fmt.Sprintf("%-*s", nameW+6, "aggregate")),
ui.TX.Render("TX"), ui.PadGbps(txBps), ui.TX.Render("TX"), ui.PadGbps(txBps),
ui.Total.Render(fmt.Sprintf("pool %s / %s", resticbench.FormatBytes(wire), resticbench.FormatBytes(capTotal))))) ui.Total.Render(fmt.Sprintf("pool %s / %s", resticbench.FormatBytes(wire), resticbench.FormatBytes(capTotal))))
if len(v.history.Values()) > 1 { if len(v.history.Values()) > 1 {
b.WriteString(ui.Muted.Render("history ") + ui.Total.Render(ui.Sparkline(v.history.Values(), 40)) + "\n") b.WriteString(ui.Muted.Render("history ") + ui.Total.Render(ui.Sparkline(v.history.Values(), 40)) + "\n")
} }
@@ -112,7 +112,7 @@ func (v *view) render(r *fbfleet.StatusReport, sampledAt time.Time, sampleSec in
for _, d := range r.Hosts { for _, d := range r.Hosts {
if d.Status == nil { if d.Status == nil {
if d.Err != "" { if d.Err != "" {
b.WriteString(fmt.Sprintf("%-*s %s\n", cnameW, fbfleet.ShortName(d.Name), ui.Bad.Render(d.Err))) fmt.Fprintf(&b, "%-*s %s\n", cnameW, fbfleet.ShortName(d.Name), ui.Bad.Render(d.Err))
} }
continue continue
} }
@@ -121,9 +121,9 @@ func (v *view) render(r *fbfleet.StatusReport, sampledAt time.Time, sampleSec in
if c.LastError != "" { if c.LastError != "" {
lastErr = ui.Bad.Render(ui.Truncate(c.LastError, 48)) lastErr = ui.Bad.Render(ui.Truncate(c.LastError, 48))
} }
b.WriteString(fmt.Sprintf("%-*s %-9s %6d %10s %s %s\n", fmt.Fprintf(&b, "%-*s %-9s %6d %10s %s %s\n",
cnameW, fbfleet.ShortName(c.Name), phaseCell(c.Phase), c.Cycles, cnameW, fbfleet.ShortName(c.Name), phaseCell(c.Phase), c.Cycles,
resticbench.FormatBytes(c.Uploaded+c.CurrentBytes), ui.ErrCell(c.Errors, 6), lastErr)) resticbench.FormatBytes(c.Uploaded+c.CurrentBytes), ui.ErrCell(c.Errors, 6), lastErr)
} }
} }
+8 -8
View File
@@ -33,12 +33,12 @@ func (v *view) render(r *warpfleet.StatusReport, sampledAt time.Time, sampleSec
if t, err := time.Parse(time.RFC3339, since); err == nil { if t, err := time.Parse(time.RFC3339, since); err == nil {
since = time.Since(t).Round(time.Second).String() + " ago" since = time.Since(t).Round(time.Second).String() + " ago"
} }
b.WriteString(fmt.Sprintf("%s %s · %s PUT / %s GET · %s/%s objects · %s RGWs\n", fmt.Fprintf(&b, "%s %s · %s PUT / %s GET · %s/%s objects · %s RGWs\n",
ui.OK.Render("● "+r.Config["mode"]), ui.OK.Render("● "+r.Config["mode"]),
ui.Muted.Render("started "+since), ui.Muted.Render("started "+since),
r.Config["put_streams"], r.Config["get_streams"], r.Config["put_streams"], r.Config["get_streams"],
r.Config["put_obj_size"], r.Config["get_obj_size"], r.Config["put_obj_size"], r.Config["get_obj_size"],
r.Config["rgw_endpoints"])) r.Config["rgw_endpoints"])
b.WriteString(ui.Muted.Render("endpoint "+r.Config["endpoint"]) + "\n") b.WriteString(ui.Muted.Render("endpoint "+r.Config["endpoint"]) + "\n")
} else { } else {
b.WriteString(ui.Warn.Render("○ no active run recorded") + b.WriteString(ui.Warn.Render("○ no active run recorded") +
@@ -58,22 +58,22 @@ func (v *view) render(r *warpfleet.StatusReport, sampledAt time.Time, sampleSec
} }
var tx, rx float64 var tx, rx float64
for _, n := range r.Nodes { for _, n := range r.Nodes {
b.WriteString(fmt.Sprintf("%-*s %s %s %s %s %s\n", fmt.Fprintf(&b, "%-*s %s %s %s %s %s\n",
nodeW, n.Node, nodeW, n.Node,
ui.Muted.Render(fmt.Sprintf("%-*s", ifaceW, n.Iface)), ui.Muted.Render(fmt.Sprintf("%-*s", ifaceW, n.Iface)),
ui.TX.Render(ui.Meter(n.TxBps, maxBps, 14)), ui.TX.Render(ui.Meter(n.TxBps, maxBps, 14)),
ui.PadGbps(n.TxBps), ui.PadGbps(n.TxBps),
ui.RX.Render(ui.Meter(n.RxBps, maxBps, 14)), ui.RX.Render(ui.Meter(n.RxBps, maxBps, 14)),
ui.PadGbps(n.RxBps))) ui.PadGbps(n.RxBps))
tx += n.TxBps tx += n.TxBps
rx += n.RxBps rx += n.RxBps
} }
if len(r.Nodes) > 0 { if len(r.Nodes) > 0 {
b.WriteString(fmt.Sprintf("%s %s %s · %s %s · %s\n", fmt.Fprintf(&b, "%s %s %s · %s %s · %s\n",
ui.Muted.Render(fmt.Sprintf("%-*s", nodeW+ifaceW-2, "aggregate")), ui.Muted.Render(fmt.Sprintf("%-*s", nodeW+ifaceW-2, "aggregate")),
ui.TX.Render("TX"), ui.PadGbps(tx), ui.TX.Render("TX"), ui.PadGbps(tx),
ui.RX.Render("RX"), ui.PadGbps(rx), ui.RX.Render("RX"), ui.PadGbps(rx),
ui.Total.Render("combined "+ui.FmtGbps(tx+rx)))) ui.Total.Render("combined "+ui.FmtGbps(tx+rx)))
if len(v.history.Values()) > 1 { if len(v.history.Values()) > 1 {
b.WriteString(ui.Muted.Render("history ") + ui.Total.Render(ui.Sparkline(v.history.Values(), 40)) + "\n") b.WriteString(ui.Muted.Render("history ") + ui.Total.Render(ui.Sparkline(v.history.Values(), 40)) + "\n")
} }
@@ -87,11 +87,11 @@ func (v *view) render(r *warpfleet.StatusReport, sampledAt time.Time, sampleSec
} }
b.WriteString(ui.Muted.Render(fmt.Sprintf("%-*s %-*s %6s %6s %10s %10s", podW, "POD", nodeW, "NODE", "PUT", "GET", "ERR(PUT)", "ERR(GET)")) + "\n") b.WriteString(ui.Muted.Render(fmt.Sprintf("%-*s %-*s %6s %6s %10s %10s", podW, "POD", nodeW, "NODE", "PUT", "GET", "ERR(PUT)", "ERR(GET)")) + "\n")
for _, p := range r.Pods { for _, p := range r.Pods {
b.WriteString(fmt.Sprintf("%-*s %-*s %s %s %s %s\n", fmt.Fprintf(&b, "%-*s %-*s %s %s %s %s\n",
podW, p.Name, nodeW, p.Node, podW, p.Name, nodeW, p.Node,
procCell(p.PutProcs, r.Config != nil), procCell(p.PutProcs, r.Config != nil),
procCell(p.GetProcs, r.Config != nil), procCell(p.GetProcs, r.Config != nil),
ui.ErrCell(p.PutErrors, 10), ui.ErrCell(p.GetErrors, 10))) ui.ErrCell(p.PutErrors, 10), ui.ErrCell(p.GetErrors, 10))
} }
b.WriteString("\n" + ui.Muted.Render(fleet.Footer(sampleSec, sampledAt, watching))) b.WriteString("\n" + ui.Muted.Render(fleet.Footer(sampleSec, sampledAt, watching)))
@@ -125,7 +125,7 @@ func newInviteCmd(f *cmdutil.Factory) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
var emails []string var emails []string
for _, arg := range args { for _, arg := range args {
for _, email := range strings.Split(arg, ",") { for email := range strings.SplitSeq(arg, ",") {
if email = strings.TrimSpace(email); email != "" { if email = strings.TrimSpace(email); email != "" {
emails = append(emails, email) emails = append(emails, email)
} }
+1 -1
View File
@@ -84,7 +84,7 @@ func Save(c *Context) error {
return fmt.Errorf("write context: %w", err) return fmt.Errorf("write context: %w", err)
} }
if err := os.Rename(tmp, p); err != nil { if err := os.Rename(tmp, p); err != nil {
os.Remove(tmp) _ = os.Remove(tmp)
return fmt.Errorf("commit context: %w", err) return fmt.Errorf("commit context: %w", err)
} }
return nil return nil
+1 -1
View File
@@ -97,7 +97,7 @@ func SaveCachedTopology(topo *Topology, logger zerolog.Logger) {
return return
} }
if err := os.Rename(tmp, p); err != nil { if err := os.Rename(tmp, p); err != nil {
os.Remove(tmp) _ = os.Remove(tmp)
logger.Warn().Err(err).Msg("skip discovery cache write") logger.Warn().Err(err).Msg("skip discovery cache write")
} }
} }
+3 -7
View File
@@ -142,9 +142,7 @@ func (c *Client) Resolve(ctx context.Context) (*Topology, error) {
var wg sync.WaitGroup var wg sync.WaitGroup
sem := make(chan struct{}, resolveConcurrency) sem := make(chan struct{}, resolveConcurrency)
for i, st := range stacks { for i, st := range stacks {
wg.Add(1) wg.Go(func() {
go func() {
defer wg.Done()
sem <- struct{}{} sem <- struct{}{}
defer func() { <-sem }() defer func() { <-sem }()
raw, err := c.getObject(ctx, st.Key) raw, err := c.getObject(ctx, st.Key)
@@ -164,7 +162,7 @@ func (c *Client) Resolve(ctx context.Context) (*Topology, error) {
return return
} }
resolved[i] = &ResolvedStack{Stack: st, Discovery: *d} resolved[i] = &ResolvedStack{Stack: st, Discovery: *d}
}() })
} }
wg.Wait() wg.Wait()
@@ -380,9 +378,7 @@ func (t *Topology) CephClusters(partition, region string) map[string]state.CephC
out := map[string]state.CephCluster{} out := map[string]state.CephCluster{}
for _, s := range t.Stacks { for _, s := range t.Stacks {
if s.Partition == partition && s.Region == region { if s.Partition == partition && s.Region == region {
for name, cc := range s.Discovery.CephClusters { maps.Copy(out, s.Discovery.CephClusters)
out[name] = cc
}
} }
} }
return out return out
+1 -1
View File
@@ -297,7 +297,7 @@ type Result struct {
Label string `json:"label"` Label string `json:"label"`
Partition string `json:"partition"` Partition string `json:"partition"`
Created time.Time `json:"created"` Created time.Time `json:"created"`
StartedAt time.Time `json:"startedAt,omitempty"` StartedAt time.Time `json:"startedAt"`
ElapsedSeconds float64 `json:"elapsedSeconds,omitempty"` ElapsedSeconds float64 `json:"elapsedSeconds,omitempty"`
Params map[string]string `json:"params,omitempty"` Params map[string]string `json:"params,omitempty"`
Hosts []HostResult `json:"droplets"` Hosts []HostResult `json:"droplets"`
+4 -4
View File
@@ -182,11 +182,11 @@ func (s *Session) SaveState() error {
// way to ever reopen those repos (e.g. `tools bench --repo-id` with a // way to ever reopen those repos (e.g. `tools bench --repo-id` with a
// re-minted URL to prune them later). // re-minted URL to prune them later).
func (s *Session) clearFleetState() error { func (s *Session) clearFleetState() error {
os.Remove(s.PrivateKeyPath()) _ = os.Remove(s.PrivateKeyPath())
os.Remove(s.knownHostsPath()) _ = os.Remove(s.knownHostsPath())
os.RemoveAll(filepath.Join(s.dir, "cm")) _ = os.RemoveAll(filepath.Join(s.dir, "cm"))
if len(s.State.Clients) == 0 { if len(s.State.Clients) == 0 {
os.Remove(s.statePath()) _ = os.Remove(s.statePath())
return nil return nil
} }
s.State.KeyID = "" s.State.KeyID = ""
+2 -2
View File
@@ -192,8 +192,8 @@ func share(total, n, i int) int {
func (s *Session) saveRunConfig(ctx context.Context, kv map[string]string) error { func (s *Session) saveRunConfig(ctx context.Context, kv map[string]string) error {
cm := &corev1.ConfigMap{ cm := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Name: runConfigMap, Namespace: s.Namespace}, Name: runConfigMap, Namespace: s.Namespace,
Data: kv, Data: kv,
} }
_, err := s.client.CoreV1().ConfigMaps(s.Namespace).Update(ctx, cm, metav1.UpdateOptions{}) _, err := s.client.CoreV1().ConfigMaps(s.Namespace).Update(ctx, cm, metav1.UpdateOptions{})
if isNotFound(err) { if isNotFound(err) {
+1 -1
View File
@@ -232,7 +232,7 @@ func (s *Session) ProbeIPs(ctx context.Context, pod string, t *S3Target) []strin
return t.IPs return t.IPs
} }
var healthy []string var healthy []string
for _, line := range strings.Fields(out) { for line := range strings.FieldsSeq(out) {
if net.ParseIP(line) != nil { if net.ParseIP(line) != nil {
healthy = append(healthy, line) healthy = append(healthy, line)
} }
+1 -1
View File
@@ -1,6 +1,6 @@
module yuctl module yuctl
go 1.25.0 go 1.27.0
require ( require (
github.com/aws/aws-sdk-go-v2 v1.43.3 github.com/aws/aws-sdk-go-v2 v1.43.3
-36
View File
@@ -2,52 +2,28 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
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/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY=
github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
github.com/aws/aws-sdk-go-v2 v1.43.3 h1:XJIcfv8uDs2ukdQsoAC8/Ebu1ejxwzlayl2ZsiFns2A= github.com/aws/aws-sdk-go-v2 v1.43.3 h1:XJIcfv8uDs2ukdQsoAC8/Ebu1ejxwzlayl2ZsiFns2A=
github.com/aws/aws-sdk-go-v2 v1.43.3/go.mod h1:70vwSy16txshwG+g55WkpgPKDIByzHI8ccBsOteo3bQ= github.com/aws/aws-sdk-go-v2 v1.43.3/go.mod h1:70vwSy16txshwG+g55WkpgPKDIByzHI8ccBsOteo3bQ=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 h1:eBMB84YGghSocM7PsjmmPffTa+1FBUeNvGvFou6V/4o=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16 h1:aiuaKlDweRC5qExJondpWjOgyzMHpofpwspGXUtwn4c= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16 h1:aiuaKlDweRC5qExJondpWjOgyzMHpofpwspGXUtwn4c=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16/go.mod h1:nG/LOlmox9BDe9HvQnXWzgcK8uKbgBMZ/Hp5pVt/21I= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.16/go.mod h1:nG/LOlmox9BDe9HvQnXWzgcK8uKbgBMZ/Hp5pVt/21I=
github.com/aws/aws-sdk-go-v2/credentials v1.19.10 h1:EEhmEUFCE1Yhl7vDhNOI5OCL/iKMdkkYFTRpZXNw7m8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.10/go.mod h1:RnnlFCAlxQCkN2Q379B67USkBMu1PipEEiibzYN5UTE=
github.com/aws/aws-sdk-go-v2/credentials v1.19.33 h1:/e5V3EWfeDiW6cuRxHsC8gbwko4/vvVYPJR2afBKFFY= github.com/aws/aws-sdk-go-v2/credentials v1.19.33 h1:/e5V3EWfeDiW6cuRxHsC8gbwko4/vvVYPJR2afBKFFY=
github.com/aws/aws-sdk-go-v2/credentials v1.19.33/go.mod h1:ZxAmkcyOM9beY/WO9oxp2oVPXiP3rq5N1/p4NbenJdE= github.com/aws/aws-sdk-go-v2/credentials v1.19.33/go.mod h1:ZxAmkcyOM9beY/WO9oxp2oVPXiP3rq5N1/p4NbenJdE=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34 h1:vuIfjzoeqhQMGJyOBU3t0ZEjn2jrN8Bbg1N4CgjzM5Q= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34 h1:vuIfjzoeqhQMGJyOBU3t0ZEjn2jrN8Bbg1N4CgjzM5Q=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34/go.mod h1:hP28cN4CPJLZHirdQPrZR50JcLN4ApRJP2tzG8cRlhY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.34/go.mod h1:hP28cN4CPJLZHirdQPrZR50JcLN4ApRJP2tzG8cRlhY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34 h1:9faHsnqxJ1vDvB4wMZy/ajIDyz5QhllQjjc72RJpXAw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34 h1:9faHsnqxJ1vDvB4wMZy/ajIDyz5QhllQjjc72RJpXAw=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34/go.mod h1:Yp6nIyejpa23nzlB/LhT63KTla9Jdi06nv/HH/OkAH8= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.34/go.mod h1:Yp6nIyejpa23nzlB/LhT63KTla9Jdi06nv/HH/OkAH8=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22 h1:rWyie/PxDRIdhNf4DzRk0lvjVOqFJuNnO8WwaIRVxzQ=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22/go.mod h1:zd/JsJ4P7oGfUhXn1VyLqaRZwPmZwg44Jf2dS84Dm3Y=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35 h1:Oe8gMKJLO5awqpa5EhAGKVnBv1s+brdWVuxM2mDa7zA= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35 h1:Oe8gMKJLO5awqpa5EhAGKVnBv1s+brdWVuxM2mDa7zA=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35/go.mod h1:FZevcG9cOST/FWAAUhHIchjR9fXFXFRCWodOhx+PDLA= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.35/go.mod h1:FZevcG9cOST/FWAAUhHIchjR9fXFXFRCWodOhx+PDLA=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 h1:JJLBQxwY+AFwuPAi5ivGc1ChnTdUt4cXMv7e76m2c/Y= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 h1:JJLBQxwY+AFwuPAi5ivGc1ChnTdUt4cXMv7e76m2c/Y=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15/go.mod h1:lQknBIe78MVL0cQOQDlag8KGflMbMEVFx9mB6O8ENvk= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15/go.mod h1:lQknBIe78MVL0cQOQDlag8KGflMbMEVFx9mB6O8ENvk=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13 h1:JRaIgADQS/U6uXDqlPiefP32yXTda7Kqfx+LgspooZM=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13/go.mod h1:CEuVn5WqOMilYl+tbccq8+N2ieCy0gVn3OtRb0vBNNM=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27 h1:zwB6ltUc0UiyOsRQaMQ8jNLjKECbjhadCyl4hqV0y/c= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27 h1:zwB6ltUc0UiyOsRQaMQ8jNLjKECbjhadCyl4hqV0y/c=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27/go.mod h1:ce9y+Y+hGLUyPKJZZJGoFLuFJNfCNuWZTujUJAsckQA= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.27/go.mod h1:ce9y+Y+hGLUyPKJZZJGoFLuFJNfCNuWZTujUJAsckQA=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 h1:c31//R3xgIJMSC8S6hEVq+38DcvUlgFY0FM6mSI5oto=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34 h1:sYg4qHWLqsjp15PzX7XCOHSOgKEGoZ5vQY43VvZ1pas= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34 h1:sYg4qHWLqsjp15PzX7XCOHSOgKEGoZ5vQY43VvZ1pas=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34/go.mod h1:N58SSz3roKf1HzW5qRaOiyk6MbDLTKgLPvlTfJ90iyI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.34/go.mod h1:N58SSz3roKf1HzW5qRaOiyk6MbDLTKgLPvlTfJ90iyI=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21 h1:ZlvrNcHSFFWURB8avufQq9gFsheUgjVD9536obIknfM=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21/go.mod h1:cv3TNhVrssKR0O/xxLJVRfd2oazSnZnkUeTf6ctUwfQ=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35 h1:ohfdSAm4TA6nryIY7mLqe4mnSIAnAreoAPBM81ZVoIM= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35 h1:ohfdSAm4TA6nryIY7mLqe4mnSIAnAreoAPBM81ZVoIM=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35/go.mod h1:uUjphnxMb3HH3vIiOHl4dH0fGNKL+csjqRQEabbfw5k= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.35/go.mod h1:uUjphnxMb3HH3vIiOHl4dH0fGNKL+csjqRQEabbfw5k=
github.com/aws/aws-sdk-go-v2/service/s3 v1.97.3 h1:HwxWTbTrIHm5qY+CAEur0s/figc3qwvLWsNkF4RPToo=
github.com/aws/aws-sdk-go-v2/service/s3 v1.97.3/go.mod h1:uoA43SdFwacedBfSgfFSjjCvYe8aYBS7EnU5GZ/YKMM=
github.com/aws/aws-sdk-go-v2/service/s3 v1.106.3 h1:oSfubHEP3a0nTRAtm99IDaws0f15qwf+fOwS1Esh5jI= github.com/aws/aws-sdk-go-v2/service/s3 v1.106.3 h1:oSfubHEP3a0nTRAtm99IDaws0f15qwf+fOwS1Esh5jI=
github.com/aws/aws-sdk-go-v2/service/s3 v1.106.3/go.mod h1:lWk6L5Q3YkaC7so1bQUJkvF7hj2KUFzdZ4w15wc2GHY= github.com/aws/aws-sdk-go-v2/service/s3 v1.106.3/go.mod h1:lWk6L5Q3YkaC7so1bQUJkvF7hj2KUFzdZ4w15wc2GHY=
github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng=
github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/aws/smithy-go v1.27.6 h1:0zjT8jgK3jbrTT7JJ3EE6JsMhX8JTrZ+f1sEndYDXrA= github.com/aws/smithy-go v1.27.6 h1:0zjT8jgK3jbrTT7JJ3EE6JsMhX8JTrZ+f1sEndYDXrA=
github.com/aws/smithy-go v1.27.6/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/aws/smithy-go v1.27.6/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
@@ -62,7 +38,6 @@ github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0G
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
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/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/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=
@@ -88,7 +63,6 @@ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+Gr
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -126,12 +100,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
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/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.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
@@ -154,7 +124,6 @@ github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns
github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
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 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/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
@@ -162,9 +131,6 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI= github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI=
github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
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=
@@ -203,9 +169,7 @@ golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
+3 -3
View File
@@ -75,16 +75,16 @@ func ReadToTempFile(ctx context.Context, ref, pattern string) (string, error) {
// platform defaults differ. // platform defaults differ.
if err := f.Chmod(0o600); err != nil { if err := f.Chmod(0o600); err != nil {
f.Close() f.Close()
os.Remove(f.Name()) _ = os.Remove(f.Name())
return "", fmt.Errorf("chmod temp file: %w", err) return "", fmt.Errorf("chmod temp file: %w", err)
} }
if _, err := f.WriteString(val); err != nil { if _, err := f.WriteString(val); err != nil {
f.Close() f.Close()
os.Remove(f.Name()) _ = os.Remove(f.Name())
return "", fmt.Errorf("write temp file: %w", err) return "", fmt.Errorf("write temp file: %w", err)
} }
if err := f.Close(); err != nil { if err := f.Close(); err != nil {
os.Remove(f.Name()) _ = os.Remove(f.Name())
return "", fmt.Errorf("close temp file: %w", err) return "", fmt.Errorf("close temp file: %w", err)
} }
return f.Name(), nil return f.Name(), nil
+3 -6
View File
@@ -1,5 +1,7 @@
package resticbench package resticbench
import "slices"
// Phase names, in execution order within a cell. // Phase names, in execution order within a cell.
const ( const (
PhaseGenerate = "generate" PhaseGenerate = "generate"
@@ -41,10 +43,5 @@ type Config struct {
} }
func (c *Config) HasPhase(name string) bool { func (c *Config) HasPhase(name string) bool {
for _, p := range c.Phases { return slices.Contains(c.Phases, name)
if p == name {
return true
}
}
return false
} }
+5 -16
View File
@@ -62,10 +62,7 @@ func writeFile(path string, key [32]byte, size int64) error {
src := rand.NewChaCha8(key) src := rand.NewChaCha8(key)
buf := make([]byte, 1<<20) buf := make([]byte, 1<<20)
for size > 0 { for size > 0 {
n := int64(len(buf)) n := min(size, int64(len(buf)))
if size < n {
n = size
}
_, _ = src.Read(buf[:n]) _, _ = src.Read(buf[:n])
if _, err := w.Write(buf[:n]); err != nil { if _, err := w.Write(buf[:n]); err != nil {
f.Close() f.Close()
@@ -95,17 +92,12 @@ func Generate(dir string, size, fileSize int64, seed uint64, progress func(delta
Files: int((size + fileSize - 1) / fileSize), Files: int((size + fileSize - 1) / fileSize),
} }
workers := runtime.NumCPU() workers := min(runtime.NumCPU(), 16)
if workers > 16 {
workers = 16
}
indices := make(chan int) indices := make(chan int)
var wg sync.WaitGroup var wg sync.WaitGroup
var firstErr atomic.Value var firstErr atomic.Value
for range workers { for range workers {
wg.Add(1) wg.Go(func() {
go func() {
defer wg.Done()
for i := range indices { for i := range indices {
sz := m.fileSizeAt(i) sz := m.fileSizeAt(i)
if err := writeFile(filePath(dir, i), fileKey(seed, i, 0), sz); err != nil { if err := writeFile(filePath(dir, i), fileKey(seed, i, 0), sz); err != nil {
@@ -116,7 +108,7 @@ func Generate(dir string, size, fileSize int64, seed uint64, progress func(delta
progress(sz) progress(sz)
} }
} }
}() })
} }
for i := 0; i < m.Files; i++ { for i := 0; i < m.Files; i++ {
if firstErr.Load() != nil { if firstErr.Load() != nil {
@@ -139,10 +131,7 @@ func Generate(dir string, size, fileSize int64, seed uint64, progress func(delta
// change, so restic re-uploads them) and bumps the manifest round. // change, so restic re-uploads them) and bumps the manifest round.
func Mutate(dir string, m *Manifest, percent float64, progress func(delta int64)) (int64, error) { func Mutate(dir string, m *Manifest, percent float64, progress func(delta int64)) (int64, error) {
round := m.Rounds + 1 round := m.Rounds + 1
k := int(float64(m.Files) * percent / 100) k := max(int(float64(m.Files)*percent/100), 1)
if k < 1 {
k = 1
}
if k > m.Files { if k > m.Files {
k = m.Files k = m.Files
} }
+2 -2
View File
@@ -121,10 +121,10 @@ func AgentBinary(explicit string) (string, func(), error) {
} }
path := dir + "/bench-agent" path := dir + "/bench-agent"
if err := os.WriteFile(path, raw, 0o755); err != nil { if err := os.WriteFile(path, raw, 0o755); err != nil {
os.RemoveAll(dir) _ = os.RemoveAll(dir)
return "", nil, err return "", nil, err
} }
return path, func() { os.RemoveAll(dir) }, nil return path, func() { _ = os.RemoveAll(dir) }, nil
} }
// drive runs the remote agent, feeding Config over stdin and consuming the // drive runs the remote agent, feeding Config over stdin and consuming the
+1 -1
View File
@@ -44,7 +44,7 @@ func Upgrade(ctx context.Context, k state.Kubernetes, opts UpgradeOptions, logge
if err != nil { if err != nil {
return fmt.Errorf("materialize talosconfig: %w", err) return fmt.Errorf("materialize talosconfig: %w", err)
} }
defer os.Remove(cfgPath) defer func() { _ = os.Remove(cfgPath) }()
for _, node := range nodes { for _, node := range nodes {
args := []string{"--talosconfig", cfgPath, "--nodes", node} args := []string{"--talosconfig", cfgPath, "--nodes", node}