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]
node = "25.9.0"
pnpm = "10.28.1"
go = "1.26.5"
go = "1.27.0"
golangci-lint = "2.13.1"
restic = "0.19.1"
gh = "2.25.0"
@@ -66,7 +67,7 @@ run = [{ task = "install:frozen" }, { task = "build" }]
[tasks."check"]
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]
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}).
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
# 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).
@@ -17,7 +17,7 @@ COPY packages/michael/ ./
EXPOSE 3010
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
COPY packages/michael/go.mod packages/michael/go.sum ./
+1 -1
View File
@@ -1,6 +1,6 @@
module michael
go 1.25.0
go 1.27.0
require (
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/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/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/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/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/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/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/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/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/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/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/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/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
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/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/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
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/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
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/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
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/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/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/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/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/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/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/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
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/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/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/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/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/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/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo=
go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts=
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/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA=
go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk=
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/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/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.18.0/go.mod h1:7cHtiVJpZebB3wybTa4NG+FUo5NPe3PROz1FqB0+qdw=
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/log/logtest v0.19.0 h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk=
go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk=
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/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/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/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/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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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/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/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
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=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
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/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/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/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
+6 -6
View File
@@ -36,13 +36,13 @@ const (
func integrationConfig() config.Config {
return config.Config{
Port: 3010,
JWTPublicKey: testPublicKey,
S3AccessKeyID: envOrDefault("S3_ACCESS_KEY_ID", "minio"),
Port: 3010,
JWTPublicKey: testPublicKey,
S3AccessKeyID: envOrDefault("S3_ACCESS_KEY_ID", "minio"),
S3SecretAccessKey: envOrDefault("S3_SECRET_ACCESS_KEY", "miniominio"),
S3Region: envOrDefault("S3_REGION", "minio"),
S3Endpoint: envOrDefault("S3_ENDPOINT", "http://localhost:9000"),
S3ForcePathStyle: true,
S3Region: envOrDefault("S3_REGION", "minio"),
S3Endpoint: envOrDefault("S3_ENDPOINT", "http://localhost:9000"),
S3ForcePathStyle: true,
}
}
+5 -4
View File
@@ -10,6 +10,7 @@ import (
"net"
"net/http"
"net/netip"
"slices"
"strconv"
"strings"
@@ -140,10 +141,10 @@ func isPrivate(addr netip.Addr) bool {
func ClientAddr(r *http.Request, header string) netip.Addr {
if header != "" {
values := r.Header.Values(header)
for i := len(values) - 1; i >= 0; i-- {
entries := strings.Split(values[i], ",")
for j := len(entries) - 1; j >= 0; j-- {
if addr, ok := parseAddr(entries[j]); ok {
for _, value := range slices.Backward(values) {
entries := strings.Split(value, ",")
for _, entrie := range slices.Backward(entries) {
if addr, ok := parseAddr(entrie); ok {
return addr
}
}
@@ -174,7 +174,7 @@ func TestResolve(t *testing.T) {
if err != nil {
t.Fatalf("Open: %v", err)
}
defer db.Close()
defer func() { _ = db.Close() }()
r := httptest.NewRequest(http.MethodGet, "/repo/data/abc", nil)
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)
}
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 {
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.
func parseLogLines(t *testing.T, buf *bytes.Buffer) []map[string]interface{} {
func parseLogLines(t *testing.T, buf *bytes.Buffer) []map[string]any {
t.Helper()
var entries []map[string]interface{}
for _, line := range bytes.Split(bytes.TrimSpace(buf.Bytes()), []byte("\n")) {
var entries []map[string]any
for line := range bytes.SplitSeq(bytes.TrimSpace(buf.Bytes()), []byte("\n")) {
if len(line) == 0 {
continue
}
var entry map[string]interface{}
var entry map[string]any
if err := json.Unmarshal(line, &entry); err != nil {
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.
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 {
hit := true
for k, v := range match {
@@ -238,7 +238,7 @@ func TestAccessLogOutput(t *testing.T) {
}
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 {
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)
// 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 {
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
// 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 {
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)
// 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 {
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)
}
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 {
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
// Collect for as long as requests are arriving, so the two actually overlap.
collectors.Add(1)
go func() {
defer collectors.Done()
collectors.Go(func() {
obs := &recordingObserver{}
for {
select {
@@ -271,20 +269,18 @@ func TestClientTrackerEvictionKeepsRequestsAttached(t *testing.T) {
obs.got = obs.got[:0]
}
}
}()
})
for i := 0; i < 4; i++ {
requests.Add(1)
go func() {
defer requests.Done()
for n := 0; n < 20000; n++ {
for range 4 {
requests.Go(func() {
for range 20000 {
state := tr.enter(key)
if v, ok := tr.states.Load(key); !ok || v.(*clientConcurrency) != state {
orphaned.Add(1)
}
state.exit(time.Now())
}
}()
})
}
requests.Wait()
@@ -331,12 +327,10 @@ func TestClientTrackerConcurrentEnterExit(t *testing.T) {
key := clientAttrKey{"u1", "r1", "restic"}
var wg sync.WaitGroup
for i := 0; i < 200; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for range 200 {
wg.Go(func() {
tr.enter(key).exit(time.Now())
}()
})
}
wg.Wait()
@@ -397,12 +397,10 @@ func TestCachedRoutePattern(t *testing.T) {
func TestBlobMetricOptionConcurrency(t *testing.T) {
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for range 100 {
wg.Go(func() {
BlobMetricOption(auth.Auth{User: "u1", Repository: "r1"}, "data")
}()
})
}
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.
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 {
// Not JSON — pass through length but skip OTEL export.
return len(p), nil
+1 -1
View File
@@ -124,7 +124,7 @@ func (p *Pool) Run(ctx context.Context) {
case <-ctx.Done():
return
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() {
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 {
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).
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() {
t.Error("ejected before reaching threshold")
}
// Third consecutive failure: ejected.
p.HeadObject(context.Background(), "bucket", "k")
_, _ = p.HeadObject(context.Background(), "bucket", "k")
if b.healthy.Load() {
t.Error("expected ejection after threshold failures")
}
@@ -242,7 +242,7 @@ func TestPool_EjectAfterThresholdThenReinstate(t *testing.T) {
// Active probe reinstates once the backend recovers.
reg["a"].opFail.Store(false)
p.Reconcile(context.Background())
_ = p.Reconcile(context.Background())
if !b.healthy.Load() {
t.Error("expected reinstatement after healthy probe")
}
@@ -324,7 +324,7 @@ func TestPool_ReconcileAddsAndRemoves(t *testing.T) {
// Remove b, add c.
res.set([]string{"a", "c"}, nil)
p.Reconcile(context.Background())
_ = p.Reconcile(context.Background())
eps := map[string]bool{}
for _, b := range p.snapshot() {
@@ -346,7 +346,7 @@ func TestPool_ReconcileAddsAndRemoves(t *testing.T) {
func TestPool_ReconcileEjectsViaProbe(t *testing.T) {
p, _, reg := newTestPool(t, []string{"a", "b"}, 3)
reg["a"].probeFail.Store(true)
p.Reconcile(context.Background())
_ = p.Reconcile(context.Background())
if backendByEndpoint(p, "a").healthy.Load() {
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.
reg["a"].probeFail.Store(false)
p.Reconcile(context.Background())
_ = p.Reconcile(context.Background())
if !backendByEndpoint(p, "a").healthy.Load() {
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) {
p, res, _ := newTestPool(t, []string{"a", "b"}, 3)
res.set(nil, errors.New("dns down"))
p.Reconcile(context.Background())
_ = p.Reconcile(context.Background())
if len(p.snapshot()) != 2 {
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) {
p, res, _ := newTestPool(t, []string{"a", "b"}, 3)
res.set([]string{}, nil)
p.Reconcile(context.Background())
_ = p.Reconcile(context.Background())
if len(p.snapshot()) != 2 {
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
default:
}
p.HeadObject(context.Background(), "bucket", "k")
_, _ = p.HeadObject(context.Background(), "bucket", "k")
if obj, err := p.GetObject(context.Background(), "bucket", "k", ""); err == nil {
_, _ = io.ReadAll(obj.Body)
obj.Body.Close()
@@ -415,7 +415,7 @@ func TestPool_ConcurrentRequestsDuringReconcile(t *testing.T) {
default:
}
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)
// Drive some successful ops.
for range 4 {
p.HeadObject(context.Background(), "bucket", "k")
_, _ = p.HeadObject(context.Background(), "bucket", "k")
}
var totalReq int64
stats := p.Stats()
+16 -20
View File
@@ -108,8 +108,8 @@ func NewS3StorageForCluster(cc config.ClusterConfig, opts S3Options) *S3Storage
),
BaseEndpoint: aws.String(opts.Endpoint),
UsePathStyle: cc.S3ForcePathStyle,
}
s3opts.HTTPClient = buildHTTPClient(opts)
HTTPClient: buildHTTPClient(opts)}
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),
})
if err != nil {
var notFound *types.NotFound
if errors.As(err, &notFound) {
if _, ok := errors.AsType[*types.NotFound](err); ok {
return false, nil
}
// Also check for 404 in the operation error
var noSuchBucket *types.NoSuchBucket
if errors.As(err, &noSuchBucket) {
if _, ok := errors.AsType[*types.NoSuchBucket](err); ok {
return false, nil
}
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 {
var uploadBody io.Reader = body
uploadBody := body
var hasher *sha256Writer
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
// not exist, as opposed to a storage failure.
func IsNotFound(err error) bool {
var notFound *types.NotFound
if errors.As(err, &notFound) {
if _, ok := errors.AsType[*types.NotFound](err); ok {
return true
}
var noSuchKey *types.NoSuchKey
if errors.As(err, &noSuchKey) {
if _, ok := errors.AsType[*types.NoSuchKey](err); ok {
return true
}
var apiErr interface {
if apiErr, ok := errors.AsType[interface {
error
HTTPStatusCode() int
}
if errors.As(err, &apiErr) {
}](err); ok {
return apiErr.HTTPStatusCode() == 404
}
return false
@@ -374,10 +370,10 @@ func IsNotFound(err error) bool {
// isPreconditionFailed checks if an S3 error is a 412 Precondition Failed.
func isPreconditionFailed(err error) bool {
// aws-sdk-go-v2 wraps HTTP status in the operation error
var apiErr interface {
if apiErr, ok := errors.AsType[interface {
error
HTTPStatusCode() int
}
if errors.As(err, &apiErr) {
}](err); ok {
return apiErr.HTTPStatusCode() == 412
}
return false
@@ -399,10 +395,10 @@ func isBackendFailure(err error) bool {
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
return false
}
var apiErr interface {
if apiErr, ok := errors.AsType[interface {
error
HTTPStatusCode() int
}
if errors.As(err, &apiErr) {
}](err); ok {
code := apiErr.HTTPStatusCode()
// A transport failure (dial refused, timeout, reset) is surfaced by the
// 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
// the s3.go RetryMaxAttempts=1 fix, GREEN after.
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) {
if r.Method == http.MethodPut {
atomic.AddInt32(&puts, 1)
puts.Add(1)
_, _ = io.Copy(io.Discard, r.Body) // let the client finish sending
w.WriteHeader(http.StatusServiceUnavailable)
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)
}
// 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)
}
}
+1 -1
View File
@@ -268,7 +268,7 @@ func (o *options) buildConfig(defaultPhases []string) (resticbench.Config, error
}
if o.connections != "" {
for _, s := range strings.Split(o.connections, ",") {
for s := range strings.SplitSeq(o.connections, ",") {
n, err := strconv.Atoi(strings.TrimSpace(s))
if err != nil || n < 1 {
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 {
since := time.Since(r.Run.StartedAt).Round(time.Second).String() + " ago"
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.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")
} else {
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
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.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 {
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 {
if d.Status == nil {
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
}
@@ -121,9 +121,9 @@ func (v *view) render(r *fbfleet.StatusReport, sampledAt time.Time, sampleSec in
if c.LastError != "" {
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,
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 {
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.Muted.Render("started "+since),
r.Config["put_streams"], r.Config["get_streams"],
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")
} else {
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
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,
ui.Muted.Render(fmt.Sprintf("%-*s", ifaceW, n.Iface)),
ui.TX.Render(ui.Meter(n.TxBps, maxBps, 14)),
ui.PadGbps(n.TxBps),
ui.RX.Render(ui.Meter(n.RxBps, maxBps, 14)),
ui.PadGbps(n.RxBps)))
ui.PadGbps(n.RxBps))
tx += n.TxBps
rx += n.RxBps
}
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.TX.Render("TX"), ui.PadGbps(tx),
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 {
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")
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,
procCell(p.PutProcs, 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)))
@@ -125,7 +125,7 @@ func newInviteCmd(f *cmdutil.Factory) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
var emails []string
for _, arg := range args {
for _, email := range strings.Split(arg, ",") {
for email := range strings.SplitSeq(arg, ",") {
if email = strings.TrimSpace(email); 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)
}
if err := os.Rename(tmp, p); err != nil {
os.Remove(tmp)
_ = os.Remove(tmp)
return fmt.Errorf("commit context: %w", err)
}
return nil
+1 -1
View File
@@ -97,7 +97,7 @@ func SaveCachedTopology(topo *Topology, logger zerolog.Logger) {
return
}
if err := os.Rename(tmp, p); err != nil {
os.Remove(tmp)
_ = os.Remove(tmp)
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
sem := make(chan struct{}, resolveConcurrency)
for i, st := range stacks {
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
sem <- struct{}{}
defer func() { <-sem }()
raw, err := c.getObject(ctx, st.Key)
@@ -164,7 +162,7 @@ func (c *Client) Resolve(ctx context.Context) (*Topology, error) {
return
}
resolved[i] = &ResolvedStack{Stack: st, Discovery: *d}
}()
})
}
wg.Wait()
@@ -380,9 +378,7 @@ func (t *Topology) CephClusters(partition, region string) map[string]state.CephC
out := map[string]state.CephCluster{}
for _, s := range t.Stacks {
if s.Partition == partition && s.Region == region {
for name, cc := range s.Discovery.CephClusters {
out[name] = cc
}
maps.Copy(out, s.Discovery.CephClusters)
}
}
return out
+1 -1
View File
@@ -297,7 +297,7 @@ type Result struct {
Label string `json:"label"`
Partition string `json:"partition"`
Created time.Time `json:"created"`
StartedAt time.Time `json:"startedAt,omitempty"`
StartedAt time.Time `json:"startedAt"`
ElapsedSeconds float64 `json:"elapsedSeconds,omitempty"`
Params map[string]string `json:"params,omitempty"`
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
// re-minted URL to prune them later).
func (s *Session) clearFleetState() error {
os.Remove(s.PrivateKeyPath())
os.Remove(s.knownHostsPath())
os.RemoveAll(filepath.Join(s.dir, "cm"))
_ = os.Remove(s.PrivateKeyPath())
_ = os.Remove(s.knownHostsPath())
_ = os.RemoveAll(filepath.Join(s.dir, "cm"))
if len(s.State.Clients) == 0 {
os.Remove(s.statePath())
_ = os.Remove(s.statePath())
return nil
}
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 {
cm := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Name: runConfigMap, Namespace: s.Namespace},
Data: kv,
Name: runConfigMap, Namespace: s.Namespace,
Data: kv,
}
_, err := s.client.CoreV1().ConfigMaps(s.Namespace).Update(ctx, cm, metav1.UpdateOptions{})
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
}
var healthy []string
for _, line := range strings.Fields(out) {
for line := range strings.FieldsSeq(out) {
if net.ParseIP(line) != nil {
healthy = append(healthy, line)
}
+1 -1
View File
@@ -1,6 +1,6 @@
module yuctl
go 1.25.0
go 1.27.0
require (
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/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/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/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/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/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/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/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/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/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/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/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/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/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/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
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/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
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/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=
@@ -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-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/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/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
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/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
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/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/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
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/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
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/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
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/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
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.
if err := f.Chmod(0o600); err != nil {
f.Close()
os.Remove(f.Name())
_ = os.Remove(f.Name())
return "", fmt.Errorf("chmod temp file: %w", err)
}
if _, err := f.WriteString(val); err != nil {
f.Close()
os.Remove(f.Name())
_ = os.Remove(f.Name())
return "", fmt.Errorf("write temp file: %w", err)
}
if err := f.Close(); err != nil {
os.Remove(f.Name())
_ = os.Remove(f.Name())
return "", fmt.Errorf("close temp file: %w", err)
}
return f.Name(), nil
+3 -6
View File
@@ -1,5 +1,7 @@
package resticbench
import "slices"
// Phase names, in execution order within a cell.
const (
PhaseGenerate = "generate"
@@ -41,10 +43,5 @@ type Config struct {
}
func (c *Config) HasPhase(name string) bool {
for _, p := range c.Phases {
if p == name {
return true
}
}
return false
return slices.Contains(c.Phases, name)
}
+5 -16
View File
@@ -62,10 +62,7 @@ func writeFile(path string, key [32]byte, size int64) error {
src := rand.NewChaCha8(key)
buf := make([]byte, 1<<20)
for size > 0 {
n := int64(len(buf))
if size < n {
n = size
}
n := min(size, int64(len(buf)))
_, _ = src.Read(buf[:n])
if _, err := w.Write(buf[:n]); err != nil {
f.Close()
@@ -95,17 +92,12 @@ func Generate(dir string, size, fileSize int64, seed uint64, progress func(delta
Files: int((size + fileSize - 1) / fileSize),
}
workers := runtime.NumCPU()
if workers > 16 {
workers = 16
}
workers := min(runtime.NumCPU(), 16)
indices := make(chan int)
var wg sync.WaitGroup
var firstErr atomic.Value
for range workers {
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
for i := range indices {
sz := m.fileSizeAt(i)
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)
}
}
}()
})
}
for i := 0; i < m.Files; i++ {
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.
func Mutate(dir string, m *Manifest, percent float64, progress func(delta int64)) (int64, error) {
round := m.Rounds + 1
k := int(float64(m.Files) * percent / 100)
if k < 1 {
k = 1
}
k := max(int(float64(m.Files)*percent/100), 1)
if 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"
if err := os.WriteFile(path, raw, 0o755); err != nil {
os.RemoveAll(dir)
_ = os.RemoveAll(dir)
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
+1 -1
View File
@@ -44,7 +44,7 @@ func Upgrade(ctx context.Context, k state.Kubernetes, opts UpgradeOptions, logge
if err != nil {
return fmt.Errorf("materialize talosconfig: %w", err)
}
defer os.Remove(cfgPath)
defer func() { _ = os.Remove(cfgPath) }()
for _, node := range nodes {
args := []string{"--talosconfig", cfgPath, "--nodes", node}